--- /dev/null
+diff -Nur bes-3.12.0/functions.orig/swath2grid/AbstractDataset.cpp bes-3.12.0/functions/swath2grid/AbstractDataset.cpp
+--- bes-3.12.0/functions.orig/swath2grid/AbstractDataset.cpp 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/AbstractDataset.cpp 2014-03-03 15:47:38.046899595 +0100
+@@ -0,0 +1,1238 @@
++/******************************************************************************
++ * $Id: AbstractDataset.cpp 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: AbstractDataset implementation for providing an abstract data
++ * model for multiple data source.
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 "AbstractDataset.h"
++
++/************************************************************************/
++/* ==================================================================== */
++/* AbstractDataset */
++/* ==================================================================== */
++/************************************************************************/
++
++/**
++ * \class AbstractDataset "AbstractDataset.h"
++ *
++ * An abstract dataset encapsulating one or more raster bands, which is
++ * based on GDALDataset, and add the support to metadata model: ISO 19115
++ * and 1SO 19115 (2). A series of Fetch functions are provided for the
++ * implementation of Web Coverage Service.
++ *
++ * Use WCSTCreateDataset() to create a AbstractDataset for a named coverage
++ * identifier and band list.
++ */
++
++/************************************************************************/
++/* AbstractDataset() */
++/************************************************************************/
++AbstractDataset::AbstractDataset()
++{
++}
++
++/************************************************************************/
++/* AbstractDataset() */
++/************************************************************************/
++
++/**
++ * \brief Constructor of an AbstractDataset.
++ *
++ * This is the accepted method of opening an abstract dataset and allocating
++ * all resources associated with it.
++ */
++
++AbstractDataset::AbstractDataset(const string& id, vector<int> &rBandList) :
++ ms_CoverageID(id), mv_BandList(rBandList)
++{
++}
++
++/************************************************************************/
++/* ~AbstractDataset() */
++/************************************************************************/
++
++/**
++ * \brief Destroy an open AbstractDataset object.
++ *
++ * This is the accepted method of closing a AbstractDataset dataset and
++ * deallocating all resources associated with it.
++ */
++
++AbstractDataset::~AbstractDataset()
++{
++ if (maptr_DS.get())
++ GDALClose(maptr_DS.release());
++}
++
++/************************************************************************/
++/* InitialDataset() */
++/************************************************************************/
++
++/**
++ * \brief Initialize the data set.
++ *
++ * This is the virtual function for initializing abstract dataste. The
++ * subclasses of AbstarctDataset will call SetNativeCRS(), SetGeoTransform()
++ * and SetGDALDataset() to initialize an abstarct dataset.
++ *
++ * @param isSimple The WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::InitialDataset(const int isSimple)
++{
++ return CE_Failure;
++}
++
++/************************************************************************/
++/* GetGDALDataset() */
++/************************************************************************/
++
++/**
++ * \brief Get the GDALDataset object from AbstarctDataset.
++ *
++ * An AbstarctDataset encapsulating one GDALDataset. GetGDALDataset()
++ * returns a GDALDatset object, which is used to fetch its information
++ * through GDAL APIs.
++ *
++ * @return GDALDatset object.
++ */
++
++GDALDataset* AbstractDataset::GetGDALDataset()
++{
++ return maptr_DS.get();
++}
++
++/************************************************************************/
++/* SetGDALDataset() */
++/************************************************************************/
++
++/**
++ * \brief Set the GDALDataset object to AbstarctDataset.
++ *
++ * This is the virtual function for setting the abstract dataset by
++ * calling GDAL functions.
++ *
++ * @param isSimple the WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::SetGDALDataset(const int isSimple)
++{
++ return CE_Failure;
++}
++
++/************************************************************************/
++/* GetNativeCRS() */
++/************************************************************************/
++
++/**
++ * \brief Get the Native CRS of an AbstarctDataset.
++ *
++ * The method will return the CRS obejct, which is an OGRSpatialReference
++ * object.
++ *
++ * @return an OGRSpatialReference object corresponding the native CRS of
++ * coverage.
++ */
++
++const OGRSpatialReference& AbstractDataset::GetNativeCRS()
++{
++ return mo_NativeCRS;
++}
++
++/************************************************************************/
++/* SetNativeCRS() */
++/************************************************************************/
++
++/**
++ * \brief Set the Native CRS for an AbstarctDataset.
++ *
++ * The method will set the CRS for an AbstractDataset as an native CRS. For
++ * some served coverage, GDAL could not tell its native CRS, this method
++ * should be called to set its native CRS.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::SetNativeCRS()
++{
++ char* wktStr = (char*) maptr_DS->GetProjectionRef();
++
++ if (wktStr && OGRERR_NONE == mo_NativeCRS.importFromWkt(&wktStr))
++ return CE_None;
++
++ return CE_Failure;
++}
++
++/************************************************************************/
++/* SetGeoTransform() */
++/************************************************************************/
++
++/**
++ * \brief Set the affine GeoTransform matrix for a coverage.
++ *
++ * The method will set a GeoTransform matrix for a coverage. The method
++ * GetGeoTransform of GDAL library will be called to get the matrix.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::SetGeoTransform()
++{
++ if (CE_None != maptr_DS->GetGeoTransform(md_Geotransform))
++ return CE_Failure;
++
++ //Is the returned matrix correct? check the resolution values;
++ if(md_Geotransform[2] == 0 && md_Geotransform[5] == 0)
++ return CE_Failure;
++
++ mb_GeoTransformSet = TRUE;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetGeoTransform() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the affine transformation coefficients.
++ *
++ * Fetches the coefficients for transforming between pixel/line (P,L) raster
++ * space, and projection coordinates (Xp,Yp) space.
++ *
++ * \code
++ * Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
++ * Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
++ * \endcode
++ *
++ * In a north up image, padfTransform[1] is the pixel width, and
++ * padfTransform[5] is the pixel height. The upper left corner of the
++ * upper left pixel is at position (padfTransform[0],padfTransform[3]).
++ *
++ * The default transform is (0,1,0,0,0,1) and should be returned even when
++ * a CE_Failure error is returned, such as for formats that don't support
++ * transformation to projection coordinates.
++ *
++ * NOTE: GetGeoTransform() isn't expressive enough to handle the variety of
++ * OGC Grid Coverages pixel/line to projection transformation schemes.
++ * Eventually this method will be depreciated in favour of a more general
++ * scheme.
++ *
++ * @param geoTrans an existing six double buffer into which the
++ * transformation will be placed.
++ *
++ * @return TRUE on success or FALSE on failure.
++ */
++
++int AbstractDataset::GetGeoTransform(double geoTrans[])
++{
++ if (!mb_GeoTransformSet)//Geo-Transform not setup in each data driver, then set default.
++ {
++ geoTrans[0]=0.0;
++ geoTrans[0]=1.0;
++ geoTrans[0]=0.0;
++ geoTrans[0]=0.0;
++ geoTrans[0]=0.0;
++ geoTrans[0]=1.0;
++ return FALSE;
++ }
++
++ memcpy(geoTrans, md_Geotransform, sizeof(double) * 6);
++
++ return TRUE;
++}
++
++/************************************************************************/
++/* GetCoverageID() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the identifier of a coverage.
++ *
++ * The method will return the coverage identifier related to the abstarct
++ * dataset. As to TRMM data, the coverage identifier likes:
++ * TRMM:/Volumes/RAIDL1/GeoData/TRMM/TRMM_3B42_daily.2000.hdf:Daily
++ *
++ * As to MODIS data, the coverage identifier likes:
++ * HDF4_EOS:EOS_GRID:"/Volumes/RAIDL1/GeoData/MOD15A2/2007/MYD15A2.A2007241.h12v09.005.2007256053902.hdf":MOD_Grid_MOD15A2:Lai_1km
++ *
++ * @return the string of coverage identifier.
++ */
++
++string AbstractDataset::GetCoverageID()
++{
++ return ms_CoverageID;
++}
++
++/************************************************************************/
++/* GetResourceFileName() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the resource file name of a coverage.
++ *
++ * The method will return the full path corresponding the file contained
++ * coverage.
++ *
++ * @return the string of resource file path.
++ */
++
++string AbstractDataset::GetResourceFileName()
++{
++ return ms_SrcFilename;
++}
++
++/************************************************************************/
++/* GetDatasetName() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the dataset name of a coverage.
++ *
++ * The method will return the data set name corresponding the file contained
++ * coverage. For example, MOD09GQ data has the coverage identifier as following;
++ * HDF4_EOS:EOS_GRID:"/Volumes/RAIDL1/GeoData/MODISData/MOD09GQ/MOD09GQ.A2010001.h12v05.005.2010007003100.hdf":MODIS_Grid_2D:sur_refl_b01_1
++ *
++ * sur_refl_b01_1 is seemed as the dataset name.
++ *
++ * @return the string of dataset name.
++ */
++
++string AbstractDataset::GetDatasetName()
++{
++ return ms_DatasetName;
++}
++
++/************************************************************************/
++/* GetDataTypeName() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the dataset type name of a coverage.
++ *
++ * The method will return the data set name corresponding the file contained
++ * coverage. For example, MOD09GQ data has the coverage identifier as following;
++ * HDF4_EOS:EOS_GRID:"/Volumes/RAIDL1/GeoData/MODISData/MOD09GQ/MOD09GQ.A2010001.h12v05.005.2010007003100.hdf":MODIS_Grid_2D:sur_refl_b01_1
++ *
++ * MODIS_Grid_2D is seemed as the dataset type name.
++ *
++ * @return the string of dataset type name.
++ */
++
++string AbstractDataset::GetDataTypeName()
++{
++ return ms_DataTypeName;
++}
++
++/************************************************************************/
++/* GetDataTypeName() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the dataset description of a coverage.
++ *
++ * The method will build a description for the coverage. The coverage
++ * extent, dataset name, dataset type name will be contained in the
++ * description,
++ *
++ * @return the string of dataset description.
++ */
++
++string AbstractDataset::GetDatasetDescription()
++{
++ //[15x2030x1354] Band JPEG2000 (16-bit unsigned integer)
++ string rtnBuf;
++ int aiDimSizes[3];
++ int nBandCount = maptr_DS->GetRasterCount();
++ string pszString;
++ if (nBandCount > 1)
++ {
++ aiDimSizes[0] = nBandCount;
++ aiDimSizes[1] = GetImageYSize();
++ aiDimSizes[2] = GetImageXSize();
++ pszString = SPrintArray(GDT_UInt32, aiDimSizes, 3, "x");
++ }
++ else
++ {
++ aiDimSizes[0] = GetImageYSize();
++ aiDimSizes[1] = GetImageXSize();
++ pszString = SPrintArray(GDT_UInt32, aiDimSizes, 2, "x");
++ }
++
++ rtnBuf = "[" + pszString + "] " + ms_DatasetName + " " + ms_DataTypeName + " (" +
++ GDALGetDataTypeName(maptr_DS->GetRasterBand(1)->GetRasterDataType()) + ")";
++
++ return rtnBuf;
++}
++
++/************************************************************************/
++/* GetNativeFormat() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the native format of a coverage.
++ *
++ * The method will return the native format of a coverage. GDAL API
++ * GDALGetDriverShortName() will be called to generate the format.
++ *
++ * @return the string of dataset native format, in forms of GDAL Formats
++ * Code. See http://gdal.org/formats_list.html for details.
++ */
++
++string AbstractDataset::GetNativeFormat()
++{
++ return ms_NativeFormat;
++}
++
++/************************************************************************/
++/* IsbGeoTransformSet() */
++/************************************************************************/
++
++/**
++ * \brief Determine whether set the affine geoTransform for a coverage.
++ *
++ * The method will return the status of the affine GeoTransform matrix.
++ *
++ * @return TRUE if set already or FALSE on failure..
++ */
++
++int AbstractDataset::IsbGeoTransformSet()
++{
++ return mb_GeoTransformSet;
++}
++
++/************************************************************************/
++/* GetNativeBBox() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the bounding box of a coverage under the native CRS.
++ *
++ * The method will fetch the bounding box of the coverage under native CRS.
++ * The sequence of values stored in array is: xmin, xmax, ymin, ymax
++ *
++ * @param bBox an existing four double buffer into which the
++ * native bounding box values will be placed.
++ */
++
++void AbstractDataset::GetNativeBBox(double bBox[])
++{
++ if (mb_GeoTransformSet)
++ {
++ bBox[0] = md_Geotransform[0];
++ bBox[1] = bBox[0] + GetImageXSize() * md_Geotransform[1];
++ bBox[3] = md_Geotransform[3];
++ bBox[2] = bBox[3] + GetImageYSize() * md_Geotransform[5];
++ }
++ else
++ {
++ bBox[0] = 0;
++ bBox[1] = maptr_DS->GetRasterXSize() - 1;
++ bBox[2] = 0;
++ bBox[3] = maptr_DS->GetRasterYSize() - 1;
++ }
++}
++
++/************************************************************************/
++/* GetGeoMinMax() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the bounding box of a coverage under EPSG:4326.
++ *
++ * The method will fetch the bounding box of the coverage under EPSG:4326
++ * CRS. The sequence of values stored in array is: xmin, xmax, ymin, ymax
++ *
++ * @param bBox an existing four double buffer into which the geographic
++ * bounding box values will be placed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::GetGeoMinMax(double geoMinMax[])
++{
++ if (!mb_GeoTransformSet)
++ {
++ SetWCS_ErrorLocator("AbstractDataset::getGeoMinMax()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to get Geo-BoundingBox coordinates");
++ return CE_Failure;
++ }
++
++ geoMinMax[0] = md_Geotransform[0];
++ geoMinMax[1] = geoMinMax[0] + GetImageXSize() * md_Geotransform[1];
++ geoMinMax[3] = md_Geotransform[3];
++ geoMinMax[2] = geoMinMax[3] + GetImageYSize() * md_Geotransform[5];
++
++
++ if (mo_NativeCRS.IsGeographic() || Find_Compare_SubStr(ms_DataTypeName, "MODIS"))//for modis data
++ {
++ geoMinMax[0] = (geoMinMax[0] >= -180.0) ? geoMinMax[0] : -180.0;
++ geoMinMax[1] = (geoMinMax[1] <= 180.0) ? geoMinMax[1] : 180.0;
++ geoMinMax[2] = (geoMinMax[2] >= -90.0) ? geoMinMax[2] : -90.0;
++ geoMinMax[3] = (geoMinMax[3] <= 90.0) ? geoMinMax[3] : 90.0;
++ return CE_None;
++ }
++
++ OGRSpatialReference oGeoSRS;
++ oGeoSRS.CopyGeogCSFrom(&mo_NativeCRS);
++
++ My2DPoint llPt(geoMinMax[0], geoMinMax[2]);
++ My2DPoint urPt(geoMinMax[1], geoMinMax[3]);
++ if (CE_None != bBox_transFormmate(mo_NativeCRS, oGeoSRS, llPt, urPt))
++ {
++ SetWCS_ErrorLocator("AbstractDataset::getGeoMinMax()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to transform bounding box coordinates to geographic coordinates.");
++ return CE_Failure;
++ }
++
++ geoMinMax[0] = llPt.mi_X;
++ geoMinMax[1] = urPt.mi_X;
++ geoMinMax[2] = llPt.mi_Y;
++ geoMinMax[3] = urPt.mi_Y;
++
++ return CE_None;
++}
++
++
++/************************************************************************/
++/* GetImageXSize() */
++/************************************************************************/
++
++/**
++ * \brief Fetch coverage width in pixels.
++ *
++ * The method will return the width of coverage in pixels. GDAL API
++ * GetRasterXSize() will be called to generate the width value.
++ *
++ * @return the width in pixels of raster bands in this coverage.
++ */
++
++int AbstractDataset::GetImageXSize()
++{
++ return maptr_DS->GetRasterXSize();
++}
++
++/************************************************************************/
++/* GetImageYSize() */
++/************************************************************************/
++
++/**
++ * \brief Fetch coverage height in pixels.
++ *
++ * The method will return the height of coverage in pixels. GDAL API
++ * GetRasterYSize() will be called to generate the height value.
++ *
++ * @return the height in pixels of raster bands in this coverage.
++ */
++int AbstractDataset::GetImageYSize()
++{
++ return maptr_DS->GetRasterYSize();
++}
++
++/************************************************************************/
++/* GetCoverageBeginTime() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the begin date/time of a coverage.
++ *
++ * The method will return the begin date/time of a coverage. For MODIS data,
++ * each granule will cover a range of time; for TRMM data, the daily data
++ * will cover a whole day, and monthly data will cover a whole month.
++ *
++ * @return the string of begin date/time corresponding to the coverage.
++ */
++
++string AbstractDataset::GetCoverageBeginTime()
++{
++ return ms_CoverageBeginTime;
++}
++
++/************************************************************************/
++/* GetCoverageBeginTime() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the end date/time of a coverage.
++ *
++ * The method will return the end date/time of a coverage. For MODIS data,
++ * each granule will cover a range of time; for TRMM data, the daily data
++ * will cover a whole day, and monthly data will cover a whole month.
++ *
++ * @return the string of end date/time corresponding to the coverage.
++ */
++
++string AbstractDataset::GetCoverageEndTime()
++{
++ return ms_CoverageEndTime;
++}
++
++/************************************************************************/
++/* getCoverageSubType() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the coverage type.
++ *
++ * The method will return the type of the coverage, such as
++ * "ReferenceableDataset" and "RectifiedDataset".
++ *
++ * @return the string of coverage type.
++ */
++
++string AbstractDataset::GetCoverageSubType()
++{
++ return ms_CoverageSubType;
++}
++
++/************************************************************************/
++/* getFieldQuantityDef() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the field units of a coverage.
++ *
++ * The method will return the field units of coverage. For example to
++ * MOD09GQ(collection name) sur_refl_b01_1(dataset name) data, units equals
++ * to reflectance.
++ *
++ * @return the string of coverage field units.
++ */
++
++string AbstractDataset::GetFieldQuantityDef()
++{
++ return ms_FieldQuantityDef;
++}
++
++/************************************************************************/
++/* GetAllowValues() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the allow values of a coverage.
++ *
++ * The method will return the valid range of a coverage. For example to
++ * MOD09GQ(collection name) sur_refl_b01_1(dataset name) data, valid_range
++ * equals to (-100, 16000).
++ *
++ * @return the string of valid range of a coverage, in the forms of "min, max".
++ */
++
++string AbstractDataset::GetAllowValues()
++{
++ return ms_AllowRanges;
++}
++
++/************************************************************************/
++/* GetISO19115Metadata() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the coverage metadata which is compliant to ISO 19115:2003
++ * - GeoGraphic information -- Metadata; and ISO 19115(2):2009 - GeoGraphic
++ * information -- Metadata -- Part 2.
++ *
++ * The method will return the metadata of a coverage based on ISO 19115
++ * and ISO 19115(2).
++ *
++ * ISO 19115:2003 defines the schema required for
++ * describing geographic information and services. It provides information
++ * about the identification, the extent, the quality, the spatial and temporal
++ * schema, spatial reference, and distribution of digital geographic data.
++ *
++ * ISO 19115-2:2009 extends the existing geographic metadata standard by
++ * defining the schema required for describing imagery and gridded data.
++ * It provides information about the properties of the measuring equipment
++ * used to acquire the data, the geometry of the measuring process employed
++ * by the equipment, and the production process used to digitize the raw data.
++ * This extension deals with metadata needed to describe the derivation of
++ * geographic information from raw data, including the properties of the
++ * measuring system, and the numerical methods and computational procedures
++ * used in the derivation. The metadata required to address coverage data in
++ * general is addressed sufficiently in the general part of ISO 19115.
++ *
++ * @return the string of metadata of a coverage.
++ */
++
++string AbstractDataset::GetISO19115Metadata()
++{
++ return ms_ISO19115Metadata;
++}
++
++/************************************************************************/
++/* GetCoverageArchiveTime() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the archive date/time of this dataset.
++ *
++ * The method will return the archive date/time of dataset (granule).
++ *
++ * @return The string of archive date/time.
++ */
++
++string AbstractDataset::GetCoverageArchiveTime()
++{
++ return ms_CoverageArchiveTime;
++}
++
++/************************************************************************/
++/* GetCoveragePlatform() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the platform name of this dataset.
++ *
++ * The method will return the platform name of dataset (granule).
++ *
++ * @return The string of platform name.
++ */
++
++string AbstractDataset::GetCoveragePlatform()
++{
++ return ms_CoveragePlatform;
++}
++
++/************************************************************************/
++/* GetCoverageInstrument() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the instrument name of this dataset.
++ *
++ * The method will return the instrument name of dataset (granule).
++ *
++ * @return The string of instrument name.
++ */
++
++string AbstractDataset::GetCoverageInstrument()
++{
++ return ms_CoverageInstrument;
++}
++
++/************************************************************************/
++/* GetCoverageInstrument() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the sensor name of this dataset.
++ *
++ * The method will return the sensor name of dataset (granule).
++ *
++ * @return The string of sensor name.
++ */
++
++string AbstractDataset::GetCoverageSensor()
++{
++ return ms_CoverageSensor;
++}
++
++/************************************************************************/
++/* GetImageBandCount() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the number of raster bands on this dataset.
++ *
++ * The method will return the number of raster bands on this dataset. GDAL
++ * API GetRasterCount() will be called to get the count number.
++ *
++ * @return the number of raster bands on this dataset.
++ */
++
++int AbstractDataset::GetImageBandCount()
++{
++ return maptr_DS->GetRasterCount();
++}
++
++/************************************************************************/
++/* getMissingValue() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the filled value (missing value) of a coverage.
++ *
++ * The method will return the filled value of a coverage.
++ *
++ * @return the value of filled value of a coverage.
++ */
++
++const double& AbstractDataset::GetMissingValue()
++{
++ return md_MissingValue;
++}
++
++/************************************************************************/
++/* GetProjectionRef() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the native projection reference of a coverage.
++ *
++ * The method will return the the native projection reference of a coverage.
++ *
++ * @return the string of the native projection reference of a coverage.
++ */
++
++string AbstractDataset::GetProjectionRef()
++{
++ char* pszProjection = NULL;
++ mo_NativeCRS.exportToWkt(&pszProjection);
++ string tmpStr = pszProjection;
++ CPLFree(pszProjection);
++
++ return tmpStr;
++}
++
++/************************************************************************/
++/* SetMetaDataList() */
++/************************************************************************/
++
++/**
++ * \brief Set the metadata list for this coverage based on dataset object.
++ *
++ * The method will set the metadata list for the coverage based on its
++ * corresponding GDALDataset object. Will be implemented in the subclasses
++ * of AbstractDataset.
++ *
++ * @param hSrc the GDALDataset object corresponding to coverage.
++ *
++ * @return CE_Failure.
++ */
++
++CPLErr AbstractDataset::SetMetaDataList(GDALDataset* hSrc)
++{
++ return CE_Failure;
++}
++
++/************************************************************************/
++/* GetMetaDataList() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the metadata list for this coverage.
++ *
++ * The method will return the metadata list for the coverage.
++ *
++ * @return the list of metadate.
++ */
++
++vector<string> AbstractDataset::GetMetaDataList()
++{
++ return mv_MetaDataList;
++}
++
++/************************************************************************/
++/* GetBandList() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the contained band list of request coverage.
++ *
++ * The method will return the contained band list of request coverage.
++ *
++ * @return the band array.
++ */
++
++vector<int> AbstractDataset::GetBandList()
++{
++ return mv_BandList;
++}
++
++/************************************************************************/
++/* getNativeCRS_URN() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the native CRS code of coverage.
++ *
++ * The method will return the native CRS code of coverage.
++ *
++ * @return the string of the URN for native CRS of coverage.
++ */
++
++string AbstractDataset::GetNativeCRS_URN()
++{
++ string urn;
++
++ if (mo_NativeCRS.IsProjected())
++ {
++ const char* nativeAuthorityName =
++ mo_NativeCRS.GetAuthorityName("PROJCS");
++ const char* nativeAuthorityCode =
++ mo_NativeCRS.GetAuthorityCode("PROJCS");
++
++ urn = "urn:ogc:def:crs:";
++
++ if (nativeAuthorityName && (EQUAL(nativeAuthorityName,"EPSG")
++ || EQUAL(nativeAuthorityName,"OGP")
++ || EQUAL(nativeAuthorityName,"OGC")))
++ urn += (string) nativeAuthorityName + (string) ":6.3:";
++ else
++ urn += "CSISS:0.0:";
++
++ if (nativeAuthorityCode)
++ urn += (string) nativeAuthorityCode;
++ else
++ urn += "80000000";
++ }
++ else if (mo_NativeCRS.IsGeographic())
++ {
++ const char* geoAuthorityName = mo_NativeCRS.GetAuthorityName("GEOGCS");
++ const char* geoAuthorityCode = mo_NativeCRS.GetAuthorityCode("GEOGCS");
++
++ urn = "urn:ogc:def:crs:";
++ if (geoAuthorityName && (EQUAL(geoAuthorityName,"EPSG")
++ || EQUAL(geoAuthorityName,"OGP")
++ || EQUAL(geoAuthorityName,"OGC")))
++ urn += (string) geoAuthorityName + (string) ":6.3:";
++ else
++ urn += "CSISS:0.0:";
++
++ if (geoAuthorityCode)
++ urn += (string) geoAuthorityCode;
++ else
++ urn += "70000000";
++ }
++ else
++ urn = "urn:ogc:def:crs:OGC:0.0:imageCRS";
++
++ return urn;
++}
++
++/************************************************************************/
++/* GetGeoCRS_URN() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the Geographic CRS code of coverage.
++ *
++ * The method will return the Geographic CRS code of coverage.
++ *
++ * @return the URN for Geographic CRS of coverage.
++ */
++
++string AbstractDataset::GetGeoCRS_URN()
++{
++ string urn;
++
++ if (mo_NativeCRS.IsProjected() || mo_NativeCRS.IsGeographic())
++ {
++ const char* geoAuthorityName = mo_NativeCRS.GetAuthorityName("GEOGCS");
++ const char* geoAuthorityCode = mo_NativeCRS.GetAuthorityCode("GEOGCS");
++
++ urn = "urn:ogc:def:crs:";
++ if (geoAuthorityName && (EQUAL(geoAuthorityName,"EPSG")
++ || EQUAL(geoAuthorityName,"OGP")
++ || EQUAL(geoAuthorityName,"OGC")))
++ urn += (string) geoAuthorityName + (string) ":6.3:";
++ else
++ urn += "CSISS:0.0:";
++
++ if (geoAuthorityCode)
++ urn += (string) geoAuthorityCode;
++ else
++ urn += "70000000";
++
++ }
++ else
++ urn = "urn:ogc:def:crs:OGC:0.0:imageCRS";
++
++ return urn;
++}
++
++/************************************************************************/
++/* IsCrossingIDL() */
++/************************************************************************/
++
++/**
++ * \brief Determine whether the extend of coverage cross the International
++ * Date Line (IDL).
++ *
++ * The method will return the status of whether the extend of coverage
++ * cross the International Date Line (IDL).
++ *
++ * @return the TRUE of the coverage extent cross the IDL, otherwise FALSE.
++ */
++
++int AbstractDataset::IsCrossingIDL()
++{
++ double bboxArray[4];
++ GetNativeBBox(bboxArray);
++
++ OGRSpatialReference latlonSRS;
++ latlonSRS.SetWellKnownGeogCS("WGS84");
++ My2DPoint llPtex(bboxArray[0], bboxArray[2]);
++ My2DPoint urPtex(bboxArray[1], bboxArray[3]);
++ bBox_transFormmate(mo_NativeCRS, latlonSRS, llPtex, urPtex);
++
++ int bCrossCenter = false;
++ if(urPtex.mi_X < 0 && llPtex.mi_X > 0)
++ bCrossCenter = true;
++
++ return bCrossCenter;
++}
++
++/************************************************************************/
++/* GetSuggestedWarpResolution() */
++/************************************************************************/
++
++/**
++ * \brief Get the suggested warp option, method 1.
++ *
++ * @return CE_Failure if an error occurs, otherwise CE_None.
++ */
++
++CPLErr AbstractDataset::GetSuggestedWarpResolution( OGRSpatialReference& dstCRS,
++ double adfDstGeoTransform[],
++ int &nPixels,
++ int &nLines)
++{
++ if (!dstCRS.IsProjected() && !dstCRS.IsGeographic())
++ {
++ adfDstGeoTransform[0] = 0;
++ adfDstGeoTransform[1] = 1;
++ adfDstGeoTransform[2] = 0;
++ adfDstGeoTransform[3] = 0;
++ adfDstGeoTransform[4] = 0;
++ adfDstGeoTransform[5] = 1;
++
++ nPixels = GetImageXSize();
++ nLines = GetImageYSize();
++
++ }
++ else if (dstCRS.IsSame(&mo_NativeCRS))
++ {
++ memcpy(adfDstGeoTransform, md_Geotransform, sizeof(double) * 6);
++ nPixels = GetImageXSize();
++ nLines = GetImageYSize();
++ }
++ else
++ {
++ char *pszDstWKT;
++ dstCRS.exportToWkt(&pszDstWKT);
++ char *pszSrcWKT;
++ mo_NativeCRS.exportToWkt(&pszSrcWKT);
++
++ void *hTransformArg = GDALCreateGenImgProjTransformer(maptr_DS.get(),
++ (const char*) pszSrcWKT, NULL, (const char*) pszDstWKT, TRUE, 1000.0, 0);
++ OGRFree(pszDstWKT);
++ OGRFree(pszSrcWKT);
++ if (hTransformArg == NULL)
++ {
++ SetWCS_ErrorLocator("AbstractDataset::GetSuggestedWarpResolution()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Create GDAL GenImgProjTransformer.");
++
++ return CE_Failure;
++ }
++ /* -------------------------------------------------------------------- */
++ /* Get approximate output definition. */
++ /* -------------------------------------------------------------------- */
++ if (GDALSuggestedWarpOutput(maptr_DS.get(), GDALGenImgProjTransform,
++ hTransformArg, adfDstGeoTransform, &nPixels, &nLines) != CE_None)
++ {
++ SetWCS_ErrorLocator("AbstractDataset::GetSuggestedWarpResolution()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Computing Output Resolution.");
++
++ return CE_Failure;
++ }
++
++ GDALDestroyGenImgProjTransformer(hTransformArg);
++ }
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetSuggestedWarpResolution2() */
++/************************************************************************/
++
++/**
++ * \brief Get the suggested warp option, method 2.
++ *
++ * @return CE_Failure if an error occurs, otherwise CE_None.
++ */
++
++CPLErr AbstractDataset::GetSuggestedWarpResolution2(OGRSpatialReference& dstCRS,
++ double adfDstGeoTransform[],
++ int &nPixels,
++ int &nLines)
++{
++ if (dstCRS.IsLocal())
++ {
++ adfDstGeoTransform[0] = 0;
++ adfDstGeoTransform[1] = 1;
++ adfDstGeoTransform[2] = 0;
++ adfDstGeoTransform[3] = 0;
++ adfDstGeoTransform[4] = 0;
++ adfDstGeoTransform[5] = 1;
++
++ nPixels = GetImageXSize();
++ nLines = GetImageYSize();
++ }
++ else if (dstCRS.IsSame(&mo_NativeCRS))
++ {
++ memcpy(adfDstGeoTransform, md_Geotransform, sizeof(double) * 6);
++ nPixels = GetImageXSize();
++ nLines = GetImageYSize();
++ }
++ else
++ {
++ double bboxArray[4];
++ GetNativeBBox(bboxArray);
++
++ My2DPoint llPt(bboxArray[0], bboxArray[2]);
++ My2DPoint urPt(bboxArray[1], bboxArray[3]);
++ if (CE_None != bBox_transFormmate(mo_NativeCRS, dstCRS, llPt, urPt))
++ {
++ SetWCS_ErrorLocator("AbstractDataset::GetSuggestedWarpResolution2()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Transform bounding box Coordinate.");
++ return CE_Failure;
++ }
++
++ double xRes, yRes;
++ if(IsCrossingIDL())
++ {
++ yRes = (urPt.mi_Y - llPt.mi_Y) / GetImageYSize();
++ xRes = fabs((llPt.mi_X - urPt.mi_X) / GetImageXSize());
++ nLines = (urPt.mi_Y - llPt.mi_Y) / yRes + 0.5;
++ nPixels = fabs((llPt.mi_X - urPt.mi_X) / xRes + 0.5);
++ }else
++ {
++ xRes = (urPt.mi_X - llPt.mi_X) / GetImageXSize();
++ yRes = (urPt.mi_Y - llPt.mi_Y) / GetImageYSize();
++ nPixels = (urPt.mi_X - llPt.mi_X) / xRes + 0.5;
++ nLines = (urPt.mi_Y - llPt.mi_Y) / yRes + 0.5;
++ }
++
++ xRes = MIN(xRes,yRes);
++ yRes = MIN(xRes,yRes);
++
++ adfDstGeoTransform[0] = llPt.mi_X;
++ adfDstGeoTransform[1] = xRes;
++ adfDstGeoTransform[2] = 0;
++ adfDstGeoTransform[3] = urPt.mi_Y;
++ adfDstGeoTransform[4] = 0;
++ adfDstGeoTransform[5] = -yRes;
++ }
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* DatasetWarper() */
++/************************************************************************/
++
++/**
++ * Wrap the dataset to a GDALDataset object based on input parameters.
++ *
++ * @return the warpped GDALDataset object.
++ */
++/************************************************************************/
++/* DatasetWarper() */
++/************************************************************************/
++
++/**
++ * \brief Wrap the dataset to a GDALDataset object based on input parameters.
++ *
++ * @return GDALDatset object.
++ */
++
++GDALDataset* AbstractDataset::DatasetWarper(int& IsRefDS,
++ OGRSpatialReference& dstCRS,
++ int& iDstRasterXsize,
++ int& iDstRasterYsize,
++ double pDstGeoTransform[],
++ GDALResampleAlg eResampleAlg)
++{
++ OGRSpatialReference locCRS=dstCRS;
++ if (dstCRS.IsLocal())
++ locCRS=mo_NativeCRS;
++
++ if((mo_NativeCRS.IsSame(&locCRS) &&
++ iDstRasterXsize == maptr_DS->GetRasterXSize() &&
++ iDstRasterYsize == maptr_DS->GetRasterYSize())&&
++ CPLIsEqual(md_Geotransform[0],pDstGeoTransform[0])&&
++ CPLIsEqual(md_Geotransform[1],pDstGeoTransform[1])&&
++ CPLIsEqual(md_Geotransform[3],pDstGeoTransform[3])&&
++ CPLIsEqual(md_Geotransform[5],pDstGeoTransform[5]))
++ {
++ IsRefDS = TRUE;
++ return maptr_DS.get();
++ }
++
++ char *sDstCRS_WKT;
++ locCRS.exportToWkt(&sDstCRS_WKT);
++
++ /* Create a memory data-set for re-projection */
++ GDALDriverH poDriver = GDALGetDriverByName("MEM");
++
++ int nBand = maptr_DS->GetRasterCount();
++ GDALDataset* hMemDS = (GDALDataset*) GDALCreate(poDriver, "", iDstRasterXsize,
++ iDstRasterYsize, nBand, GDALGetRasterDataType(maptr_DS->GetRasterBand(1)), NULL);
++ if (NULL == hMemDS)
++ {
++ GDALClose(poDriver);
++ OGRFree(sDstCRS_WKT);
++ return NULL;
++ }
++
++ hMemDS->SetProjection(sDstCRS_WKT);
++ hMemDS->SetGeoTransform(pDstGeoTransform);
++
++ for (int i = 1; i <= nBand; i++)
++ {
++ hMemDS->GetRasterBand(i)->SetNoDataValue(md_MissingValue);
++ }
++
++ /* -------------------------------------------------------------------- */
++ /* Perform the re-projection. */
++ /* -------------------------------------------------------------------- */
++ char *srcWKT;
++ mo_NativeCRS.exportToWkt(&srcWKT);
++ if (CE_None != GDALReprojectImage(maptr_DS.get(), srcWKT, hMemDS,
++ sDstCRS_WKT, eResampleAlg, 0, 0.125, NULL, NULL, NULL))
++ {
++ GDALClose(poDriver);
++ GDALClose(GDALDatasetH(hMemDS));
++ OGRFree(sDstCRS_WKT);
++ OGRFree(srcWKT);
++ return NULL;
++ }
++ IsRefDS = FALSE;
++ OGRFree(sDstCRS_WKT);
++ OGRFree(srcWKT);
++
++ return hMemDS;
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/AbstractDataset.h bes-3.12.0/functions/swath2grid/AbstractDataset.h
+--- bes-3.12.0/functions.orig/swath2grid/AbstractDataset.h 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/AbstractDataset.h 2014-03-03 15:47:38.050232928 +0100
+@@ -0,0 +1,150 @@
++/******************************************************************************
++ * $Id: AbstractDataset.h 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: AbstractDataset class definition
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 ABSTRACTDATASET_H_
++#define ABSTRACTDATASET_H_
++
++#include <vector>
++#include <memory>
++
++#include <gdal.h>
++#include <gdal_priv.h>
++#include <gdalwarper.h>
++#include <ogrsf_frmts.h>
++#include <ogr_spatialref.h>
++#include <cpl_conv.h>
++#include <cpl_minixml.h>
++#include <vrtdataset.h>
++
++#include "wcsUtil.h"
++
++using namespace std;
++
++/* ******************************************************************** */
++/* AbstractDataset */
++/* ******************************************************************** */
++
++//! Abstract dataset model definition. Based on GDAL dataset model.
++class AbstractDataset {
++
++protected:
++ auto_ptr<GDALDataset> maptr_DS;
++
++ // Coverage Information Related
++ string ms_CoverageID;
++ string ms_CoverageBeginTime;
++ string ms_CoverageEndTime;
++ string ms_CoverageSubType;
++ string ms_CoverageArchiveTime;
++ string ms_CoveragePlatform;
++ string ms_CoverageInstrument;
++ string ms_CoverageSensor;
++ string ms_SrcFilename;
++ string ms_DatasetName;
++ string ms_DataTypeName;
++ string ms_NativeFormat;
++ string ms_FieldQuantityDef;
++ string ms_AllowRanges;
++ string ms_ISO19115Metadata;
++
++ vector<int> mv_BandList;
++ vector<string> mv_MetaDataList;
++
++ double md_Geotransform[6];
++ double md_GeoMinMax[4]; // Order: xmin, xmax, ymin, ymax
++ double md_MissingValue;
++
++ int mb_GeoTransformSet;
++ int mb_IsVirtualDS;
++
++ OGRSpatialReference mo_NativeCRS;
++
++protected:
++ AbstractDataset();
++ virtual CPLErr SetNativeCRS();
++ virtual CPLErr SetGeoTransform();
++ virtual CPLErr SetGDALDataset(const int isSimple = 0);
++ virtual CPLErr SetMetaDataList(GDALDataset*);
++
++public:
++ AbstractDataset(const string&, vector<int> &);
++ virtual ~AbstractDataset();
++
++ GDALDataset* GetGDALDataset();
++
++ // Virtual Functions Definition
++ virtual CPLErr InitialDataset(const int isSimple = 0);
++
++ // Fetch Function Related
++ const OGRSpatialReference& GetNativeCRS();
++ const double& GetMissingValue();
++ int GetGeoTransform(double geoTrans[]);
++ vector<string> GetMetaDataList();
++ vector<int> GetBandList();
++ void GetNativeBBox(double bBox[]);
++ CPLErr GetGeoMinMax(double geoMinMax[]);
++
++ int GetImageBandCount();
++ int GetImageXSize();
++ int GetImageYSize();
++ string GetResourceFileName();
++ string GetDatasetName();
++ string GetDataTypeName();
++ string GetNativeFormat();
++ string GetCoverageID();
++ string GetDatasetDescription();
++ string GetNativeCRS_URN();
++ string GetGeoCRS_URN();
++ string GetProjectionRef();
++ string GetCoverageBeginTime();
++ string GetCoverageEndTime();
++ string GetCoverageSubType();
++ string GetFieldQuantityDef();
++ string GetAllowValues();
++ string GetISO19115Metadata();
++ string GetCoverageArchiveTime();
++ string GetCoveragePlatform();
++ string GetCoverageInstrument();
++ string GetCoverageSensor();
++
++ // Fetch Variables Status Related
++ int IsbGeoTransformSet();
++ int IsCrossingIDL();
++
++ CPLErr GetSuggestedWarpResolution(OGRSpatialReference& dstCRS, double adfDstGeoTransform[], int &nPixels,
++ int &nLines);
++ CPLErr GetSuggestedWarpResolution2(OGRSpatialReference& dstCRS, double adfDstGeoTransform[], int &nPixels,
++ int &nLines);
++
++ GDALDataset* DatasetWarper(int& IsRefDS, OGRSpatialReference& dstCRS, int& iDstRasterXsize, int& iDstRasterYsize,
++ double pDstGeoTransform[], GDALResampleAlg eResampleAlg = GRA_NearestNeighbour);
++};
++
++#endif /*ABSTRACTDATASET_H_*/
+diff -Nur bes-3.12.0/functions.orig/swath2grid/airs.nc.0.data.bescmd bes-3.12.0/functions/swath2grid/airs.nc.0.data.bescmd
+--- bes-3.12.0/functions.orig/swath2grid/airs.nc.0.data.bescmd 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/airs.nc.0.data.bescmd 2014-03-03 15:47:38.050232928 +0100
+@@ -0,0 +1,13 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<request reqID ="some_unique_value" >
++ <setContext name="dap_format">dap2</setContext>
++ <setContext name="xdap_accept">3.3</setContext>
++ <setContainer name="c" space="catalog">/data/nc/OWS_9_Data/AIRS_570672/AIRS_AQUA_L1B_BRIGHTNESS_20101026_1617.nc.gz</setContainer>
++ <define name="d">
++ <container name="c">
++ <constraint>swath2grid(topog,Latitude,Longitude)</constraint>
++ </container>
++ </define>
++ <get type="dods" definition="d"/>
++</request>
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/airs.nc.0.ddx.bescmd bes-3.12.0/functions/swath2grid/airs.nc.0.ddx.bescmd
+--- bes-3.12.0/functions.orig/swath2grid/airs.nc.0.ddx.bescmd 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/airs.nc.0.ddx.bescmd 2014-03-03 15:47:38.053566262 +0100
+@@ -0,0 +1,13 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<request reqID ="some_unique_value" >
++ <setContext name="dap_format">dap2</setContext>
++ <setContext name="xdap_accept">3.3</setContext>
++ <setContainer name="c" space="catalog">/data/nc/OWS_9_Data/AIRS_570672/AIRS_AQUA_L1B_BRIGHTNESS_20101026_1617.nc.gz</setContainer>
++ <define name="d">
++ <container name="c">
++ <constraint>swath2grid(topog,Latitude,Longitude)</constraint>
++ </container>
++ </define>
++ <get type="das" definition="d"/>
++</request>
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/airs.nc.1.err.bescmd bes-3.12.0/functions/swath2grid/airs.nc.1.err.bescmd
+--- bes-3.12.0/functions.orig/swath2grid/airs.nc.1.err.bescmd 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/airs.nc.1.err.bescmd 2014-03-03 15:47:38.043566262 +0100
+@@ -0,0 +1,13 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<request reqID ="some_unique_value" >
++ <setContext name="dap_format">dap2</setContext>
++ <setContext name="xdap_accept">3.3</setContext>
++ <setContainer name="c" space="catalog">/data/nc/OWS_9_Data/AIRS_570672/AIRS_AQUA_L1B_BRIGHTNESS_20101026_1617.nc.gz</setContainer>
++ <define name="d">
++ <container name="c">
++ <constraint>swath2grid()</constraint>
++ </container>
++ </define>
++ <get type="dods" definition="d"/>
++</request>
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/bes.conf.in bes-3.12.0/functions/swath2grid/bes.conf.in
+--- bes-3.12.0/functions.orig/swath2grid/bes.conf.in 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/bes.conf.in 2014-03-03 15:47:38.050232928 +0100
+@@ -0,0 +1,48 @@
++BES.ServerAdministrator=root@null.dev
++
++BES.User=user_name
++BES.Group=group_name
++
++BES.LogName=./bes.log
++BES.LogVerbose=no
++
++BES.modules=dap,cmd,nc,h4,fong,fonc
++BES.module.dap=@libdir@/bes/libdap_module.so
++BES.module.cmd=@libdir@/bes/libdap_xml_module.so
++
++BES.module.nc=@libdir@/bes/libnc_module.so
++BES.module.h4=@libdir@/bes/libhdf4_module.so
++
++BES.module.fong=@libdir@/bes/libfong_module.so
++BES.module.fonc=@libdir@/bes/libfonc_module.so
++
++BES.Catalog.catalog.RootDirectory=@abs_top_srcdir@
++BES.Data.RootDirectory=/dev/null
++
++BES.Catalog.catalog.TypeMatch=nc:.*.nc(.bz2|.gz|.Z)?$;h4:.*.(hdf|HDF|eos)(.bz2|.gz|.Z)?$;
++
++BES.Catalog.catalog.Include=;
++BES.Catalog.catalog.Exclude=^\..*;
++
++BES.FollowSymLinks=No
++BES.Catalog.catalog.FollowSymLinks=No
++
++BES.ServerPort=10002
++
++BES.CacheDir=/tmp
++BES.CachePrefix=bes_cache
++BES.CacheSize=500
++
++BES.Container.Persistence=strict
++
++BES.Memory.GlobalArea.EmergencyPoolSize=1
++BES.Memory.GlobalArea.MaximumHeapSize=20
++BES.Memory.GlobalArea.Verbose=no
++BES.Memory.GlobalArea.ControlHeap=no
++
++BES.ProcessManagerMethod=multiple
++
++BES.DefaultResponseMethod=POST
++
++FONg.TempDirectory=@abs_top_srcdir@/tests
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/BoundingBox.cpp bes-3.12.0/functions/swath2grid/BoundingBox.cpp
+--- bes-3.12.0/functions.orig/swath2grid/BoundingBox.cpp 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/BoundingBox.cpp 2014-03-03 15:47:38.050232928 +0100
+@@ -0,0 +1,360 @@
++/******************************************************************************
++ * $Id: BoundingBox.cpp 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: BoundingBox class implementation, enable transform bounding box
++ * between different CRS
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 <vector>
++#include <iostream>
++
++#include "BoundingBox.h"
++#include "wcs_error.h"
++
++using namespace std;
++
++My2DPoint::~My2DPoint()
++{
++
++}
++
++BoundingBox::BoundingBox()
++{
++
++}
++
++BoundingBox::~BoundingBox()
++{
++
++}
++
++BoundingBox BoundingBox::TransformWorkExtend(OGRSpatialReference &dstCRS, int &IsOK)
++{
++ if (mo_CRS.IsSame(&dstCRS))
++ {
++ IsOK = TRUE;
++ return *this;
++ }
++
++ OGRCoordinateTransformation *poCT = OGRCreateCoordinateTransformation(&mo_CRS, &dstCRS);
++ if (poCT == NULL)
++ {
++ IsOK = FALSE;
++ return *this;
++ }
++
++ double xdes = (mo_UpperRightPT.mi_X - mo_LowerLeftPT.mi_X) / 100;
++
++ if (mo_CRS.IsGeographic()
++ && mo_UpperRightPT.mi_X < mo_LowerLeftPT.mi_X
++ && mo_LowerLeftPT.mi_X > 0 && mo_UpperRightPT.mi_X < 0)
++ {
++ xdes = (360 + mo_UpperRightPT.mi_X - mo_LowerLeftPT.mi_X) / 100;
++ }
++
++ vector<double> x;
++ vector<double> y;
++ //up and down edge
++ for (double stepX = mo_LowerLeftPT.mi_X; stepX < mo_UpperRightPT.mi_X; stepX
++ += xdes)
++ {
++ x.push_back(stepX);
++ y.push_back(mo_UpperRightPT.mi_Y);
++ x.push_back(stepX);
++ y.push_back(mo_LowerLeftPT.mi_Y);
++ }
++ x.push_back(mo_UpperRightPT.mi_X);
++ y.push_back(mo_UpperRightPT.mi_Y);
++ x.push_back(mo_UpperRightPT.mi_X);
++ y.push_back(mo_LowerLeftPT.mi_Y);
++
++ double yMin = numeric_limits<double>::max();
++ double yMax = numeric_limits<double>::min();
++
++ int k = 0;
++ vector<int> bSuccess;
++ vector<double> tmpX;
++ vector<double> tmpY;
++
++ for (unsigned int i = 0; i < x.size(); i++)
++ {
++ tmpX.push_back(x[i]);
++ tmpY.push_back(y[i]);
++ bSuccess.push_back(0);
++ }
++
++ poCT->TransformEx(x.size(), &tmpX[0], &tmpY[0], NULL, &bSuccess[0]);
++
++ for (unsigned int n = 0; n < x.size(); n++)
++ {
++ if (bSuccess[n])
++ {
++ ++k;
++ yMin = MIN(yMin,tmpY[n]);
++ yMax = MAX(yMax,tmpY[n]);
++ }
++ }
++
++ if (k < 80)
++ {
++ IsOK = FALSE;
++ OCTDestroyCoordinateTransformation(poCT);
++ return *this;
++ }
++
++ //find xmin on left edge and xmax on right edge
++ double xMin;
++ double xMax;
++
++ double tmpPTX[2];
++ double tmpPTY[2];
++
++ int isSucc[2];
++
++ tmpPTX[0] = mo_LowerLeftPT.mi_X;
++ tmpPTX[1] = mo_LowerLeftPT.mi_X;
++ tmpPTY[0] = mo_LowerLeftPT.mi_Y;
++ tmpPTY[1] = mo_UpperRightPT.mi_Y;
++
++ poCT->TransformEx(2, tmpPTX, tmpPTY, NULL, isSucc);
++ if (isSucc[0] && isSucc[1])
++ {
++ xMin = MIN(tmpPTX[0],tmpPTX[1]);
++ }
++ else
++ {
++ OCTDestroyCoordinateTransformation(poCT);
++ IsOK = FALSE;
++ return *this;
++ }
++
++ tmpPTX[0] = mo_UpperRightPT.mi_X;
++ tmpPTX[1] = mo_UpperRightPT.mi_X;
++ tmpPTY[0] = mo_UpperRightPT.mi_Y;
++ tmpPTY[1] = mo_LowerLeftPT.mi_Y;
++
++ poCT->TransformEx(2, tmpPTX, tmpPTY, NULL, isSucc);
++ if (isSucc[0] && isSucc[1])
++ {
++ xMax = MAX(tmpPTX[0],tmpPTX[1]);
++ }
++ else
++ {
++ OCTDestroyCoordinateTransformation(poCT);
++ IsOK = FALSE;
++ return *this;
++ }
++
++ BoundingBox bbox(My2DPoint(xMin, yMin), My2DPoint(xMax, yMax), dstCRS);
++
++ if (dstCRS.IsGeographic())
++ {
++ if (xMin > 180)
++ xMin = xMin - 360;
++ if (xMax > 180)
++ xMax = xMax - 360;
++
++ if (xMin >= 180.)
++ xMin = 180.;
++ if (xMin <= -180.)
++ xMin = -180.;
++ if (xMax >= 180.)
++ xMax = 180.;
++ if (xMax <= -180.)
++ xMax = -180.;
++
++ if (yMin < 0.)
++ yMin = 0.;
++ if (yMax > 90.)
++ yMax = 90.;
++ }
++ OCTDestroyCoordinateTransformation(poCT);
++ IsOK = TRUE;
++ return BoundingBox(My2DPoint(xMin, yMin), My2DPoint(xMax, yMax), dstCRS);
++}
++
++BoundingBox BoundingBox::Transform(const double GeoTransform[])
++{
++ My2DPoint llPt;
++ My2DPoint urPt;
++ llPt.mi_X = GeoTransform[0] + GeoTransform[1] * mo_LowerLeftPT.mi_X + GeoTransform[2] * mo_LowerLeftPT.mi_Y;
++ llPt.mi_Y = GeoTransform[3] + GeoTransform[4] * mo_LowerLeftPT.mi_X + GeoTransform[5] * mo_LowerLeftPT.mi_Y;
++ urPt.mi_X = GeoTransform[0] + GeoTransform[1] * mo_UpperRightPT.mi_X + GeoTransform[2] * mo_UpperRightPT.mi_Y;
++ urPt.mi_Y = GeoTransform[3] + GeoTransform[4] * mo_UpperRightPT.mi_X + GeoTransform[5] * mo_UpperRightPT.mi_Y;
++
++ return BoundingBox(llPt,urPt,mo_CRS);
++}
++
++/**
++ * Transform Coordinates of lowercorner_left and upcorner_right
++ * lowLeft, upRight.
++ * the return value has considered the case of image area crossing 180/-180 longitude line,
++ * so lowLeft.x maybe bigger than upRight.x
++ */
++CPLErr CPL_STDCALL bBox_transFormmate(OGRSpatialReference& oSrcCRS,
++ OGRSpatialReference& oDesCRS, My2DPoint& lowLeft, My2DPoint& upRight)
++{
++ if (oSrcCRS.IsSame(&oDesCRS))
++ return CE_None;
++
++ OGRCoordinateTransformation *poCT = OGRCreateCoordinateTransformation(&oSrcCRS, &oDesCRS);
++ if (poCT == NULL)
++ {
++ SetWCS_ErrorLocator("bBox_transFormmate()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Create \"OGRCoordinateTransformation\"");
++ return CE_Failure;
++ }
++
++ double xdes = (upRight.mi_X - lowLeft.mi_X) / 100;
++ if (oSrcCRS.IsGeographic() && upRight.mi_X < lowLeft.mi_X && lowLeft.mi_X > 0 && upRight.mi_X < 0)
++ {
++ xdes = (360 + upRight.mi_X - lowLeft.mi_X) / 100;
++ }
++
++ vector<double> x, y;
++ //up and down edge
++ for (double stepX = lowLeft.mi_X; stepX < upRight.mi_X; stepX += xdes)
++ {
++ x.push_back(stepX);
++ y.push_back(upRight.mi_Y);
++ x.push_back(stepX);
++ y.push_back(lowLeft.mi_Y);
++ }
++ x.push_back(upRight.mi_X);
++ y.push_back(upRight.mi_Y);
++ x.push_back(upRight.mi_X);
++ y.push_back(lowLeft.mi_Y);
++
++ double yMin = numeric_limits<double>::max();
++ double yMax = -numeric_limits<double>::max();
++
++ int k = 0;
++ vector<int> bSuccess;
++ vector<double> tmpX;
++ vector<double> tmpY;
++
++ for (unsigned int i = 0; i < x.size(); i++)
++ {
++ tmpX.push_back(x[i]);
++ tmpY.push_back(y[i]);
++ bSuccess.push_back(0);
++ }
++
++ poCT->TransformEx(x.size(), &tmpX[0], &tmpY[0], NULL, &bSuccess[0]);
++
++ for (unsigned int n = 0; n < x.size(); n++)
++ {
++ if (bSuccess[n])
++ {
++ ++k;
++ yMin = MIN(yMin,tmpY[n]);
++ yMax = MAX(yMax,tmpY[n]);
++ }
++ }
++
++ if (k < 80)
++ {
++ OCTDestroyCoordinateTransformation(poCT);
++ SetWCS_ErrorLocator("bBox_transFormmate()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Transform Coordinates");
++ return CE_Failure;
++ }
++
++ double xMin;
++ double xMax;
++
++ //find xmin on left edge and xmax on right edge
++ double tmpPTX[2];
++ double tmpPTY[2];
++ int isOK[2];
++
++ tmpPTX[0] = lowLeft.mi_X;
++ tmpPTX[1] = lowLeft.mi_X;
++ tmpPTY[0] = upRight.mi_Y;
++ tmpPTY[1] = lowLeft.mi_Y;
++
++ poCT->TransformEx(2, tmpPTX, tmpPTY, NULL, isOK);
++ if (isOK[0] && isOK[1])
++ {
++ xMin = MIN(tmpPTX[0],tmpPTX[1]);
++ }
++ else
++ {
++ OCTDestroyCoordinateTransformation(poCT);
++ SetWCS_ErrorLocator("bBox_transFormmate()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Transform Coordinates");
++ return CE_Failure;
++ }
++
++ tmpPTX[0] = upRight.mi_X;
++ tmpPTX[1] = upRight.mi_X;
++ tmpPTY[0] = upRight.mi_Y;
++ tmpPTY[1] = lowLeft.mi_Y;
++
++ poCT->TransformEx(2, tmpPTX, tmpPTY, NULL, isOK);
++ if (isOK[0] && isOK[1])
++ {
++ xMax = MAX(tmpPTX[0],tmpPTX[1]);
++ }
++ else
++ {
++ SetWCS_ErrorLocator("bBox_transFormmate()");
++ OCTDestroyCoordinateTransformation(poCT);
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Transform Coordinates");
++ return CE_Failure;
++ }
++
++ lowLeft.mi_X = xMin;
++ lowLeft.mi_Y = yMin;
++ upRight.mi_X = xMax;
++ upRight.mi_Y = yMax;
++
++ if (oDesCRS.IsGeographic())
++ {
++ if (xMin > 180)
++ lowLeft.mi_X = xMin - 360;
++ if (xMax > 180)
++ upRight.mi_X = xMax - 360;
++
++ if (lowLeft.mi_X >= 180.)
++ lowLeft.mi_X = 180.;
++ if (lowLeft.mi_X <= -180.)
++ lowLeft.mi_X = -180.;
++ if (upRight.mi_X >= 180.)
++ upRight.mi_X = 180.;
++ if (upRight.mi_X <= -180.)
++ upRight.mi_X = -180.;
++
++ if (lowLeft.mi_Y <= -90.)
++ lowLeft.mi_Y = -90.;
++ if (upRight.mi_Y >= 90.)
++ upRight.mi_Y = 90.;
++ }
++ OCTDestroyCoordinateTransformation(poCT);
++
++ return CE_None;
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/BoundingBox.h bes-3.12.0/functions/swath2grid/BoundingBox.h
+--- bes-3.12.0/functions.orig/swath2grid/BoundingBox.h 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/BoundingBox.h 2014-03-03 15:47:38.053566262 +0100
+@@ -0,0 +1,137 @@
++/******************************************************************************
++ * $Id: BoundingBox.h 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: BoundingBox class definition
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 BOUNDINGBOX_H_
++#define BOUNDINGBOX_H_
++
++#include <gdal.h>
++#include <ogr_spatialref.h>
++#include <limits>
++#include <stdlib.h>
++
++using namespace std;
++
++/************************************************************************/
++/* ==================================================================== */
++/* My2DPoint */
++/* ==================================================================== */
++/************************************************************************/
++
++/**
++ * \class My2DPoint "BoundingBox.h"
++ *
++ * My2DPoint class is used to store the point coordinates.
++ */
++
++class My2DPoint
++{
++public:
++ double mi_X;
++ double mi_Y;
++
++ virtual ~My2DPoint();
++
++ My2DPoint()
++ {
++ mi_X = 0;
++ mi_Y = 0;
++ }
++
++ My2DPoint(const double& xx, const double& yy) :
++ mi_X(xx), mi_Y(yy)
++ {
++ }
++
++ My2DPoint(const My2DPoint& p) :
++ mi_X(p.mi_X), mi_Y(p.mi_Y)
++ {
++ }
++
++ My2DPoint& operator =(const My2DPoint& p)
++ {
++ mi_X = p.mi_X;
++ mi_Y = p.mi_Y;
++ return *this;
++ }
++};
++
++/************************************************************************/
++/* ==================================================================== */
++/* BoundingBox */
++/* ==================================================================== */
++/************************************************************************/
++
++/**
++ * \class BoundingBox "BoundingBox.h"
++ *
++ * BoundingBox class is used to transform bounding box between different
++ * Coordinate Reference System.
++ */
++
++class BoundingBox
++{
++public:
++ My2DPoint mo_LowerLeftPT;
++ My2DPoint mo_UpperRightPT;
++ OGRSpatialReference mo_CRS;
++
++ BoundingBox(const My2DPoint& llpt, const My2DPoint& urpt, OGRSpatialReference& crs) :
++ mo_LowerLeftPT(llpt), mo_UpperRightPT(urpt), mo_CRS(crs)
++ {
++
++ }
++
++ BoundingBox(OGRSpatialReference& crs) :
++ mo_LowerLeftPT(0,0), mo_UpperRightPT(0,0), mo_CRS(crs)
++ {
++
++ }
++ BoundingBox& operator =(const BoundingBox& box)
++ {
++ mo_LowerLeftPT = box.mo_LowerLeftPT;
++ mo_UpperRightPT = box.mo_UpperRightPT;
++ mo_CRS = box.mo_CRS;
++ return *this;
++ }
++
++ BoundingBox();
++ virtual ~BoundingBox();
++
++ BoundingBox Transform(OGRSpatialReference&, int&);
++ BoundingBox TransformWorkExtend(OGRSpatialReference&, int&);
++ BoundingBox Transform(const double*);
++};
++
++CPLErr CPL_DLL CPL_STDCALL bBox_transFormmate( OGRSpatialReference&,
++ OGRSpatialReference&,
++ My2DPoint& lowLeft,
++ My2DPoint& upRight);
++
++#endif /* BOUNDINGBOX_H_ */
+diff -Nur bes-3.12.0/functions.orig/swath2grid/DAP_Dataset.cpp bes-3.12.0/functions/swath2grid/DAP_Dataset.cpp
+--- bes-3.12.0/functions.orig/swath2grid/DAP_Dataset.cpp 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/DAP_Dataset.cpp 2014-03-03 15:47:38.046899595 +0100
+@@ -0,0 +1,730 @@
++
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2012 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++#include <cstdlib>
++
++#define DODS_DEBUG
++
++#include "DAP_Dataset.h"
++
++#include "Array.h"
++#include "Grid.h"
++#include "Float64.h"
++
++#include "ce_functions.h"
++#include "util.h"
++#include "debug.h"
++
++using namespace libdap;
++using namespace std;
++
++#if 0
++#define GOES_TIME_DEBUG FALSE
++#endif
++
++namespace libdap {
++
++DAP_Dataset::DAP_Dataset()
++{
++}
++
++/************************************************************************/
++/* ~DAP_Dataset() */
++/************************************************************************/
++
++/**
++ * \brief Destroy an open DAP_Dataset object.
++ *
++ * This is the accepted method of closing a DAP_Dataset dataset and
++ * deallocating all resources associated with it.
++ */
++
++DAP_Dataset::~DAP_Dataset()
++{
++}
++
++/************************************************************************/
++/* DAP_Dataset() */
++/************************************************************************/
++
++/**
++ * \brief Create an DAP_Dataset object.
++ *
++ * This is the accepted method of creating a DAP_Dataset object and
++ * allocating all resources associated with it.
++ *
++ * @param id The coverage identifier.
++ *
++ * @param rBandList The field list selected for this coverage. For TRMM
++ * daily data, the user could specify multiple days range in request.
++ * Each day is seemed as one field.
++ *
++ * @return A DAP_Dataset object.
++ */
++
++DAP_Dataset::DAP_Dataset(const string& id, vector<int> &rBandList) :
++ AbstractDataset(id, rBandList)
++{
++ md_MissingValue = 0;
++ mb_GeoTransformSet = FALSE;
++}
++
++/**
++ * @brief Initialize a DAP Dataset using Array objects already read.
++ *
++ *
++ */
++
++DAP_Dataset::DAP_Dataset(Array *src, Array *lat, Array *lon) :
++ AbstractDataset(), m_src(src), m_lat(lat), m_lon(lon)
++{
++#if 1
++ // TODO Remove these?
++ DBG(cerr << "Registering GDAL drivers" << endl);
++ GDALAllRegister();
++ OGRRegisterAll();
++#endif
++
++ CPLSetErrorHandler(CPLQuietErrorHandler);
++
++ // Read this from the 'missing_value' or '_FillValue' attributes
++ string missing_value = m_src->get_attr_table().get_attr("missing_value");
++ if (missing_value.empty())
++ missing_value = m_src->get_attr_table().get_attr("_FillValue");
++
++ if (!missing_value.empty())
++ md_MissingValue = atof(missing_value.c_str());
++ else
++ md_MissingValue = 0;
++
++ mb_GeoTransformSet = FALSE;
++}
++
++/************************************************************************/
++/* InitialDataset() */
++/************************************************************************/
++
++/**
++ * \brief Initialize the GOES dataset with NetCDF format.
++
++ * This method is the implementation for initializing a GOES dataset with NetCDF format.
++ * Within this method, SetNativeCRS(), SetGeoTransform() and SetGDALDataset()
++ * will be called to initialize an GOES dataset.
++ *
++ * @note To use this, call this method and then access the GDALDataset that
++ * contains the reprojected array using maptr_DS.get().
++ *
++ * @param isSimple the WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::InitialDataset(const int isSimple)
++{
++ DBG(cerr << "In InitialDataset" << endl);
++
++ // Might break that operation out so the remap is a separate call
++ if (CE_None != SetNativeCRS() || CE_None != SetGeoTransform())
++ throw Error("Could not set the dataset native CRS or the GeoTransform.");
++
++ DBG(cerr << "Before SetGDALDataset" << endl);
++
++ if (CE_None != SetGDALDataset(isSimple)) {
++ GDALClose(maptr_DS.release());
++ throw Error("Could not reproject the dataset.");
++ }
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetDAPArray() */
++/************************************************************************/
++
++/**
++ * @brief Build a DAP Array from the GDALDataset
++ */
++Array *DAP_Dataset::GetDAPArray()
++{
++ DBG(cerr << "In GetDAPArray" << endl);
++ DBG(cerr << "maptr_DS: " << maptr_DS.get() << endl);
++ DBG(cerr << "raster band count: " << maptr_DS->GetRasterCount() << endl);
++
++ // There should be just one band
++ if (maptr_DS->GetRasterCount() != 1)
++ throw Error("In function swath2grid(), expected a single raster band.");
++
++ // Get the x and y dimensions of the raster band
++ int x = maptr_DS->GetRasterXSize();
++ int y = maptr_DS->GetRasterYSize();
++ GDALRasterBand *rb = maptr_DS->GetRasterBand(1);
++ if (!rb)
++ throw Error("In function swath2grid(), could not access the raster data.");
++
++ // Since the DAP_Dataset code works with all data values as doubles,
++ // Assume the raster band has GDAL type GDT_Float64, but test anyway
++ if (GDT_Float64 != rb->GetRasterDataType())
++ throw Error("In function swath2grid(), expected raster data to be of type double.");
++
++ DBG(cerr << "Destination array will have dimensions: " << x << ", " << y << endl);
++
++ Array *a = new Array(m_src->name(), new Float64(m_src->name()));
++
++ // Make the result array have two dimensions
++ Array::Dim_iter i = m_src->dim_begin();
++
++ a->append_dim(x, m_src->dimension_name(i));
++ ++i;
++
++ if (i == m_src->dim_end())
++ throw Error("In function swath2grid(), expected source array to have two dimensions (2).");
++
++ a->append_dim(y, m_src->dimension_name(i));
++
++ // Poke in the data values
++ /* RasterIO ( GDALRWFlag eRWFlag,
++ int nXOff,
++ int nYOff,
++ int nXSize,
++ int nYSize,
++ void * pData,
++ int nBufXSize,
++ int nBufYSize,
++ GDALDataType eBufType,
++ int nPixelSpace,
++ int nLineSpace
++ ) */
++ vector<double> data(x * y);
++ rb->RasterIO(GF_Read, 0, 0, x, y, &data[0], x, y, GDT_Float64, 0, 0);
++
++ // NB: set_value() copies into new storage
++ a->set_value(data, data.size());
++
++ // Now poke in some attributes
++ // TODO Make these CF attributes
++ string projection_info = maptr_DS->GetProjectionRef();
++ string gcp_projection_info = maptr_DS->GetGCPProjection();
++
++ // This sets the instance variable that holds the geotransform coefs. These
++ // are needed by the GetDAPGrid() method.
++ if (CE_None != maptr_DS->GetGeoTransform (m_geo_transform_coef))
++ throw Error("In function swath2grid(), could not access the geo transform data.");
++
++ DBG(cerr << "projection_info: " << projection_info << endl);
++ DBG(cerr << "gcp_projection_info: " << gcp_projection_info << endl);
++ DBG(cerr << "geo_transform coefs: " << double_to_string(m_geo_transform_coef[0]) << endl);
++
++ AttrTable &attr = a->get_attr_table();
++ attr.append_attr("projection", "String", projection_info);
++ attr.append_attr("gcp_projection", "String", gcp_projection_info);
++ for (unsigned int i = 0; i < sizeof(m_geo_transform_coef); ++i) {
++ attr.append_attr("geo_transform_coefs", "String", double_to_string(m_geo_transform_coef[i]));
++ }
++
++ return a;
++}
++
++/************************************************************************/
++/* GetDAPGrid() */
++/************************************************************************/
++
++/**
++ * @brief Build a DAP Grid from the GDALDataset
++ */
++Grid *DAP_Dataset::GetDAPGrid()
++{
++ DBG(cerr << "In GetDAPGrid" << endl);
++
++ Array *a = GetDAPArray();
++ Array::Dim_iter i = a->dim_begin();
++ int lon_size = a->dimension_size(i);
++ int lat_size = a->dimension_size(++i);
++
++ Grid *g = new Grid(a->name());
++ g->add_var_nocopy(a, array);
++
++ // Add maps; assume lon, lat; only two dimensions
++ Array *lon = new Array("longitude", new Float64("longitude"));
++ lon->append_dim(lon_size);
++
++ vector<double> data(max(lon_size, lat_size)); // (re)use this for both lon and lat
++
++ // Compute values
++ // u = a*x + b*y
++ // v = c*x + d*y
++ // u,v --> x,y --> lon,lat
++ // The constants a, b, c, d are given by the 1, 2, 4, and 5 entries in the geotransform array.
++
++ if (m_geo_transform_coef[2] != 0)
++ throw Error("The transformed data's Geographic projection should not be rotated.");
++ for (int j = 0; j < lon_size; ++j) {
++ data[j] = m_geo_transform_coef[1] * j + m_geo_transform_coef[0];
++ }
++
++ // load (copy) values
++ lon->set_value(&data[0], lon_size);
++ // Set the map
++ g->add_var_nocopy(lon, maps);
++
++ // Now do the latitude map
++ Array *lat = new Array("latitude", new Float64("latitude"));
++ lat->append_dim(lat_size);
++
++ if (m_geo_transform_coef[4] != 0)
++ throw Error("The transformed data's Geographic projection should not be rotated.");
++ for (int k = 0; k < lat_size; ++k) {
++ data[k] = m_geo_transform_coef[5] * k + m_geo_transform_coef[3];
++ }
++
++ lat->set_value(&data[0], lat_size);
++ g->add_var_nocopy(lat, maps);
++
++ return g;
++}
++
++/************************************************************************/
++/* SetNativeCRS() */
++/************************************************************************/
++
++/**
++ * \brief Set the Native CRS for a GOES dataset.
++ *
++ * The method will set the CRS for a GOES dataset as an native CRS.
++ *
++ * Since the original GOES data adopt satellite CRS to recored its value,
++ * like MODIS swath data, each data point has its corresponding latitude
++ * and longitude value, those coordinates could be fetched in another two fields.
++ *
++ * The native CRS for GOES Imager and Sounder data is assigned to EPSG:4326 if
++ * both the latitude and longitude are existed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetNativeCRS()
++{
++ DBG(cerr << "In SetNativeCRS" << endl);
++
++ mo_NativeCRS.SetWellKnownGeogCS("WGS84");
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetGeoTransform() */
++/************************************************************************/
++
++/**
++ * \brief Set the affine GeoTransform matrix for a GOES data.
++ *
++ * The method will set a GeoTransform matrix for a GOES data
++ * by parsing the coordinates values existed in longitude and latitude field.
++ *
++ * The CRS for the bounding box is EPSG:4326.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetGeoTransform()
++{
++ DBG(cerr << "In SetGeoTransform" << endl);
++
++ // TODO Look at this; is this correct
++ // Assume the array is two dimensional
++ Array::Dim_iter i = m_src->dim_begin();
++#if 0
++ // ORIGINAL code; maybe wrong
++ int nXSize = m_src->dimension_size(i, true);
++ int nYSize = m_src->dimension_size(i + 1, true);
++#endif
++ // Data are in row-major order, so the first dim is the Y-axis value
++ int nYSize = m_src->dimension_size(i, true);
++ int nXSize = m_src->dimension_size(i + 1, true);
++
++ mi_SrcImageXSize = nXSize;
++ mi_SrcImageYSize = nYSize;
++
++ SetGeoBBoxAndGCPs(nXSize, nYSize);
++
++ double resX, resY;
++ if (mdSrcGeoMinX > mdSrcGeoMaxX && mdSrcGeoMinX > 0 && mdSrcGeoMaxX < 0)
++ resX = (360 + mdSrcGeoMaxX - mdSrcGeoMinX) / (nXSize - 1);
++ else
++ resX = (mdSrcGeoMaxX - mdSrcGeoMinX) / (nXSize - 1);
++
++ resY = (mdSrcGeoMaxY - mdSrcGeoMinY) / (nYSize - 1);
++
++ double res = MIN(resX, resY);
++
++ if (mdSrcGeoMinX > mdSrcGeoMaxX && mdSrcGeoMinX > 0 && mdSrcGeoMaxX < 0)
++ mi_RectifiedImageXSize = (int) ((360 + mdSrcGeoMaxX - mdSrcGeoMinX) / res) + 1;
++ else
++ mi_RectifiedImageXSize = (int) ((mdSrcGeoMaxX - mdSrcGeoMinX) / res) + 1;
++
++ mi_RectifiedImageYSize = (int) fabs((mdSrcGeoMaxY - mdSrcGeoMinY) / res) + 1;
++
++ DBG(cerr << "Source image size: " << nXSize << ", " << nYSize << endl);
++ DBG(cerr << "Rectified image size: " << mi_RectifiedImageXSize << ", " << mi_RectifiedImageYSize << endl);
++
++ md_Geotransform[0] = mdSrcGeoMinX;
++ md_Geotransform[1] = res;
++ md_Geotransform[2] = 0;
++ md_Geotransform[3] = mdSrcGeoMaxY;
++ md_Geotransform[4] = 0;
++ md_Geotransform[5] = -res;
++ mb_GeoTransformSet = TRUE;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetGeoBBoxAndGCPs() */
++/************************************************************************/
++
++/**
++ * \brief Set the native geographical bounding box and GCP array for a GOES data.
++ *
++ * The method will set the native geographical bounding box
++ * by comparing the coordinates values existed in longitude and latitude field.
++ *
++ * @param poVDS The GDAL dataset returned by calling GDALOpen() method.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++void DAP_Dataset::SetGeoBBoxAndGCPs(int nXSize, int nYSize)
++{
++ DBG(cerr << "In SetGeoBBoxAndGCPs" << endl);
++
++ // reuse the Dim_iter for both lat and lon arrays
++ Array::Dim_iter i = m_lat->dim_begin();
++ int nLatXSize = m_lat->dimension_size(i, true);
++ int nLatYSize = m_lat->dimension_size(i + 1, true);
++ i = m_lon->dim_begin();
++ int nLonXSize = m_lon->dimension_size(i, true);
++ int nLonYSize = m_lon->dimension_size(i + 1, true);
++
++ if (nXSize != nLatXSize || nLatXSize != nLonXSize || nYSize != nLatYSize || nLatYSize != nLonYSize)
++ throw Error("The size of latitude/longitude and data field does not match.");
++
++#if 0
++ /*
++ * Re-sample Standards:
++ * Height | Width
++ * (0, 500) every other one pixel
++ * [500, 1000) every other two pixels
++ * [1000,1500) every other three pixels
++ * [1500,2000) every other four pixels
++ * ... ...
++ */
++
++ int xSpace = 1;
++ int ySpace = 1;
++ //setResampleStandard(poVDS, xSpace, ySpace);
++
++ // TODO understand how GMU picked this value.
++ // xSpace and ySpace are the stride values for sampling in
++ // the x and y dimensions.
++ const int RESAMPLE_STANDARD = 500;
++
++ xSpace = int(nXSize / RESAMPLE_STANDARD) + 2;
++ ySpace = int(nYSize / RESAMPLE_STANDARD) + 2;
++#endif
++
++ m_lat->read();
++ m_lon->read();
++ double *dataLat = extract_double_array(m_lat);
++ double *dataLon = extract_double_array(m_lon);
++
++ DBG(cerr << "Past lat/lon data read" << endl);
++
++ try {
++
++ mdSrcGeoMinX = 360;
++ mdSrcGeoMaxX = -360;
++ mdSrcGeoMinY = 90;
++ mdSrcGeoMaxY = -90;
++
++ // Sample every other row and column
++ int xSpace = 2;
++ int ySpace = 2;
++
++ int nGCPs = 0;
++ GDAL_GCP gdalCGP;
++
++ for (int iLine = 0; iLine < nYSize - ySpace; iLine += ySpace) {
++ for (int iPixel = 0; iPixel < nXSize - xSpace; iPixel += xSpace) {
++ double x = *(dataLon + (iLine * nYSize) + iPixel);
++ double y = *(dataLat + (iLine * nYSize) + iPixel);
++
++ if (isValidLongitude(x) && isValidLatitude(y)) {
++ char pChr[64];
++ snprintf(pChr, 64, "%d", ++nGCPs);
++ GDALInitGCPs(1, &gdalCGP);
++ gdalCGP.pszId = strdup(pChr);
++ gdalCGP.pszInfo = strdup("");
++ gdalCGP.dfGCPLine = iLine;
++ gdalCGP.dfGCPPixel = iPixel;
++ gdalCGP.dfGCPX = x;
++ gdalCGP.dfGCPY = y;
++
++ DBG2(cerr << "iLine, iPixel: " << iLine << ", " << iPixel << " --> x,y: " << x << ", " << y << endl);
++
++ gdalCGP.dfGCPZ = 0;
++ m_gdalGCPs.push_back(gdalCGP);
++
++ mdSrcGeoMinX = MIN(mdSrcGeoMinX, gdalCGP.dfGCPX);
++ mdSrcGeoMaxX = MAX(mdSrcGeoMaxX, gdalCGP.dfGCPX);
++ mdSrcGeoMinY = MIN(mdSrcGeoMinY, gdalCGP.dfGCPY);
++ mdSrcGeoMaxY = MAX(mdSrcGeoMaxY, gdalCGP.dfGCPY);
++ }
++ }
++ }
++ }
++ catch (...) {
++ delete[] dataLat;
++ delete[] dataLon;
++ throw;
++ }
++
++ delete[] dataLat;
++ delete[] dataLon;
++
++ DBG(cerr << "Leaving SetGeoBBoxAndGCPs" << endl);
++}
++
++/************************************************************************/
++/* SetGDALDataset() */
++/************************************************************************/
++
++/**
++ * \brief Make a 'memory' dataset with one band
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetGDALDataset(const int isSimple)
++{
++ DBG(cerr << "In SetGDALDataset" << endl);
++
++ // NB: mi_RectifiedImageXSize & Y are set in SetGeoTransform()
++ GDALDataType eBandType = GDT_Float64;
++ // VRT, which was used in the original sample code, is not supported in this context, so I used MEM
++ GDALDriverH poDriver = GDALGetDriverByName("MEM");
++ if (!poDriver) {
++ throw Error("Failed to get MEM driver (" + string(CPLGetLastErrorMsg()) + ").");
++ }
++
++ GDALDataset* satDataSet = (GDALDataset*) GDALCreate(poDriver, "", mi_RectifiedImageXSize, mi_RectifiedImageYSize,
++ 1, eBandType, NULL);
++ if (!satDataSet) {
++ GDALClose(poDriver);
++ throw Error("Failed to create MEM dataSet (" + string(CPLGetLastErrorMsg()) + ").");
++ }
++
++ GDALRasterBand *poBand = satDataSet->GetRasterBand(1);
++ poBand->SetNoDataValue(md_MissingValue);
++
++ m_src->read();
++ double *data = extract_double_array(m_src);
++ if (CE_None != poBand->RasterIO(GF_Write, 0, 0, mi_RectifiedImageXSize, mi_RectifiedImageYSize, data,
++ mi_SrcImageXSize, mi_SrcImageYSize, eBandType, 0, 0)) {
++ GDALClose((GDALDatasetH) satDataSet);
++ throw Error("Failed to set satellite data band to MEM DataSet (" + string(CPLGetLastErrorMsg()) + ").");
++ }
++ delete[] data;
++
++ //set GCPs for this VRTDataset
++ if (CE_None != SetGCPGeoRef4VRTDataset(satDataSet)) {
++ GDALClose((GDALDatasetH) satDataSet);
++ throw Error("Could not georeference the virtual dataset (" + string(CPLGetLastErrorMsg()) + ").");
++ }
++
++ DBG(cerr << "satDataSet: " << satDataSet << endl);
++
++ maptr_DS.reset(satDataSet);
++
++ if (isSimple)
++ return CE_None;
++
++ return RectifyGOESDataSet();
++}
++
++/************************************************************************/
++/* SetGCPGeoRef4VRTDataset() */
++/************************************************************************/
++
++/**
++ * \brief Set the GCP array for the VRT dataset.
++ *
++ * This method is used to set the GCP array to created VRT dataset based on GDAL
++ * method SetGCPs().
++ *
++ * @param poVDS The VRT dataset.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetGCPGeoRef4VRTDataset(GDALDataset* poVDS)
++{
++ char* psTargetSRS;
++ mo_NativeCRS.exportToWkt(&psTargetSRS);
++
++#if (__GNUC__ >=4 && __GNUC_MINOR__ > 1)
++ if (CE_None != poVDS->SetGCPs(m_gdalGCPs.size(), (GDAL_GCP*) (m_gdalGCPs.data()), psTargetSRS)) {
++ OGRFree(psTargetSRS);
++ throw Error("Failed to set GCPs.");
++ }
++#else
++ {
++ if(CE_None!=poVDS->SetGCPs(m_gdalGCPs.size(), (GDAL_GCP*)&m_gdalGCPs[0], psTargetSRS))
++ {
++ OGRFree( psTargetSRS );
++ throw Error("Failed to set GCPs.");
++ }
++ }
++#endif
++
++ OGRFree(psTargetSRS);
++
++ return CE_None;
++}
++#if 0
++/************************************************************************/
++/* SetMetaDataList() */
++/************************************************************************/
++
++/**
++ * \brief Set the metadata list for this coverage.
++ *
++ * The method will set the metadata list for the coverage based on its
++ * corresponding GDALDataset object.
++ *
++ * @param hSrc the GDALDataset object corresponding to coverage.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetMetaDataList(GDALDataset* hSrcDS)
++{
++ // TODO Remove
++#if 0
++ mv_MetaDataList.push_back("Product_Description=The data was created by GMU WCS from NOAA GOES satellite data.");
++ mv_MetaDataList.push_back("unit=GVAR");
++ mv_MetaDataList.push_back("FillValue=0");
++ ms_FieldQuantityDef = "GVAR";
++ ms_AllowRanges = "0 65535";
++ ms_CoveragePlatform = "GOES-11";
++ ms_CoverageInstrument = "GOES-11";
++ ms_CoverageSensor = "Imager";
++#endif
++
++ return CE_None;
++}
++#endif
++/************************************************************************/
++/* GetGeoMinMax() */
++/************************************************************************/
++
++/**
++ * \brief Get the min/max coordinates of laitutude and longitude.
++ *
++ * The method will fetch the min/max coordinates of laitutude and longitude.
++ *
++ * @param geoMinMax an existing four double buffer into which the
++ * native geographical bounding box values will be placed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::GetGeoMinMax(double geoMinMax[])
++{
++ if (!mb_GeoTransformSet)
++ return CE_Failure;
++
++ geoMinMax[0] = mdSrcGeoMinX;
++ geoMinMax[2] = mdSrcGeoMinY;
++ geoMinMax[1] = mdSrcGeoMaxX;
++ geoMinMax[3] = mdSrcGeoMaxY;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* RectifyGOESDataSet() */
++/************************************************************************/
++
++/**
++ * \brief Convert the GOES dataset from satellite CRS project to grid CRS.
++ *
++ * The method will convert the GOES dataset from satellite CRS project to
++ * grid CRS based on GDAL API GDALReprojectImage;
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::RectifyGOESDataSet()
++{
++ DBG(cerr << "In RectifyGOESDataSet" << endl);
++
++ char *pszDstWKT;
++ mo_NativeCRS.exportToWkt(&pszDstWKT);
++
++ GDALDriverH poDriver = GDALGetDriverByName("VRT"); // MEM
++ GDALDataset* rectDataSet = (GDALDataset*) GDALCreate(poDriver, "", mi_RectifiedImageXSize, mi_RectifiedImageYSize,
++ maptr_DS->GetRasterCount(), maptr_DS->GetRasterBand(1)->GetRasterDataType(), NULL);
++ if (NULL == rectDataSet) {
++ GDALClose(poDriver);
++ OGRFree(pszDstWKT);
++ throw Error("Failed to create \"MEM\" dataSet.");
++ }
++
++ rectDataSet->SetProjection(pszDstWKT);
++ rectDataSet->SetGeoTransform(md_Geotransform);
++
++ DBG(cerr << "rectDataSet: " << rectDataSet << endl);
++ DBG(cerr << "satDataSet: " << maptr_DS.get() << endl);
++
++ // FIXME Magic value of 0.125
++ if (CE_None != GDALReprojectImage(maptr_DS.get(), NULL, rectDataSet, pszDstWKT,
++ GRA_Lanczos /*GRA_NearestNeighbour*/, 0, 0.0/*0.125*/, NULL, NULL, NULL)) {
++ GDALClose(rectDataSet);
++ GDALClose(poDriver);
++ OGRFree(pszDstWKT);
++ throw Error("Failed to re-project satellite data from GCP CRS to geographical CRS.");
++ }
++
++ OGRFree(pszDstWKT);
++ GDALClose(maptr_DS.release());
++
++ maptr_DS.reset(rectDataSet);
++
++ DBG(cerr << "Leaving RectifyGOESDataSet" << endl);
++
++ return CE_None;
++}
++
++} // namespace libdap
+diff -Nur bes-3.12.0/functions.orig/swath2grid/DAP_Dataset.h bes-3.12.0/functions/swath2grid/DAP_Dataset.h
+--- bes-3.12.0/functions.orig/swath2grid/DAP_Dataset.h 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/DAP_Dataset.h 2014-03-03 15:47:38.050232928 +0100
+@@ -0,0 +1,142 @@
++
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2012 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++#ifndef DAP_DATASET_H_
++#define DAP_DATASET_H_
++
++#include <string>
++#include "AbstractDataset.h"
++#include "wcsUtil.h"
++
++using namespace std;
++
++namespace libdap {
++
++class Array;
++class Grid;
++
++/************************************************************************/
++/* ==================================================================== */
++/* DAP_Dataset */
++/* ==================================================================== */
++/************************************************************************/
++
++//! DAP_Dataset is a subclass of AbstractDataset, used to process NOAA GOES data.
++/**
++ * \class DAP_Dataset "DAP_Dataset.h"
++ *
++ * GOES satellites provide the kind of continuous monitoring necessary for
++ * intensive data analysis. They circle the Earth in a geosynchronous orbit,
++ * which means they orbit the equatorial plane of the Earth at a speed
++ * matching the Earth's rotation. This allows them to hover continuously
++ * over one position on the surface. The geosynchronous plane is about
++ * 35,800 km (22,300 miles) above the Earth, high enough to allow the
++ * satellites a full-disc view of the Earth. Because they stay above a
++ * fixed spot on the surface, they provide a constant vigil for the atmospheric
++ * "triggers" for severe weather conditions such as tornadoes, flash floods,
++ * hail storms, and hurricanes. When these conditions develop the GOES
++ * satellites are able to monitor storm development and track their movements.
++ *
++ * GOES satellite imagery is also used to estimate rainfall during
++ * the thunderstorms and hurricanes for flash flood warnings, as well
++ * as estimates snowfall accumulations and overall extent of snow cover.
++ * Such data help meteorologists issue winter storm warnings and spring
++ * snow melt advisories. Satellite sensors also detect ice fields and map
++ * the movements of sea and lake ice.
++ *
++ * For more inforamtion about NOAA GOES data, please access
++ * <a href=http://www.oso.noaa.gov/GOES/>http://www.oso.noaa.gov/GOES/</a>
++ *
++ * DAP_Dataset is a subclass of AbstractDataset, which is used to
++ * process GOES Imager and Sounder products.
++ */
++
++class DAP_Dataset : public AbstractDataset {
++protected:
++ string m_ncLatDataSetName;
++ string m_ncLonDataSetName;
++ string m_ncCoverageIDName;
++
++ // Instead of using names and opening files with GDAL,
++ // store pointers to Arrays read by the underlying DAP
++ // server constraint evaluator.
++ Array *m_src;
++ Array *m_lat;
++ Array *m_lon;
++
++ int mi_RectifiedImageXSize;
++ int mi_RectifiedImageYSize;
++ int mi_SrcImageXSize;
++ int mi_SrcImageYSize;
++
++ double mb_LatLonBBox[4];
++ double mdSrcGeoMinX;
++ double mdSrcGeoMinY;
++ double mdSrcGeoMaxX;
++ double mdSrcGeoMaxY;
++
++ // This is not set until GetDAPArray() is called.
++ double m_geo_transform_coef[6];
++
++ vector<GDAL_GCP> m_gdalGCPs;
++
++public:
++ CPLErr SetGCPGeoRef4VRTDataset(GDALDataset*);
++ void SetGeoBBoxAndGCPs(int xSize, int ySize);
++ CPLErr RectifyGOESDataSet();
++ CPLErr setResampleStandard(GDALDataset* hSrcDS, int& xRSValue, int& yRSValue);
++
++ int isValidLatitude(const double &lat)
++ {
++ return (lat >= -90 && lat <= 90);
++ }
++ int isValidLongitude(const double &lon)
++ {
++ return (lon >= -180 && lon <= 180);
++ }
++
++ virtual CPLErr SetGeoTransform();
++#if 0
++ virtual CPLErr SetMetaDataList(GDALDataset* hSrcDS); //TODO Remove
++#endif
++ virtual CPLErr SetNativeCRS();
++ virtual CPLErr SetGDALDataset(const int isSimple = 0);
++ virtual CPLErr InitialDataset(const int isSimple = 0);
++ virtual CPLErr GetGeoMinMax(double geoMinMax[]);
++
++public:
++ DAP_Dataset();
++ DAP_Dataset(const string& id, vector<int> &rBandList);
++
++ // Added jhrg 11/23/12
++ DAP_Dataset(Array *src, Array *lat, Array *lon);
++ Array *GetDAPArray();
++ Grid *GetDAPGrid();
++
++ virtual ~DAP_Dataset();
++};
++
++} // namespace libdap
++#endif /* DAP_DATASET_H_ */
+diff -Nur bes-3.12.0/functions.orig/swath2grid/Makefile.am bes-3.12.0/functions/swath2grid/Makefile.am
+--- bes-3.12.0/functions.orig/swath2grid/Makefile.am 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/Makefile.am 2014-03-03 15:47:38.056899595 +0100
+@@ -0,0 +1,106 @@
++
++# Build libswath2grid, part of libdap.
++
++AUTOMAKE_OPTIONS = foreign
++
++AM_CPPFLAGS = -I$(top_srcdir)/GNU -I$(top_srcdir) -I$(top_srcdir)/tests -I$(top_srcdir)/dispatch $(XML2_CFLAGS) $(CURL_CFLAGS)
++AM_LDADD =
++
++if CPPUNIT
++AM_CPPFLAGS += $(CPPUNIT_CFLAGS)
++AM_LDADD += $(CPPUNIT_LIBS)
++endif
++
++# These are not used by automake but are often useful for certain types of
++# debugging. The best way to use these is to run configure as:
++# export CXXFLAGS='...'; ./configure --disable-shared
++# the --disable-shared is not required, but it seems to help with debuggers.
++CXXFLAGS_DEBUG = -g3 -O0 -Wall -W -Wcast-align -Werror
++TEST_COV_FLAGS = -ftest-coverage -fprofile-arcs
++
++# SUBDIRS =
++# DIST_SUBDIRS =
++
++# This determines what gets built by make check
++check_PROGRAMS = $(UNIT_TESTS)
++
++# This determines what gets run by 'make check.'
++# Now (12/20/12) this fails; don't run until it works.
++# TESTS = $(UNIT_TESTS)
++
++
++noinst_LTLIBRARIES = libswath2grid.la
++
++libswath2grid_la_SOURCES = $(SRCS) $(HDRS)
++libswath2grid_la_CPPFLAGS = $(GDAL_CFLAGS) $(XML2_CFLAGS) $(DAP_SERVER_CFLAGS) $(DAP_CLIENT_CFLAGS) -I$(top_srcdir)/dispatch
++libswath2grid_la_LDFLAGS =
++libswath2grid_la_LIBADD = $(GDAL_LDFLAGS) $(DAP_SERVER_LIBS) $(DAP_CLIENT_LIBS)
++
++SRCS = AbstractDataset.cpp wcs_error.cpp \
++BoundingBox.cpp wcsUtil.cpp DAP_Dataset.cpp reproj_functions.cc
++
++# NC_GOES_Dataset.cpp NC_GOES_Dataset.h
++
++HDRS = AbstractDataset.h wcs_error.h \
++BoundingBox.h wcsUtil.h DAP_Dataset.h reproj_functions.h
++
++if CPPUNIT
++UNIT_TESTS = s2gTest
++
++else
++UNIT_TESTS =
++
++check-local:
++ @echo ""
++ @echo "**********************************************************"
++ @echo "You must have cppunit 1.12.x or greater installed to run *"
++ @echo "check target in unit-tests directory *"
++ @echo "**********************************************************"
++ @echo ""
++endif
++
++s2gTest_SOURCES = s2gTest.cc
++s2gTest_CPPFLAGS = $(AM_CPPFLAGS) $(DAP_SERVER_CFLAGS) $(DAP_CLIENT_CFLAGS) $(GDAL_CFLAGS)
++s2gTest_LDADD = -ltest-types libswath2grid.la $(AM_LDADD) $(DAP_SERVER_LIBS) $(DAP_CLIENT_LIBS) $(GDAL_LDFLAGS)
++
++if LIBDAP
++check-dap:
++ @echo ""
++ @echo "**********************************************************"
++ @echo "USING DAP "
++ @echo "DAP_CLIENT_CFLAGS: " $(DAP_CLIENT_CFLAGS)
++ @echo "DAP_SERVER_CFLAGS: " $(DAP_SERVER_CFLAGS)
++ @echo "DAP_CLIENT_LIBS: " $(DAP_CLIENT_LIBS)
++ @echo "DAP_SERVER_LIBS: " $(DAP_SERVER_LIBS)
++ @echo "**********************************************************"
++ @echo ""
++else
++check-dap:
++ @echo ""
++ @echo "**********************************************************"
++ @echo " Unable to locate DAP libraries!"
++ @echo "**********************************************************"
++ @echo ""
++endif
++
++
++if GDAL_FOUND
++check-gdal:
++ @echo ""
++ @echo "**********************************************************"
++ @echo "Using gdal. "
++ @echo "GDAL_CFLAGS: " $(GDAL_CFLAGS)
++ @echo "GDAL_LDFLAGS: " $(GDAL_LDFLAGS)
++ @echo "**********************************************************"
++ @echo ""
++else
++check-gdal:
++ @echo ""
++ @echo "**********************************************************"
++ @echo "You must have gdal 12.15.12 or greater installed to run"
++ @echo "check target in unit-tests directory "
++ @echo "GDAL_VERSION: '$(GDAL_VERSION)'"
++ @echo "prefix: '$(prefix)'"
++ @echo "**********************************************************"
++ @echo ""
++endif
+diff -Nur bes-3.12.0/functions.orig/swath2grid/NC_GOES_Dataset.cpp bes-3.12.0/functions/swath2grid/NC_GOES_Dataset.cpp
+--- bes-3.12.0/functions.orig/swath2grid/NC_GOES_Dataset.cpp 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/NC_GOES_Dataset.cpp 2014-03-03 15:47:38.053566262 +0100
+@@ -0,0 +1,625 @@
++/******************************************************************************
++ * $Id: TRMM_Dataset.cpp 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: NC_GOES_Dataset implementation for NOAA GOES data
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 "NC_GOES_Dataset.h"
++
++using namespace std;
++
++#define GOES_TIME_DEBUG FALSE
++
++NC_GOES_Dataset::NC_GOES_Dataset()
++{
++}
++
++/************************************************************************/
++/* ~NC_GOES_Dataset() */
++/************************************************************************/
++
++/**
++ * \brief Destroy an open NC_GOES_Dataset object.
++ *
++ * This is the accepted method of closing a NC_GOES_Dataset dataset and
++ * deallocating all resources associated with it.
++ */
++
++NC_GOES_Dataset::~NC_GOES_Dataset()
++{
++}
++
++/************************************************************************/
++/* NC_GOES_Dataset() */
++/************************************************************************/
++
++/**
++ * \brief Create an NC_GOES_Dataset object.
++ *
++ * This is the accepted method of creating a NC_GOES_Dataset object and
++ * allocating all resources associated with it.
++ *
++ * @param id The coverage identifier.
++ *
++ * @param rBandList The field list selected for this coverage. For TRMM
++ * daily data, the user could specify multiple days range in request.
++ * Each day is seemed as one field.
++ *
++ * @return A NC_GOES_Dataset object.
++ */
++
++NC_GOES_Dataset::NC_GOES_Dataset(const string& id, vector<int> &rBandList) :
++ AbstractDataset(id, rBandList)
++{
++ md_MissingValue = 0;
++ mb_GeoTransformSet = FALSE;
++}
++
++/************************************************************************/
++/* InitialDataset() */
++/************************************************************************/
++
++/**
++ * \brief Initialize the GOES dataset with NetCDF format.
++
++ * This method is the implementation for initializing a GOES dataset with NetCDF format.
++ * Within this method, SetNativeCRS(), SetGeoTransform() and SetGDALDataset()
++ * will be called to initialize an GOES dataset.
++ *
++ * @param isSimple the WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::InitialDataset(const int isSimple)
++{
++ vector<string> strSet;
++ unsigned int n = CsvburstCpp(ms_CoverageID, strSet, ':');
++ if (n != 4)
++ {
++ SetWCS_ErrorLocator("NC_GOES_Dataset::InitialDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Incorrect coverage ID.");
++ return CE_Failure;
++ }
++
++ ms_DataTypeName = strSet[0] + ":" + strSet[1];
++ ms_SrcFilename = StrTrims(strSet[2], " \'\"");
++ ms_DatasetName = strSet[3];
++
++ m_ncLatDataSetName = "NETCDF:" + ms_SrcFilename + ":latitude";
++ m_ncLonDataSetName = "NETCDF:" + ms_SrcFilename + ":longitude";
++ m_ncCoverageIDName = strSet[1] + ":" + strSet[2] + ":" + strSet[3];
++
++ GDALDataset* pSrc = (GDALDataset*) GDALOpenShared(m_ncCoverageIDName.c_str(), GA_ReadOnly);
++ if (pSrc == NULL)
++ {
++ SetWCS_ErrorLocator("NC_GOES_Dataset::InitialDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to open file \"%s\".", ms_SrcFilename.c_str());
++ return CE_Failure;
++ }
++
++ ms_NativeFormat = GDALGetDriverShortName(pSrc->GetDriver());
++
++ //setmetalist
++ SetMetaDataList(pSrc);
++
++ //set noValue
++ unsigned int nBandCount = pSrc->GetRasterCount();
++ if (nBandCount < 1)
++ {
++ GDALClose(pSrc);
++ SetWCS_ErrorLocator("NC_GOES_Dataset::InitialDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "The GOES file does not contain any raster band.");
++ return CE_Failure;
++ }
++
++ maptr_DS.reset(pSrc);
++
++ //set moNativeCRS and mGeoTransform
++ if (CE_None != SetNativeCRS() ||
++ CE_None != SetGeoTransform() ||
++ CE_None != SetGDALDataset(isSimple))
++ {
++ GDALClose(maptr_DS.release());
++ return CE_Failure;
++ }
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetNativeCRS() */
++/************************************************************************/
++
++/**
++ * \brief Set the Native CRS for a GOES dataset.
++ *
++ * The method will set the CRS for a GOES dataset as an native CRS.
++ *
++ * Since the original GOES data adopt satellite CRS to recored its value,
++ * like MODIS swath data, each data point has its corresponding latitude
++ * and longitude value, those coordinates could be fetched in another two fields.
++ *
++ * The native CRS for GOES Imager and Sounder data is assigned to EPSG:4326 if
++ * both the latitude and longitude are existed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetNativeCRS()
++{
++ if (CE_None == AbstractDataset::SetNativeCRS())
++ return CE_None;
++
++ GDALDataset* hLatDS = (GDALDataset*) GDALOpen(m_ncLatDataSetName.c_str(), GA_ReadOnly);
++ GDALDataset* hLonDS = (GDALDataset*) GDALOpen(m_ncLonDataSetName.c_str(), GA_ReadOnly);
++
++ if(hLatDS == NULL) {
++ m_ncLatDataSetName = "NETCDF:\"" + ms_SrcFilename + "\":lat";
++ hLatDS = (GDALDataset*) GDALOpen(m_ncLatDataSetName.c_str(), GA_ReadOnly);
++ }
++
++ if(hLonDS == NULL) {
++ m_ncLonDataSetName = "NETCDF:\"" + ms_SrcFilename + "\":lon";
++ hLonDS = (GDALDataset*) GDALOpen(m_ncLonDataSetName.c_str(), GA_ReadOnly);
++ }
++
++ if (hLatDS == NULL || hLonDS == NULL)
++ {
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetNativeCRS()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to open latitude/longitude sub-dataset.");
++ return CE_Failure;
++ }
++
++ mo_NativeCRS.SetWellKnownGeogCS("WGS84");
++
++ GDALClose(hLatDS);
++ GDALClose(hLonDS);
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetGeoTransform() */
++/************************************************************************/
++
++/**
++ * \brief Set the affine GeoTransform matrix for a GOES data.
++ *
++ * The method will set a GeoTransform matrix for a GOES data
++ * by parsing the coordinates values existed in longitude and latitude field.
++ *
++ * The CRS for the bounding box is EPSG:4326.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetGeoTransform()
++{
++ if (CE_None == AbstractDataset::SetGeoTransform())
++ return CE_None;
++
++ if (CE_None != SetGeoBBoxAndGCPs(maptr_DS.get()))
++ return CE_Failure;
++
++ double resX, resY;
++ if (mdSrcGeoMinX > mdSrcGeoMaxX && mdSrcGeoMinX > 0 && mdSrcGeoMaxX < 0)
++ resX = (360 + mdSrcGeoMaxX - mdSrcGeoMinX) / (maptr_DS->GetRasterXSize() - 1);
++ else
++ resX = (mdSrcGeoMaxX - mdSrcGeoMinX) / (maptr_DS->GetRasterXSize() - 1);
++
++ resY = (mdSrcGeoMaxY - mdSrcGeoMinY) / (maptr_DS->GetRasterYSize() - 1);
++
++ double res = MIN(resX,resY);
++
++ if (mdSrcGeoMinX > mdSrcGeoMaxX && mdSrcGeoMinX > 0 && mdSrcGeoMaxX < 0)
++ mi_RectifiedImageXSize = (int)((360 + mdSrcGeoMaxX - mdSrcGeoMinX) / res) + 1;
++ else
++ mi_RectifiedImageXSize = (int)((mdSrcGeoMaxX - mdSrcGeoMinX) / res) + 1;
++
++ mi_RectifiedImageYSize = (int)fabs((mdSrcGeoMaxY - mdSrcGeoMinY) / res) + 1;
++
++ md_Geotransform[0] = mdSrcGeoMinX;
++ md_Geotransform[1] = res;
++ md_Geotransform[2] = 0;
++ md_Geotransform[3] = mdSrcGeoMaxY;
++ md_Geotransform[4] = 0;
++ md_Geotransform[5] = -res;
++ mb_GeoTransformSet = TRUE;
++
++ return CE_None;
++}
++
++CPLErr NC_GOES_Dataset::setResampleStandard(GDALDataset* hSrcDS, int& xRSValue, int& yRSValue)
++{
++ static int RESAMPLE_STANDARD = 500;
++ int nXSize = hSrcDS->GetRasterXSize();
++ int nYSize = hSrcDS->GetRasterYSize();
++
++ xRSValue = int(nXSize / RESAMPLE_STANDARD) + 2;
++ yRSValue = int(nYSize / RESAMPLE_STANDARD) + 2;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetGeoBBoxAndGCPs() */
++/************************************************************************/
++
++/**
++ * \brief Set the native geographical bounding box and GCP array for a GOES data.
++ *
++ * The method will set the native geographical bounding box
++ * by comparing the coordinates values existed in longitude and latitude field.
++ *
++ * @param poVDS The GDAL dataset returned by calling GDALOpen() method.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetGeoBBoxAndGCPs(GDALDataset* poVDS)
++{
++ GDALDataset* hLatDS = (GDALDataset*) GDALOpen(m_ncLatDataSetName.c_str(), GA_ReadOnly);
++ GDALDataset* hLonDS = (GDALDataset*) GDALOpen(m_ncLonDataSetName.c_str(), GA_ReadOnly);
++
++ int nXSize = poVDS->GetRasterXSize();
++ int nYSize = poVDS->GetRasterYSize();
++
++ mi_GoesSrcImageXSize = nXSize;
++ mi_GoesSrcImageYSize = nYSize;
++
++ int nLatXSize = hLatDS->GetRasterXSize();
++ int nLatYSize = hLatDS->GetRasterYSize();
++ int nLonXSize = hLonDS->GetRasterXSize();
++ int nLonYSize = hLonDS->GetRasterYSize();
++
++ if (nXSize != nLatXSize || nLatXSize != nLonXSize || nYSize != nLatYSize || nLatYSize != nLonYSize)
++ {
++ GDALClose(hLatDS);
++ GDALClose(hLonDS);
++
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetGeoBBoxAndGCPs()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "The size of latitude/longitude and data field does not match.");
++
++ return CE_Failure;
++ }
++
++ /*
++ * Re-sample Standards:
++ * Height | Width
++ * (0, 500) every other one pixel
++ * [500, 1000) every other two pixels
++ * [1000,1500) every other three pixels
++ * [1500,2000) every other four pixels
++ * ... ...
++ */
++
++ int xSpace = 1;
++ int ySpace = 1;
++ setResampleStandard(poVDS, xSpace, ySpace);
++
++ int nGCPs = 0;
++ GDAL_GCP gdalCGP;
++
++ GDALRasterBand *poBandLat = hLatDS->GetRasterBand(1);
++ GDALRasterBand *poBandLon = hLonDS->GetRasterBand(1);
++ GDALDataType eDT = poBandLat->GetRasterDataType();
++ void *dataLat = NULL;
++ void *dataLon = NULL;
++
++ mdSrcGeoMinX = 360;
++ mdSrcGeoMaxX = -360;
++ mdSrcGeoMinY = 90;
++ mdSrcGeoMaxY = -90;
++
++ switch (eDT)
++ {
++ case GDT_Float32: //For GOES Imager and Sounder data
++ {
++ dataLat = (float *) CPLMalloc(nXSize * sizeof(float));
++ dataLon = (float *) CPLMalloc(nXSize * sizeof(float));
++
++ for (int iLine = 0; iLine < nYSize; iLine += ySpace)
++ {
++ if (iLine >= nYSize)
++ iLine = nYSize - 1;
++
++ poBandLat->RasterIO(GF_Read, 0, iLine, nXSize, 1, dataLat, nXSize, 1, GDT_Float32, 0, 0);
++ poBandLon->RasterIO(GF_Read, 0, iLine, nXSize, 1, dataLon, nXSize, 1, GDT_Float32, 0, 0);
++
++ for (int iPixel = 0; iPixel < nXSize; iPixel += xSpace)
++ {
++ if(iPixel >= nXSize)
++ iPixel = nXSize - 1;
++ double x = *((float *) dataLon + iPixel);
++ double y = *((float *) dataLat + iPixel);
++ if (isValidLongitude(x) && isValidLatitude(y))
++ {
++ char pChr[64];
++ sprintf(pChr, "%d", ++nGCPs);
++ GDALInitGCPs(1, &gdalCGP);
++ gdalCGP.pszId = strdup(pChr);
++ gdalCGP.pszInfo = strdup("");
++ gdalCGP.dfGCPLine = iLine;
++ gdalCGP.dfGCPPixel = iPixel;
++ gdalCGP.dfGCPX = x;
++ gdalCGP.dfGCPY = y;
++ gdalCGP.dfGCPZ = 0;
++ m_gdalGCPs.push_back(gdalCGP);
++ mdSrcGeoMinX = MIN(mdSrcGeoMinX,gdalCGP.dfGCPX );
++ mdSrcGeoMaxX = MAX(mdSrcGeoMaxX,gdalCGP.dfGCPX);
++ mdSrcGeoMinY = MIN(mdSrcGeoMinY,gdalCGP.dfGCPY);
++ mdSrcGeoMaxY = MAX(mdSrcGeoMaxY,gdalCGP.dfGCPY);
++ }
++ }
++ }
++
++ VSIFree((float *) dataLat);
++ VSIFree((float *) dataLon);
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ GDALClose(hLatDS);
++ GDALClose(hLonDS);
++
++ return CE_None;
++}
++
++
++/************************************************************************/
++/* SetGDALDataset() */
++/************************************************************************/
++
++/**
++ * \brief Set the GDALDataset object to GOES Imager and Sounder dataset.
++ *
++ * This method is used to set the GOES Imager and Sounder dataset based on GDAL
++ * class VRTDataset.
++ *
++ * @param isSimple the WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetGDALDataset(const int isSimple)
++{
++ for(int i = 1; i <= maptr_DS->GetRasterCount(); ++i)
++ mv_BandList.push_back(i);
++
++ VRTDataset *poVDS = (VRTDataset *)VRTCreate(mi_RectifiedImageXSize, mi_RectifiedImageYSize);
++ if (poVDS == NULL)
++ {
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetGDALDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to create VRT DataSet.");
++ return CE_Failure;
++ }
++
++ VRTSourcedRasterBand *poVRTBand = NULL;
++ GDALRasterBand *poSrcBand = NULL;
++ GDALDataType eBandType;
++ for (unsigned int i = 0; i < mv_BandList.size(); i++)
++ {
++ poSrcBand = maptr_DS->GetRasterBand(mv_BandList[i]);
++ eBandType = poSrcBand->GetRasterDataType();
++ poVDS->AddBand(eBandType, NULL);
++ poVRTBand = (VRTSourcedRasterBand *) poVDS->GetRasterBand(i + 1);
++ poVRTBand->SetNoDataValue(md_MissingValue);
++
++ if (CE_None != poVRTBand->AddSimpleSource(poSrcBand, 0, 0,
++ mi_RectifiedImageXSize, mi_RectifiedImageYSize, 0, 0,
++ mi_RectifiedImageXSize, mi_RectifiedImageYSize, NULL, md_MissingValue))
++ {
++ GDALClose((GDALDatasetH) poVDS);
++ SetWCS_ErrorLocator("NC_GOES_Dataset::setGDALDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Add Simple Source into VRT DataSet.");
++ return CE_Failure;
++ }
++ }
++
++ //set GCPs for this VRTDataset
++ if (CE_None != SetGCPGeoRef4VRTDataset(poVDS))
++ {
++ GDALClose((GDALDatasetH) poVDS);
++ return CE_Failure;
++ }
++
++ GDALClose(maptr_DS.release());
++ maptr_DS.reset(poVDS);
++
++ if (isSimple)
++ return CE_None;
++
++ return RectifyGOESDataSet();
++}
++
++/************************************************************************/
++/* SetGCPGeoRef4VRTDataset() */
++/************************************************************************/
++
++/**
++ * \brief Set the GCP array for the VRT dataset.
++ *
++ * This method is used to set the GCP array to created VRT dataset based on GDAL
++ * method SetGCPs().
++ *
++ * @param poVDS The VRT dataset.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetGCPGeoRef4VRTDataset(GDALDataset* poVDS)
++{
++ char* psTargetSRS;
++ mo_NativeCRS.exportToWkt(&psTargetSRS);
++
++#if (__GNUC__ >=4 && __GNUC_MINOR__ > 1)
++ if (CE_None != poVDS->SetGCPs(m_gdalGCPs.size(), (GDAL_GCP*) (m_gdalGCPs.data()), psTargetSRS))
++ {
++ OGRFree(psTargetSRS);
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetGCPGeoRef4VRTDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to set GCPs.");
++
++ return CE_Failure;
++ }
++#else
++ {
++ if(CE_None!=poVDS->SetGCPs(m_gdalGCPs.size(), (GDAL_GCP*)&m_gdalGCPs[0], psTargetSRS))
++ {
++ OGRFree( psTargetSRS );
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetGCPGeoRef4VRTDataset()");
++ WCS_Error(CE_Failure,OGC_WCS_NoApplicableCode,"Failed to set GCPs.");
++
++ return CE_Failure;
++ }
++ }
++#endif
++
++ OGRFree(psTargetSRS);
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetMetaDataList() */
++/************************************************************************/
++
++/**
++ * \brief Set the metadata list for this coverage.
++ *
++ * The method will set the metadata list for the coverage based on its
++ * corresponding GDALDataset object.
++ *
++ * @param hSrc the GDALDataset object corresponding to coverage.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetMetaDataList(GDALDataset* hSrcDS)
++{
++ mv_MetaDataList.push_back("Product_Description=The data was created by GMU WCS from NOAA GOES satellite data.");
++ mv_MetaDataList.push_back("unit=GVAR");
++ mv_MetaDataList.push_back("FillValue=0");
++ ms_FieldQuantityDef = "GVAR";
++ ms_AllowRanges = "0 65535";
++ ms_CoveragePlatform = "GOES-11";
++ ms_CoverageInstrument = "GOES-11";
++ ms_CoverageSensor = "Imager";
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetGeoMinMax() */
++/************************************************************************/
++
++/**
++ * \brief Get the min/max coordinates of laitutude and longitude.
++ *
++ * The method will fetch the min/max coordinates of laitutude and longitude.
++ *
++ * @param geoMinMax an existing four double buffer into which the
++ * native geographical bounding box values will be placed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::GetGeoMinMax(double geoMinMax[])
++{
++ if (!mb_GeoTransformSet)
++ return CE_Failure;
++
++ geoMinMax[0] = mdSrcGeoMinX;
++ geoMinMax[2] = mdSrcGeoMinY;
++ geoMinMax[1] = mdSrcGeoMaxX;
++ geoMinMax[3] = mdSrcGeoMaxY;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetGeoMinMax() */
++/************************************************************************/
++
++/**
++ * \brief Convert the GOES dataset from satellite CRS project to grid CRS.
++ *
++ * The method will convert the GOES dataset from satellite CRS project to
++ * grid CRS based on GDAL API GDALReprojectImage;
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::RectifyGOESDataSet()
++{
++ char *pszDstWKT;
++ mo_NativeCRS.exportToWkt(&pszDstWKT);
++
++ GDALDriverH poDriver = GDALGetDriverByName("MEM");
++ GDALDataset* rectDataSet = (GDALDataset*) GDALCreate(poDriver, "", mi_RectifiedImageXSize,
++ mi_RectifiedImageYSize, maptr_DS->GetRasterCount(),
++ maptr_DS->GetRasterBand(1)->GetRasterDataType(), NULL);
++ if (NULL == rectDataSet)
++ {
++ GDALClose(poDriver);
++ OGRFree(pszDstWKT);
++ SetWCS_ErrorLocator("AbstractDataset::rectifyDataSet()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode,
++ "Failed to create \"MEM\" dataSet.");
++
++ return CE_Failure;
++ }
++
++ rectDataSet->SetProjection(pszDstWKT);
++ rectDataSet->SetGeoTransform(md_Geotransform);
++
++ if (CE_None != GDALReprojectImage(maptr_DS.get(), NULL, rectDataSet,
++ pszDstWKT, GRA_NearestNeighbour, 0, 0.125, NULL, NULL, NULL))
++ {
++ GDALClose(rectDataSet);
++ GDALClose(poDriver);
++ OGRFree(pszDstWKT);
++ SetWCS_ErrorLocator("AbstractDataset::RectifyDataSet()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode,
++ "Failed to re-project GOES data from satellite GCP CRS to geographical CRS.");
++
++ return CE_Failure;
++ }
++
++ OGRFree(pszDstWKT);
++ GDALClose(maptr_DS.release());
++
++ maptr_DS.reset(rectDataSet);
++
++ return CE_None;
++}
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/NC_GOES_Dataset.h bes-3.12.0/functions/swath2grid/NC_GOES_Dataset.h
+--- bes-3.12.0/functions.orig/swath2grid/NC_GOES_Dataset.h 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/NC_GOES_Dataset.h 2014-03-03 15:47:38.053566262 +0100
+@@ -0,0 +1,124 @@
++/******************************************************************************
++ * $Id: NC_GOES_Dataset.h 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: NC_GOES_Dataset class definition
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 NC_GOES_DATASET_H_
++#define NC_GOES_DATASET_H_
++
++#include <string>
++#include "AbstractDataset.h"
++#include "wcsUtil.h"
++
++using namespace std;
++
++/************************************************************************/
++/* ==================================================================== */
++/* NC_GOES_Dataset */
++/* ==================================================================== */
++/************************************************************************/
++
++//! NC_GOES_Dataset is a subclass of AbstractDataset, used to process NOAA GOES data.
++
++/**
++ * \class NC_GOES_Dataset "NC_GOES_Dataset.h"
++ *
++ * GOES satellites provide the kind of continuous monitoring necessary for
++ * intensive data analysis. They circle the Earth in a geosynchronous orbit,
++ * which means they orbit the equatorial plane of the Earth at a speed
++ * matching the Earth's rotation. This allows them to hover continuously
++ * over one position on the surface. The geosynchronous plane is about
++ * 35,800 km (22,300 miles) above the Earth, high enough to allow the
++ * satellites a full-disc view of the Earth. Because they stay above a
++ * fixed spot on the surface, they provide a constant vigil for the atmospheric
++ * "triggers" for severe weather conditions such as tornadoes, flash floods,
++ * hail storms, and hurricanes. When these conditions develop the GOES
++ * satellites are able to monitor storm development and track their movements.
++ *
++ * GOES satellite imagery is also used to estimate rainfall during
++ * the thunderstorms and hurricanes for flash flood warnings, as well
++ * as estimates snowfall accumulations and overall extent of snow cover.
++ * Such data help meteorologists issue winter storm warnings and spring
++ * snow melt advisories. Satellite sensors also detect ice fields and map
++ * the movements of sea and lake ice.
++ *
++ * For more inforamtion about NOAA GOES data, please access
++ * <a href=http://www.oso.noaa.gov/GOES/>http://www.oso.noaa.gov/GOES/</a>
++ *
++ * NC_GOES_Dataset is a subclass of AbstractDataset, which is used to
++ * process GOES Imager and Sounder products.
++ */
++
++class NC_GOES_Dataset : public AbstractDataset
++{
++protected:
++ string m_ncLatDataSetName;
++ string m_ncLonDataSetName;
++ string m_ncCoverageIDName;
++ int mi_RectifiedImageXSize;
++ int mi_RectifiedImageYSize;
++ int mi_GoesSrcImageXSize;
++ int mi_GoesSrcImageYSize;
++
++ double mb_LatLonBBox[4];
++ double mdSrcGeoMinX;
++ double mdSrcGeoMinY;
++ double mdSrcGeoMaxX;
++ double mdSrcGeoMaxY;
++
++ vector<GDAL_GCP> m_gdalGCPs;
++
++public:
++ CPLErr SetGCPGeoRef4VRTDataset(GDALDataset* );
++ CPLErr SetGeoBBoxAndGCPs(GDALDataset* hSrcDS);
++ CPLErr RectifyGOESDataSet();
++ CPLErr setResampleStandard(GDALDataset* hSrcDS, int& xRSValue, int& yRSValue);
++
++ int isValidLatitude(const double &lat)
++ {
++ return (lat >= -90 && lat <= 90);
++ }
++ int isValidLongitude(const double &lon)
++ {
++ return (lon >= -180 && lon <= 180);
++ }
++
++ virtual CPLErr SetGeoTransform();
++ virtual CPLErr SetMetaDataList(GDALDataset* hSrcDS);
++ virtual CPLErr SetNativeCRS();
++ virtual CPLErr SetGDALDataset(const int isSimple=0);
++ virtual CPLErr InitialDataset(const int isSimple=0);
++ virtual CPLErr GetGeoMinMax(double geoMinMax[]);
++
++public:
++ NC_GOES_Dataset();
++ NC_GOES_Dataset(const string& id, vector<int> &rBandList);
++ virtual ~NC_GOES_Dataset();
++};
++
++#endif /* NC_GOES_DATASET_H_ */
+diff -Nur bes-3.12.0/functions.orig/swath2grid/reproj_functions.cc bes-3.12.0/functions/swath2grid/reproj_functions.cc
+--- bes-3.12.0/functions.orig/swath2grid/reproj_functions.cc 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/reproj_functions.cc 2014-03-03 15:47:38.056899595 +0100
+@@ -0,0 +1,209 @@
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2002,2003 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++// (c) COPYRIGHT URI/MIT 1999
++// Please read the full copyright statement in the file COPYRIGHT_URI.
++//
++// Authors:
++// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
++
++
++// These functions are used by the CE evaluator
++//
++// 1/15/99 jhrg
++
++#include "config.h"
++
++#include <limits.h>
++
++#if 0
++#include <cstdlib> // used by strtod()
++#include <cerrno>
++#include <cmath>
++#endif
++#include <iostream>
++#if 0
++#include <vector>
++#include <algorithm>
++#endif
++
++// #include <gdal.h>
++// #include <gdal_priv.h>
++
++#define DODS_DEBUG
++
++#include "BaseType.h"
++
++#include "Str.h"
++#include "Array.h"
++#include "Grid.h"
++
++#include "Error.h"
++#include "debug.h"
++
++#include "DAP_Dataset.h"
++#include "reproj_functions.h"
++
++// We wrapped VC++ 6.x strtod() to account for a short coming
++// in that function in regards to "NaN". I don't know if this
++// still applies in more recent versions of that product.
++// ROM - 12/2007
++#ifdef WIN32
++#include <limits>
++double w32strtod(const char *, char **);
++#endif
++
++using namespace std;
++//using namespace libdap;
++
++namespace libdap {
++
++/**
++ * @todo The lat and lon arrays are passed in, but there's an assumption that the
++ * source data array and the two lat and lon arrays are the same shape. But the
++ * code does not actually test that.
++ *
++ * @todo Enable multiple bands paired with just the two lat/lon arrays? Not sure
++ * if that is a good idea...
++ */
++void function_swath2array(int argc, BaseType * argv[], DDS &, BaseType **btpp)
++{
++ DBG(cerr << "Entering function_swath2array..." << endl);
++
++ // Use the same documentation for both swath2array and swath2grid
++ string info = string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
++ + "<function name=\"swath2array\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid\">\n"
++ + "</function>\n";
++
++ if (argc == 0) {
++ Str *response = new Str("info");
++ response->set_value(info);
++ *btpp = response;
++ return;
++ }
++
++ // TODO Add optional fourth arg that lets the caller say which datum to use;
++ // default to WGS84
++ if (argc != 3)
++ throw Error("The function swath2array() requires three arguments. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *src = dynamic_cast<Array*>(argv[0]);
++ if (!src)
++ throw Error("The first argument to swath2array() must be a data array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *lat = dynamic_cast<Array*>(argv[1]);
++ if (!lat)
++ throw Error("The second argument to swath2array() must be a latitude array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *lon = dynamic_cast<Array*>(argv[2]);
++ if (!lon)
++ throw Error("The third argument to swath2array() must be a longitude array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ // The args passed into the function using argv[] are deleted after the call.
++
++ DAP_Dataset ds(src, lat, lon);
++
++ try {
++ ds.InitialDataset(0);
++
++ *btpp = ds.GetDAPArray();
++ }
++ catch (Error &e) {
++ DBG(cerr << "caught Error: " << e.get_error_message() << endl);
++ throw e;
++ }
++ catch(...) {
++ DBG(cerr << "caught unknown exception" << endl);
++ throw;
++ }
++
++ return;
++}
++
++/**
++ * @todo The lat and lon arrays are passed in, but there's an assumption that the
++ * source data array and the two lat and lon arrays are the same shape. But the
++ * code does not actually test that.
++ *
++ * @todo Enable multiple bands paired with just the two lat/lon arrays? Not sure
++ * if that is a good idea...
++ */
++void function_swath2grid(int argc, BaseType * argv[], DDS &, BaseType **btpp)
++{
++ DBG(cerr << "Entering function_swath2grid..." << endl);
++
++ string info = string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
++ + "<function name=\"swath2grid\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid\">\n"
++ + "</function>\n";
++
++ if (argc == 0) {
++ Str *response = new Str("info");
++ response->set_value(info);
++ *btpp = response;
++ return;
++ }
++
++ // TODO Add optional fourth arg that lets the caller say which datum to use;
++ // default to WGS84
++ if (argc != 3)
++ throw Error("The function swath2grid() requires three arguments. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *src = dynamic_cast<Array*>(argv[0]);
++ if (!src)
++ throw Error("The first argument to swath2grid() must be a data array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *lat = dynamic_cast<Array*>(argv[1]);
++ if (!lat)
++ throw Error("The second argument to swath2grid() must be a latitude array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *lon = dynamic_cast<Array*>(argv[2]);
++ if (!lon)
++ throw Error("The third argument to swath2grid() must be a longitude array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ // The args passed into the function using argv[] are deleted after the call.
++
++ DAP_Dataset ds(src, lat, lon);
++
++ try {
++ ds.InitialDataset(0);
++
++ *btpp = ds.GetDAPGrid();
++ }
++ catch (Error &e) {
++ DBG(cerr << "caught Error: " << e.get_error_message() << endl);
++ throw e;
++ }
++ catch(...) {
++ DBG(cerr << "caught unknown exception" << endl);
++ throw;
++ }
++
++ return;
++}
++
++
++
++
++
++} // namespace libdap
+diff -Nur bes-3.12.0/functions.orig/swath2grid/reproj_functions.h bes-3.12.0/functions/swath2grid/reproj_functions.h
+--- bes-3.12.0/functions.orig/swath2grid/reproj_functions.h 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/reproj_functions.h 2014-03-03 15:47:38.043566262 +0100
+@@ -0,0 +1,109 @@
++
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2002,2003 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++// (c) COPYRIGHT URI/MIT 1999
++// Please read the full copyright statement in the file COPYRIGHT_URI.
++//
++// Authors:
++// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
++
++// Declarations for CE functions.
++//
++// 1/15/99 jhrg
++
++#ifndef _reproj_functions_h
++#define _reproj_functions_h
++
++#include "BESAbstractModule.h"
++#include "ServerFunction.h"
++#include "ServerFunctionsList.h"
++
++namespace libdap {
++
++void function_swath2array(int argc, BaseType * argv[], DDS &, BaseType **btpp);
++void function_swath2grid(int argc, BaseType * argv[], DDS &, BaseType **btpp);
++
++
++class SwathToGrid: public libdap::ServerFunction {
++public:
++ SwathToGrid()
++ {
++ setName("swath2grid");
++ setDescriptionString("This function echos back it's arguments as DAP data.");
++ setUsageString("swath2grid(dataArray, latitudeArray, longitudeArray)");
++ setRole("http://services.opendap.org/dap4/server-side-function/swath2grid");
++ setDocUrl("http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++ setFunction(libdap::function_swath2grid);
++ setVersion("1.0");
++ }
++ virtual ~SwathToGrid()
++ {
++ }
++
++};
++
++class SwathToArray: public libdap::ServerFunction {
++public:
++ SwathToArray()
++ {
++ setName("swath2array");
++ setDescriptionString("This function echos back it's arguments as DAP data.");
++ setUsageString("swath2array(dataArray, latitudeArray, longitudeArray)");
++ setRole("http://services.opendap.org/dap4/server-side-function/swath2array");
++ setDocUrl("http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2array");
++ setFunction(libdap::function_swath2array);
++ setVersion("1.0");
++ }
++ virtual ~SwathToArray()
++ {
++ }
++
++};
++
++
++class ReProjectionFunctions: public BESAbstractModule {
++public:
++ ReProjectionFunctions()
++ {
++ libdap::ServerFunctionsList::TheList()->add_function(new libdap::SwathToGrid());
++
++ libdap::ServerFunctionsList::TheList()->add_function(new libdap::SwathToArray());
++
++ }
++ virtual ~ReProjectionFunctions()
++ {
++ }
++ virtual void initialize(const string &modname);
++ virtual void terminate(const string &modname);
++
++ virtual void dump(ostream &strm) const;
++};
++
++
++
++
++} // namespace libdap
++
++#endif // _reproj_functions_h
+diff -Nur bes-3.12.0/functions.orig/swath2grid/s2gTest.cc bes-3.12.0/functions/swath2grid/s2gTest.cc
+--- bes-3.12.0/functions.orig/swath2grid/s2gTest.cc 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/s2gTest.cc 2014-03-03 15:47:38.043566262 +0100
+@@ -0,0 +1,668 @@
++
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2012 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++// Tests for the AISResources class.
++
++#include <cppunit/TextTestRunner.h>
++#include <cppunit/extensions/TestFactoryRegistry.h>
++#include <cppunit/extensions/HelperMacros.h>
++
++#define DODS_DEBUG
++//#define DODS_DEBUG2
++
++#include "BaseType.h"
++#include "Array.h"
++#include "Grid.h"
++
++#include "reproj_functions.h"
++
++#include "test/TestTypeFactory.h"
++
++#include "util.h"
++#include "debug.h"
++
++#define THREE_ARRAY_1_DDS "three_array_1.dds"
++#define THREE_ARRAY_1_DAS "three_array_1.das"
++
++using namespace CppUnit;
++using namespace libdap;
++using namespace std;
++
++int test_variable_sleep_interval = 0;
++
++/**
++ * Splits the string on the passed char. Returns vector of substrings.
++ * TODO make this work on situations where multiple spaces doesn't hose the split()
++ */
++static vector<string> &split(const string &s, char delim, vector<string> &elems) {
++ stringstream ss(s);
++ string item;
++ while (getline(ss, item, delim)) {
++ elems.push_back(item);
++ }
++ return elems;
++}
++
++/**
++ * Splits the string on the passed char. Returns vector of substrings.
++ */
++static vector<string> split(const string &s, char delim = ' ') {
++ vector<string> elems;
++ return split(s, delim, elems);
++}
++
++class s2gTest:public TestFixture
++{
++private:
++ DDS * dds;
++ TestTypeFactory btf;
++ ConstraintEvaluator ce;
++public:
++ s2gTest():dds(0)
++ {}
++ ~s2gTest()
++ {}
++
++ void setUp()
++ {
++ try {
++ dds = new DDS(&btf);
++ string dds_file = /*(string)TEST_SRC_DIR + "/" +*/ THREE_ARRAY_1_DDS ;
++ dds->parse(dds_file);
++ DAS das;
++ string das_file = /*(string)TEST_SRC_DIR + "/" +*/ THREE_ARRAY_1_DAS ;
++ das.parse(das_file);
++ dds->transfer_attributes(&das);
++
++ DBG(dds->print_xml(stderr, false, "noBlob"));
++
++ // Load values into the array variables
++ Array & t = dynamic_cast < Array & >(*dds->var("t"));
++ Array & lon = dynamic_cast < Array & >(*dds->var("lon"));
++ Array & lat = dynamic_cast < Array & >(*dds->var("lat"));
++
++ dods_float64 t_vals[10][10];
++ for (int i = 0; i < 10; ++i)
++ for (int j = 0; j < 10; ++j)
++ t_vals[i][j] = j + (i * 10);
++ t.set_value(&t_vals[0][0], 100);
++ t.set_read_p(true);
++
++ // Read real lat/lon values from a Level 1B file ascii dump
++ fstream input("AIRS_AQUA_L1B_BRIGHTNESS_20101026_1617.nc.gz.ascii.txt", fstream::in);
++ if (input.eof() || input.fail())
++ throw Error("Could not open lat/lon data in SetUp.");
++ // Read a line of text to get to the start of the data.
++ string line;
++ getline(input, line);
++ if (input.eof() || input.fail())
++ throw Error("Could not read lat/lon data in SetUp.");
++
++ dods_float64 lon_vals[10][10];
++ for (int i = 0; i < 10; ++i) {
++ getline(input, line);
++ if (input.eof() || input.fail())
++ throw Error("Could not read lon data from row " + long_to_string(i) + " in SetUp.");
++ vector<string> vals = split(line, ',');
++ for (unsigned int j = 1; j < vals.size(); ++j) {
++ DBG2(cerr << "loading in lon value: " << vals[j] << "' " << atof(vals[j].c_str()) << endl;)
++ lon_vals[i][j-1] = atof(vals[j].c_str());
++ }
++ }
++ lon.set_value(&lon_vals[0][0], 100);
++ lon.set_read_p(true);
++
++ dods_float64 lat_vals[10][10];
++ for (int i = 0; i < 10; ++i) {
++ getline(input, line);
++ if (input.eof() || input.fail())
++ throw Error("Could not read lat data from row " + long_to_string(i) + " in SetUp.");
++ vector<string> vals = split(line, ',');
++ for (unsigned int j = 1; j < vals.size(); ++j) {
++ DBG2(cerr << "loading in lat value: " << vals[j] << "' " << atof(vals[j].c_str()) << endl;)
++ lat_vals[i][j-1] = atof(vals[j].c_str());
++ }
++ }
++ lat.set_value(&lat_vals[0][0], 100);
++ lat.set_read_p(true);
++ }
++
++ catch (Error & e) {
++ cerr << "SetUp (Error): " << e.get_error_message() << endl;
++ throw;
++ }
++ catch(std::exception &e) {
++ cerr << "SetUp (std::exception): " << e.what() << endl;
++ throw;
++ }
++ }
++
++ void tearDown()
++ {
++ delete dds; dds = 0;
++ }
++
++ CPPUNIT_TEST_SUITE( s2gTest );
++
++ CPPUNIT_TEST(no_arguments_test);
++ CPPUNIT_TEST(array_return_test);
++ CPPUNIT_TEST(grid_return_test);
++
++ CPPUNIT_TEST_SUITE_END();
++
++ void no_arguments_test()
++ {
++ try {
++ BaseType *btp = 0;
++ function_swath2array(0, 0, *dds, &btp);
++ CPPUNIT_ASSERT(true);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"no_arguments_test() should not have failed");
++ }
++ }
++
++ void array_return_test()
++ {
++ try {
++ BaseType *argv[3];
++ argv[0] = dds->var("t");
++ argv[1] = dds->var("lon");
++ argv[2] = dds->var("lat");
++
++ BaseType *btp = 0;
++ function_swath2array(3, argv, *dds, &btp);
++
++ DBG(cerr << "btp->name(): " << btp->name() << endl);
++ CPPUNIT_ASSERT(btp->name() == "t");
++ CPPUNIT_ASSERT(btp->type() == dods_array_c);
++
++ // Extract data; I know it's 10x16 from debugging output
++ dods_float64 values[10][16];
++ Array *a = static_cast<Array*>(btp);
++ a->value(&values[0][0]);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_FAIL("array_return_test");
++ }
++ }
++
++#if 0
++ void one_argument_not_a_grid_test()
++ {
++ try {
++ BaseType *argv[1];
++ argv[0] = dds->var("lat");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this, although it is not a grid");
++ BaseType *btp = 0;
++ function_grid(1, argv, *dds, &btp);
++ CPPUNIT_ASSERT(!"one_argument_not_a_grid_test() should have failed");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(true);
++ }
++ }
++
++ void map_not_in_grid_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "3<second<=7";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ CPPUNIT_ASSERT(!"map_not_in_grid_test() should have failed");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(true);
++ }
++ }
++
++ void one_dim_grid_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "3<first<=7";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ Grid &g = dynamic_cast<Grid&>(*btp);
++
++ //Grid &g = dynamic_cast<Grid&>(*argv[0]);
++ Array &m = dynamic_cast<Array&>(**g.map_begin());
++ CPPUNIT_ASSERT(m.dimension_start(m.dim_begin(), true) == 4);
++ CPPUNIT_ASSERT(m.dimension_stop(m.dim_begin(), true) == 7);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"one_dim_grid_test() should have worked");
++ }
++ }
++
++ void one_dim_grid_two_expressions_test()
++ {
++ try {
++ BaseType *argv[3];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++
++ argv[1] = new Str("");
++ string expression = "first>3";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ argv[2] = new Str("");
++ expression = "first<=7";
++ dynamic_cast<Str*>(argv[2])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[2])->set_read_p(true);
++
++ //function_grid(3, argv, *dds);
++ BaseType *btp = 0;
++ function_grid(3, argv, *dds, &btp);
++ Grid &g = dynamic_cast<Grid&>(*btp);
++
++ //Grid &g = dynamic_cast<Grid&>(*function_grid(3, argv, *dds));
++ //Grid &g = dynamic_cast<Grid&>(*argv[0]);
++ Array &m = dynamic_cast<Array&>(**g.map_begin());
++ CPPUNIT_ASSERT(m.dimension_start(m.dim_begin(), true) == 4);
++ CPPUNIT_ASSERT(m.dimension_stop(m.dim_begin(), true) == 7);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"one_dim_grid_two_expressions_test() should have worked");
++ }
++ }
++
++ void one_dim_grid_descending_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("b");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "3<first<=7";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ Grid &g = dynamic_cast<Grid&>(*btp);
++
++ //function_grid(2, argv, *dds);
++ //Grid &g = dynamic_cast<Grid&>(*function_grid(2, argv, *dds));
++ //Grid &g = dynamic_cast<Grid&>(*argv[0]);
++ Array &m = dynamic_cast<Array&>(**g.map_begin());
++ CPPUNIT_ASSERT(m.dimension_start(m.dim_begin(), true) == 2);
++ CPPUNIT_ASSERT(m.dimension_stop(m.dim_begin(), true) == 5);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"one_dim_grid_test() should have worked");
++ }
++ }
++
++ void one_dim_grid_two_expressions_descending_test()
++ {
++ try {
++ BaseType *argv[3];
++ argv[0] = dds->var("b");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++
++ argv[1] = new Str("");
++ string expression = "first>3";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ argv[2] = new Str("");
++ expression = "first<=7";
++ dynamic_cast<Str*>(argv[2])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[2])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(3, argv, *dds, &btp);
++ Grid &g = dynamic_cast<Grid&>(*btp);
++
++ //function_grid(3, argv, *dds);
++ //Grid &g = dynamic_cast<Grid&>(*function_grid(3, argv, *dds));
++ //Grid &g = dynamic_cast<Grid&>(*argv[0]);
++ Array &m = dynamic_cast<Array&>(**g.map_begin());
++ CPPUNIT_ASSERT(m.dimension_start(m.dim_begin(), true) == 2);
++ CPPUNIT_ASSERT(m.dimension_stop(m.dim_begin(), true) == 5);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"one_dim_grid_two_expressions_test() should have worked");
++ }
++ }
++
++ void one_dim_grid_noninclusive_values_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "7<first<=3";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ //Grid &g = dynamic_cast<Grid&>(*btp);
++
++ // function_grid(2, argv, *dds);
++
++ CPPUNIT_ASSERT(!"one_dim_grid_noninclusive_values_test() should not have worked");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(true);
++ }
++ }
++
++ // grid() is not required to handle this case. This test is not used.
++ void values_outside_map_range_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "3<=first<20";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ //Grid &g = dynamic_cast<Grid&>(*btp);
++
++ // function_grid(2, argv, *dds);
++
++ CPPUNIT_ASSERT(!"values_outside_map_range_test() should not have worked");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(true);
++ }
++ }
++
++ // linear_scale tests
++ void linear_scale_args_test() {
++ try {
++ BaseType *btp = 0;
++ function_linear_scale(0, 0, *dds, &btp);
++ CPPUNIT_ASSERT(true);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"linear_scale_args_test: should not throw Error");
++ }
++ }
++
++ void linear_scale_array_test() {
++ try {
++ Array *a = dynamic_cast<Grid&>(*dds->var("a")).get_array();
++ CPPUNIT_ASSERT(a);
++ BaseType *argv[3];
++ argv[0] = a;
++ argv[1] = new Float64("");
++ dynamic_cast<Float64*>(argv[1])->set_value(0.1);//m
++ argv[2] = new Float64("");
++ dynamic_cast<Float64*>(argv[2])->set_value(10);//b
++ BaseType *scaled = 0;
++ function_linear_scale(3, argv, *dds, &scaled);
++ CPPUNIT_ASSERT(scaled->type() == dods_array_c
++ && scaled->var()->type() == dods_float64_c);
++ double *values = extract_double_array(dynamic_cast<Array*>(scaled));
++ CPPUNIT_ASSERT(values[0] == 10);
++ CPPUNIT_ASSERT(values[1] == 10.1);
++ CPPUNIT_ASSERT(values[9] == 10.9);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"Error in linear_scale_grid_test()");
++ }
++ }
++
++ void linear_scale_grid_test() {
++ try {
++ Grid *g = dynamic_cast<Grid*>(dds->var("a"));
++ CPPUNIT_ASSERT(g);
++ BaseType *argv[3];
++ argv[0] = g;
++ argv[1] = new Float64("");
++ dynamic_cast<Float64*>(argv[1])->set_value(0.1);
++ argv[2] = new Float64("");
++ dynamic_cast<Float64*>(argv[2])->set_value(10);
++ BaseType *scaled = 0;
++ function_linear_scale(3, argv, *dds, &scaled);
++ CPPUNIT_ASSERT(scaled->type() == dods_grid_c);
++ Grid *g_s = dynamic_cast<Grid*>(scaled);
++ CPPUNIT_ASSERT(g_s->get_array()->var()->type() == dods_float64_c);
++ double *values = extract_double_array(g_s->get_array());
++ CPPUNIT_ASSERT(values[0] == 10);
++ CPPUNIT_ASSERT(values[1] == 10.1);
++ CPPUNIT_ASSERT(values[9] == 10.9);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"Error in linear_scale_grid_test()");
++ }
++ }
++
++ void linear_scale_grid_attributes_test() {
++ try {
++ Grid *g = dynamic_cast<Grid*>(dds->var("a"));
++ CPPUNIT_ASSERT(g);
++ BaseType *argv[1];
++ argv[0] = g;
++ BaseType *scaled = 0;
++ function_linear_scale(1, argv, *dds, &scaled);
++ CPPUNIT_ASSERT(scaled->type() == dods_grid_c);
++ Grid *g_s = dynamic_cast<Grid*>(scaled);
++ CPPUNIT_ASSERT(g_s->get_array()->var()->type() == dods_float64_c);
++ double *values = extract_double_array(g_s->get_array());
++ CPPUNIT_ASSERT(values[0] == 10);
++ CPPUNIT_ASSERT(values[1] == 10.1);
++ CPPUNIT_ASSERT(values[9] == 10.9);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"Error in linear_scale_grid_test()");
++ }
++ }
++
++ // This tests the case where attributes are not found
++ void linear_scale_grid_attributes_test2() {
++ try {
++ Grid *g = dynamic_cast<Grid*>(dds->var("b"));
++ CPPUNIT_ASSERT(g);
++ BaseType *argv[1];
++ argv[0] = g;
++ BaseType *btp = 0;
++ function_linear_scale(1, argv, *dds, &btp);
++ CPPUNIT_FAIL("Should not get here; no params passed and no attributes set for grid 'b'");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT("Caught exception");
++ }
++ }
++
++ void linear_scale_scalar_test() {
++ try {
++ Int32 *i = new Int32("linear_scale_test_int32");
++ CPPUNIT_ASSERT(i);
++ i->set_value(1);
++ BaseType *argv[3];
++ argv[0] = i;
++ argv[1] = new Float64("");
++ dynamic_cast<Float64*>(argv[1])->set_value(0.1);//m
++ argv[2] = new Float64("");
++ dynamic_cast<Float64*>(argv[2])->set_value(10);//b
++ BaseType *scaled = 0;
++ function_linear_scale(3, argv, *dds, &scaled);
++ CPPUNIT_ASSERT(scaled->type() == dods_float64_c);
++
++ CPPUNIT_ASSERT(dynamic_cast<Float64*>(scaled)->value() == 10.1);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"Error in linear_scale_scalar_test()");
++ }
++ }
++
++
++ void function_dap_1_test() {
++ try {
++ Int32 *i = new Int32("function_dap_1_test_int32");
++ CPPUNIT_ASSERT(i);
++ i->set_value(2);
++ BaseType *argv[1];
++ argv[0] = i;
++
++ ConstraintEvaluator unused;
++ function_dap(1, argv, *dds, unused);
++
++ CPPUNIT_ASSERT(dds->get_dap_major() == 2);
++ CPPUNIT_ASSERT(dds->get_dap_minor() == 0);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_FAIL("Error in function_dap_1_test(): " + e.get_error_message());
++ }
++ }
++
++ void function_dap_2_test() {
++ try {
++ Float64 *d = new Float64("function_dap_1_test_float64");
++ CPPUNIT_ASSERT(d);
++ d->set_value(3.2);
++ BaseType *argv[1];
++ argv[0] = d;
++
++ ConstraintEvaluator unused;
++ function_dap(1, argv, *dds, unused);
++
++ CPPUNIT_ASSERT(dds->get_dap_major() == 3);
++ CPPUNIT_ASSERT(dds->get_dap_minor() == 2);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_FAIL("Error in function_dap_2_test(): " + e.get_error_message());
++ }
++ }
++
++ void function_dap_3_test() {
++ try {
++ cerr <<"In function_dap_3_test" << endl;
++ ConstraintEvaluator unused;
++ function_dap(0, 0, *dds, unused);
++
++ CPPUNIT_FAIL("Should have thrown an exception on no args");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT("Pass: Caught exception");
++ }
++ }
++#endif
++ void grid_return_test()
++ {
++ try {
++ BaseType *argv[3];
++ argv[0] = dds->var("t");
++ argv[1] = dds->var("lon");
++ argv[2] = dds->var("lat");
++
++ cerr << "Input values:" << endl;
++ dods_float64 t_vals[10][10];
++ Array *a = static_cast<Array*>(argv[0]);
++ a->value(&t_vals[0][0]);
++ for (int i = 0; i < 10; ++i) {
++ for (int j = 0; j < 10; ++j) {
++ cerr << "t[" << i << "][" << j << "]: " << t_vals[i][j] << endl;
++ }
++ }
++
++ BaseType *btp = 0;
++ function_swath2grid(3, argv, *dds, &btp);
++
++ DBG(cerr << "btp->name(): " << btp->name() << endl);
++ CPPUNIT_ASSERT(btp->name() == "t");
++ CPPUNIT_ASSERT(btp->type() == dods_grid_c);
++
++ // Extract data; I know it's 10x16 from debugging output
++ dods_float64 values[10][16];
++ Grid *g = static_cast<Grid*>(btp);
++ g->get_array()->value(&values[0][0]);
++
++ Grid::Map_iter m = g->map_begin();
++ dods_float64 lat[10];
++ static_cast<Array*>(*m)->value(&lat[0]);
++
++ ++m;
++ dods_float64 lon[16];
++ static_cast<Array*>(*m)->value(&lon[0]);
++
++ cerr << "Output values:" << endl;
++ for (int i = 0; i < 10; ++i) {
++ for (int j = 0; j < 16; ++j) {
++ cerr << "t[" << i << "][" << j << "] == lon: " << lon[j] << ", lat: " << lat[i] << " val: " << values[i][j] << endl;
++ }
++ }
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_FAIL("array_return_test");
++ }
++ }
++};
++
++CPPUNIT_TEST_SUITE_REGISTRATION(s2gTest);
++
++int
++main( int, char** )
++{
++ CppUnit::TextTestRunner runner;
++ runner.addTest( CppUnit::TestFactoryRegistry::getRegistry().makeTest() );
++
++ bool wasSuccessful = runner.run( "", false ) ;
++
++ return wasSuccessful ? 0 : 1;
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/entries bes-3.12.0/functions/swath2grid/.svn/entries
+--- bes-3.12.0/functions.orig/swath2grid/.svn/entries 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/entries 2014-03-03 15:47:34.366899750 +0100
+@@ -0,0 +1 @@
++12
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/format bes-3.12.0/functions/swath2grid/.svn/format
+--- bes-3.12.0/functions.orig/swath2grid/.svn/format 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/format 2014-03-03 15:47:34.366899750 +0100
+@@ -0,0 +1 @@
++12
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/2c/2c1fb68452ecaa4ec099ab4ec2c2a3a62c6aa0d9.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/2c/2c1fb68452ecaa4ec099ab4ec2c2a3a62c6aa0d9.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/2c/2c1fb68452ecaa4ec099ab4ec2c2a3a62c6aa0d9.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/2c/2c1fb68452ecaa4ec099ab4ec2c2a3a62c6aa0d9.svn-base 2014-03-03 15:47:37.593566281 +0100
+@@ -0,0 +1,116 @@
++/******************************************************************************
++ * $Id: wcs_error.cpp 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: WCS exception and error handler implementation, used to set
++ * the exception code and locator of WCS
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 "wcs_error.h"
++
++static string WCS_ERROR_STRING="";
++static string ERROR_LOCATOR="";
++static string ExcptCodeText[] =
++{
++ "OperationNotSupported",
++ "MissingParameterValue",
++ "InvalidParameterValue",
++ "VersionNegotiationFailed",
++ "InvalidUpdateSequence",
++ "OptionNotSupported",
++ "NoApplicableCode",
++ "NoSuchCoverage",
++ "InvalidAxisLabel",
++ "InvalidSubsetting"
++};
++
++static int WCS_IsSoapMessage_Transform = 0;
++
++string CPL_STDCALL GetWCS_ErrorMsg()
++{
++ return WCS_ERROR_STRING;
++}
++
++void CPL_STDCALL SetWCS_ErrorLocator(const char* loc)
++{
++ ERROR_LOCATOR = loc;
++}
++
++void CPL_STDCALL WCS_ErrorHandler(CPLErr eErrClass,int err_no,const char *pszErrorMsg )
++{
++ WCS_ERROR_STRING.clear();
++ string ExcCode;
++
++ if(err_no >= 300 && err_no <= 309)
++ ExcCode = ExcptCodeText[err_no - 300];
++ else
++ ExcCode = ExcptCodeText[6];
++
++ if(WCS_IsSoapMessage_Transform)
++ {
++ WCS_ERROR_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
++ WCS_ERROR_STRING += "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n";
++ WCS_ERROR_STRING += "<soap:Body>\n";
++ WCS_ERROR_STRING += "<ExceptionReport xmlns=\"http://www.opengis.net/ows\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
++ WCS_ERROR_STRING += "xsi:schemaLocation=\"http://www.opengis.net/ows/owsCommon.xsd\" version=\"0.3.20\" language=\"en\">\n";
++ WCS_ERROR_STRING += " <Exception exceptionCode=\"";
++ WCS_ERROR_STRING += ExcCode;
++ WCS_ERROR_STRING += "\" locator=\"";
++ WCS_ERROR_STRING += ERROR_LOCATOR;
++ WCS_ERROR_STRING += "\">\n";
++ WCS_ERROR_STRING += " <ExceptionText>" + string(pszErrorMsg) + "</ExceptionText>\n";
++ WCS_ERROR_STRING += " </Exception>\n";
++ WCS_ERROR_STRING += "</ExceptionReport>\n";
++ WCS_ERROR_STRING += "/soap:Body>\n";
++ WCS_ERROR_STRING += "/<soap:Envelope>\n";
++ }
++ else
++ {
++ WCS_ERROR_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
++ WCS_ERROR_STRING += "<ExceptionReport xmlns=\"http://www.opengis.net/ows\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
++ WCS_ERROR_STRING += "xsi:schemaLocation=\"http://www.opengis.net/ows/owsCommon.xsd\" version=\"0.3.20\" language=\"en\">\n";
++ WCS_ERROR_STRING += " <Exception exceptionCode=\"";
++ WCS_ERROR_STRING += ExcCode;
++ WCS_ERROR_STRING += "\" locator=\"";
++ WCS_ERROR_STRING += ERROR_LOCATOR;
++ WCS_ERROR_STRING += "\">\n";
++ WCS_ERROR_STRING += " <ExceptionText>" + string(pszErrorMsg) + "</ExceptionText>\n";
++ WCS_ERROR_STRING += " </Exception>\n";
++ WCS_ERROR_STRING += "</ExceptionReport>\n";
++ }
++
++ return;
++}
++
++void WCST_SetSoapMsgTrns(int isSoap)
++{
++ WCS_IsSoapMessage_Transform = isSoap;
++}
++
++int WCST_GetSoapMsgTrns()
++{
++ return WCS_IsSoapMessage_Transform;
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/37/3738e631c59c1f5cded9ac6457cfcb35d402dba7.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/37/3738e631c59c1f5cded9ac6457cfcb35d402dba7.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/37/3738e631c59c1f5cded9ac6457cfcb35d402dba7.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/37/3738e631c59c1f5cded9ac6457cfcb35d402dba7.svn-base 2014-03-03 15:47:37.810232939 +0100
+@@ -0,0 +1,10 @@
++# three_array_1.dds
++#
++# Created on: Dec 12, 2012
++# Author: jimg
++
++Dataset {
++ Float64 t[10][10];
++ Float64 lon[10][10];
++ Float64 lat[10][10];
++} three_array_1;
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/54/5408a8ae104fd8000f1d7015e95b1848047c9f56.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/54/5408a8ae104fd8000f1d7015e95b1848047c9f56.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/54/5408a8ae104fd8000f1d7015e95b1848047c9f56.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/54/5408a8ae104fd8000f1d7015e95b1848047c9f56.svn-base 2014-03-03 15:47:37.806899605 +0100
+@@ -0,0 +1,81 @@
++/******************************************************************************
++ * $Id: wcs_error.h 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: WCS exception and error handler definition
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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.
++ ****************************************************************************/
++
++/************************************************************************
++ WCS Exception Code
++
++ See OGC Web Services Common Standard [OGC 06-121r9] for details
++ Table 27 — Standard exception codes and meanings
++ OperationNotSupported
++ MissingParameterValue
++ InvalidParameterValue
++ VersionNegotiationFailed
++ InvalidUpdateSequence
++ OptionNotSupported
++ NoApplicableCode
++
++ See OGC® WCS 2.0 Interface Standard - Core [09-110r3] for details
++ Table 18 - Exception codes for GetCoverage operation
++ NoSuchCoverage
++ InvalidAxisLabel
++ InvalidSubsetting
++
++*************************************************************************/
++
++#ifndef WCS_ERROR_H_
++#define WCS_ERROR_H_
++
++#include <cpl_error.h>
++#include <string>
++
++using namespace std;
++
++#define OGC_WCS_OperationNotSupported 300
++#define OGC_WCS_MissingParameterValue 301
++#define OGC_WCS_InvalidParameterValue 302
++#define OGC_WCS_VersionNegotiationFailed 303
++#define OGC_WCS_InvalidUpdateSequence 304
++#define OGC_WCS_OptionNotSupported 305
++#define OGC_WCS_NoApplicableCode 306
++
++#define OGC_WCS_NoSuchCoverage 307
++#define OGC_WCS_InvalidAxisLabel 308
++#define OGC_WCS_InvalidSubsetting 309
++
++void CPL_DLL CPL_STDCALL WCS_Error(CPLErr, int, const char*, ...);
++void CPL_DLL CPL_STDCALL SetWCS_ErrorLocator(const char* loc);
++void CPL_DLL CPL_STDCALL WCS_ErrorHandler(CPLErr, int, const char*);
++string CPL_DLL CPL_STDCALL GetWCS_ErrorMsg();
++
++int WCST_GetSoapMsgTrns();
++void WCST_SetSoapMsgTrns(int);
++
++#define WCS_Error CPLError
++#endif /* WCS_ERROR_H_ */
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/55/552f5680f38631504c1a309d875c7bbbf2bc2492.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/55/552f5680f38631504c1a309d875c7bbbf2bc2492.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/55/552f5680f38631504c1a309d875c7bbbf2bc2492.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/55/552f5680f38631504c1a309d875c7bbbf2bc2492.svn-base 2014-03-03 15:47:37.846899604 +0100
+@@ -0,0 +1,142 @@
++
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2012 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++#ifndef DAP_DATASET_H_
++#define DAP_DATASET_H_
++
++#include <string>
++#include "AbstractDataset.h"
++#include "wcsUtil.h"
++
++using namespace std;
++
++namespace libdap {
++
++class Array;
++class Grid;
++
++/************************************************************************/
++/* ==================================================================== */
++/* DAP_Dataset */
++/* ==================================================================== */
++/************************************************************************/
++
++//! DAP_Dataset is a subclass of AbstractDataset, used to process NOAA GOES data.
++/**
++ * \class DAP_Dataset "DAP_Dataset.h"
++ *
++ * GOES satellites provide the kind of continuous monitoring necessary for
++ * intensive data analysis. They circle the Earth in a geosynchronous orbit,
++ * which means they orbit the equatorial plane of the Earth at a speed
++ * matching the Earth's rotation. This allows them to hover continuously
++ * over one position on the surface. The geosynchronous plane is about
++ * 35,800 km (22,300 miles) above the Earth, high enough to allow the
++ * satellites a full-disc view of the Earth. Because they stay above a
++ * fixed spot on the surface, they provide a constant vigil for the atmospheric
++ * "triggers" for severe weather conditions such as tornadoes, flash floods,
++ * hail storms, and hurricanes. When these conditions develop the GOES
++ * satellites are able to monitor storm development and track their movements.
++ *
++ * GOES satellite imagery is also used to estimate rainfall during
++ * the thunderstorms and hurricanes for flash flood warnings, as well
++ * as estimates snowfall accumulations and overall extent of snow cover.
++ * Such data help meteorologists issue winter storm warnings and spring
++ * snow melt advisories. Satellite sensors also detect ice fields and map
++ * the movements of sea and lake ice.
++ *
++ * For more inforamtion about NOAA GOES data, please access
++ * <a href=http://www.oso.noaa.gov/GOES/>http://www.oso.noaa.gov/GOES/</a>
++ *
++ * DAP_Dataset is a subclass of AbstractDataset, which is used to
++ * process GOES Imager and Sounder products.
++ */
++
++class DAP_Dataset : public AbstractDataset {
++protected:
++ string m_ncLatDataSetName;
++ string m_ncLonDataSetName;
++ string m_ncCoverageIDName;
++
++ // Instead of using names and opening files with GDAL,
++ // store pointers to Arrays read by the underlying DAP
++ // server constraint evaluator.
++ Array *m_src;
++ Array *m_lat;
++ Array *m_lon;
++
++ int mi_RectifiedImageXSize;
++ int mi_RectifiedImageYSize;
++ int mi_SrcImageXSize;
++ int mi_SrcImageYSize;
++
++ double mb_LatLonBBox[4];
++ double mdSrcGeoMinX;
++ double mdSrcGeoMinY;
++ double mdSrcGeoMaxX;
++ double mdSrcGeoMaxY;
++
++ // This is not set until GetDAPArray() is called.
++ double m_geo_transform_coef[6];
++
++ vector<GDAL_GCP> m_gdalGCPs;
++
++public:
++ CPLErr SetGCPGeoRef4VRTDataset(GDALDataset*);
++ void SetGeoBBoxAndGCPs(int xSize, int ySize);
++ CPLErr RectifyGOESDataSet();
++ CPLErr setResampleStandard(GDALDataset* hSrcDS, int& xRSValue, int& yRSValue);
++
++ int isValidLatitude(const double &lat)
++ {
++ return (lat >= -90 && lat <= 90);
++ }
++ int isValidLongitude(const double &lon)
++ {
++ return (lon >= -180 && lon <= 180);
++ }
++
++ virtual CPLErr SetGeoTransform();
++#if 0
++ virtual CPLErr SetMetaDataList(GDALDataset* hSrcDS); //TODO Remove
++#endif
++ virtual CPLErr SetNativeCRS();
++ virtual CPLErr SetGDALDataset(const int isSimple = 0);
++ virtual CPLErr InitialDataset(const int isSimple = 0);
++ virtual CPLErr GetGeoMinMax(double geoMinMax[]);
++
++public:
++ DAP_Dataset();
++ DAP_Dataset(const string& id, vector<int> &rBandList);
++
++ // Added jhrg 11/23/12
++ DAP_Dataset(Array *src, Array *lat, Array *lon);
++ Array *GetDAPArray();
++ Grid *GetDAPGrid();
++
++ virtual ~DAP_Dataset();
++};
++
++} // namespace libdap
++#endif /* DAP_DATASET_H_ */
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/5c/5c131461ae16583ef4babcd3a87404f41769d430.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/5c/5c131461ae16583ef4babcd3a87404f41769d430.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/5c/5c131461ae16583ef4babcd3a87404f41769d430.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/5c/5c131461ae16583ef4babcd3a87404f41769d430.svn-base 2014-03-03 15:47:37.633566281 +0100
+@@ -0,0 +1,1238 @@
++/******************************************************************************
++ * $Id: AbstractDataset.cpp 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: AbstractDataset implementation for providing an abstract data
++ * model for multiple data source.
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 "AbstractDataset.h"
++
++/************************************************************************/
++/* ==================================================================== */
++/* AbstractDataset */
++/* ==================================================================== */
++/************************************************************************/
++
++/**
++ * \class AbstractDataset "AbstractDataset.h"
++ *
++ * An abstract dataset encapsulating one or more raster bands, which is
++ * based on GDALDataset, and add the support to metadata model: ISO 19115
++ * and 1SO 19115 (2). A series of Fetch functions are provided for the
++ * implementation of Web Coverage Service.
++ *
++ * Use WCSTCreateDataset() to create a AbstractDataset for a named coverage
++ * identifier and band list.
++ */
++
++/************************************************************************/
++/* AbstractDataset() */
++/************************************************************************/
++AbstractDataset::AbstractDataset()
++{
++}
++
++/************************************************************************/
++/* AbstractDataset() */
++/************************************************************************/
++
++/**
++ * \brief Constructor of an AbstractDataset.
++ *
++ * This is the accepted method of opening an abstract dataset and allocating
++ * all resources associated with it.
++ */
++
++AbstractDataset::AbstractDataset(const string& id, vector<int> &rBandList) :
++ ms_CoverageID(id), mv_BandList(rBandList)
++{
++}
++
++/************************************************************************/
++/* ~AbstractDataset() */
++/************************************************************************/
++
++/**
++ * \brief Destroy an open AbstractDataset object.
++ *
++ * This is the accepted method of closing a AbstractDataset dataset and
++ * deallocating all resources associated with it.
++ */
++
++AbstractDataset::~AbstractDataset()
++{
++ if (maptr_DS.get())
++ GDALClose(maptr_DS.release());
++}
++
++/************************************************************************/
++/* InitialDataset() */
++/************************************************************************/
++
++/**
++ * \brief Initialize the data set.
++ *
++ * This is the virtual function for initializing abstract dataste. The
++ * subclasses of AbstarctDataset will call SetNativeCRS(), SetGeoTransform()
++ * and SetGDALDataset() to initialize an abstarct dataset.
++ *
++ * @param isSimple The WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::InitialDataset(const int isSimple)
++{
++ return CE_Failure;
++}
++
++/************************************************************************/
++/* GetGDALDataset() */
++/************************************************************************/
++
++/**
++ * \brief Get the GDALDataset object from AbstarctDataset.
++ *
++ * An AbstarctDataset encapsulating one GDALDataset. GetGDALDataset()
++ * returns a GDALDatset object, which is used to fetch its information
++ * through GDAL APIs.
++ *
++ * @return GDALDatset object.
++ */
++
++GDALDataset* AbstractDataset::GetGDALDataset()
++{
++ return maptr_DS.get();
++}
++
++/************************************************************************/
++/* SetGDALDataset() */
++/************************************************************************/
++
++/**
++ * \brief Set the GDALDataset object to AbstarctDataset.
++ *
++ * This is the virtual function for setting the abstract dataset by
++ * calling GDAL functions.
++ *
++ * @param isSimple the WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::SetGDALDataset(const int isSimple)
++{
++ return CE_Failure;
++}
++
++/************************************************************************/
++/* GetNativeCRS() */
++/************************************************************************/
++
++/**
++ * \brief Get the Native CRS of an AbstarctDataset.
++ *
++ * The method will return the CRS obejct, which is an OGRSpatialReference
++ * object.
++ *
++ * @return an OGRSpatialReference object corresponding the native CRS of
++ * coverage.
++ */
++
++const OGRSpatialReference& AbstractDataset::GetNativeCRS()
++{
++ return mo_NativeCRS;
++}
++
++/************************************************************************/
++/* SetNativeCRS() */
++/************************************************************************/
++
++/**
++ * \brief Set the Native CRS for an AbstarctDataset.
++ *
++ * The method will set the CRS for an AbstractDataset as an native CRS. For
++ * some served coverage, GDAL could not tell its native CRS, this method
++ * should be called to set its native CRS.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::SetNativeCRS()
++{
++ char* wktStr = (char*) maptr_DS->GetProjectionRef();
++
++ if (wktStr && OGRERR_NONE == mo_NativeCRS.importFromWkt(&wktStr))
++ return CE_None;
++
++ return CE_Failure;
++}
++
++/************************************************************************/
++/* SetGeoTransform() */
++/************************************************************************/
++
++/**
++ * \brief Set the affine GeoTransform matrix for a coverage.
++ *
++ * The method will set a GeoTransform matrix for a coverage. The method
++ * GetGeoTransform of GDAL library will be called to get the matrix.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::SetGeoTransform()
++{
++ if (CE_None != maptr_DS->GetGeoTransform(md_Geotransform))
++ return CE_Failure;
++
++ //Is the returned matrix correct? check the resolution values;
++ if(md_Geotransform[2] == 0 && md_Geotransform[5] == 0)
++ return CE_Failure;
++
++ mb_GeoTransformSet = TRUE;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetGeoTransform() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the affine transformation coefficients.
++ *
++ * Fetches the coefficients for transforming between pixel/line (P,L) raster
++ * space, and projection coordinates (Xp,Yp) space.
++ *
++ * \code
++ * Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
++ * Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
++ * \endcode
++ *
++ * In a north up image, padfTransform[1] is the pixel width, and
++ * padfTransform[5] is the pixel height. The upper left corner of the
++ * upper left pixel is at position (padfTransform[0],padfTransform[3]).
++ *
++ * The default transform is (0,1,0,0,0,1) and should be returned even when
++ * a CE_Failure error is returned, such as for formats that don't support
++ * transformation to projection coordinates.
++ *
++ * NOTE: GetGeoTransform() isn't expressive enough to handle the variety of
++ * OGC Grid Coverages pixel/line to projection transformation schemes.
++ * Eventually this method will be depreciated in favour of a more general
++ * scheme.
++ *
++ * @param geoTrans an existing six double buffer into which the
++ * transformation will be placed.
++ *
++ * @return TRUE on success or FALSE on failure.
++ */
++
++int AbstractDataset::GetGeoTransform(double geoTrans[])
++{
++ if (!mb_GeoTransformSet)//Geo-Transform not setup in each data driver, then set default.
++ {
++ geoTrans[0]=0.0;
++ geoTrans[0]=1.0;
++ geoTrans[0]=0.0;
++ geoTrans[0]=0.0;
++ geoTrans[0]=0.0;
++ geoTrans[0]=1.0;
++ return FALSE;
++ }
++
++ memcpy(geoTrans, md_Geotransform, sizeof(double) * 6);
++
++ return TRUE;
++}
++
++/************************************************************************/
++/* GetCoverageID() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the identifier of a coverage.
++ *
++ * The method will return the coverage identifier related to the abstarct
++ * dataset. As to TRMM data, the coverage identifier likes:
++ * TRMM:/Volumes/RAIDL1/GeoData/TRMM/TRMM_3B42_daily.2000.hdf:Daily
++ *
++ * As to MODIS data, the coverage identifier likes:
++ * HDF4_EOS:EOS_GRID:"/Volumes/RAIDL1/GeoData/MOD15A2/2007/MYD15A2.A2007241.h12v09.005.2007256053902.hdf":MOD_Grid_MOD15A2:Lai_1km
++ *
++ * @return the string of coverage identifier.
++ */
++
++string AbstractDataset::GetCoverageID()
++{
++ return ms_CoverageID;
++}
++
++/************************************************************************/
++/* GetResourceFileName() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the resource file name of a coverage.
++ *
++ * The method will return the full path corresponding the file contained
++ * coverage.
++ *
++ * @return the string of resource file path.
++ */
++
++string AbstractDataset::GetResourceFileName()
++{
++ return ms_SrcFilename;
++}
++
++/************************************************************************/
++/* GetDatasetName() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the dataset name of a coverage.
++ *
++ * The method will return the data set name corresponding the file contained
++ * coverage. For example, MOD09GQ data has the coverage identifier as following;
++ * HDF4_EOS:EOS_GRID:"/Volumes/RAIDL1/GeoData/MODISData/MOD09GQ/MOD09GQ.A2010001.h12v05.005.2010007003100.hdf":MODIS_Grid_2D:sur_refl_b01_1
++ *
++ * sur_refl_b01_1 is seemed as the dataset name.
++ *
++ * @return the string of dataset name.
++ */
++
++string AbstractDataset::GetDatasetName()
++{
++ return ms_DatasetName;
++}
++
++/************************************************************************/
++/* GetDataTypeName() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the dataset type name of a coverage.
++ *
++ * The method will return the data set name corresponding the file contained
++ * coverage. For example, MOD09GQ data has the coverage identifier as following;
++ * HDF4_EOS:EOS_GRID:"/Volumes/RAIDL1/GeoData/MODISData/MOD09GQ/MOD09GQ.A2010001.h12v05.005.2010007003100.hdf":MODIS_Grid_2D:sur_refl_b01_1
++ *
++ * MODIS_Grid_2D is seemed as the dataset type name.
++ *
++ * @return the string of dataset type name.
++ */
++
++string AbstractDataset::GetDataTypeName()
++{
++ return ms_DataTypeName;
++}
++
++/************************************************************************/
++/* GetDataTypeName() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the dataset description of a coverage.
++ *
++ * The method will build a description for the coverage. The coverage
++ * extent, dataset name, dataset type name will be contained in the
++ * description,
++ *
++ * @return the string of dataset description.
++ */
++
++string AbstractDataset::GetDatasetDescription()
++{
++ //[15x2030x1354] Band JPEG2000 (16-bit unsigned integer)
++ string rtnBuf;
++ int aiDimSizes[3];
++ int nBandCount = maptr_DS->GetRasterCount();
++ string pszString;
++ if (nBandCount > 1)
++ {
++ aiDimSizes[0] = nBandCount;
++ aiDimSizes[1] = GetImageYSize();
++ aiDimSizes[2] = GetImageXSize();
++ pszString = SPrintArray(GDT_UInt32, aiDimSizes, 3, "x");
++ }
++ else
++ {
++ aiDimSizes[0] = GetImageYSize();
++ aiDimSizes[1] = GetImageXSize();
++ pszString = SPrintArray(GDT_UInt32, aiDimSizes, 2, "x");
++ }
++
++ rtnBuf = "[" + pszString + "] " + ms_DatasetName + " " + ms_DataTypeName + " (" +
++ GDALGetDataTypeName(maptr_DS->GetRasterBand(1)->GetRasterDataType()) + ")";
++
++ return rtnBuf;
++}
++
++/************************************************************************/
++/* GetNativeFormat() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the native format of a coverage.
++ *
++ * The method will return the native format of a coverage. GDAL API
++ * GDALGetDriverShortName() will be called to generate the format.
++ *
++ * @return the string of dataset native format, in forms of GDAL Formats
++ * Code. See http://gdal.org/formats_list.html for details.
++ */
++
++string AbstractDataset::GetNativeFormat()
++{
++ return ms_NativeFormat;
++}
++
++/************************************************************************/
++/* IsbGeoTransformSet() */
++/************************************************************************/
++
++/**
++ * \brief Determine whether set the affine geoTransform for a coverage.
++ *
++ * The method will return the status of the affine GeoTransform matrix.
++ *
++ * @return TRUE if set already or FALSE on failure..
++ */
++
++int AbstractDataset::IsbGeoTransformSet()
++{
++ return mb_GeoTransformSet;
++}
++
++/************************************************************************/
++/* GetNativeBBox() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the bounding box of a coverage under the native CRS.
++ *
++ * The method will fetch the bounding box of the coverage under native CRS.
++ * The sequence of values stored in array is: xmin, xmax, ymin, ymax
++ *
++ * @param bBox an existing four double buffer into which the
++ * native bounding box values will be placed.
++ */
++
++void AbstractDataset::GetNativeBBox(double bBox[])
++{
++ if (mb_GeoTransformSet)
++ {
++ bBox[0] = md_Geotransform[0];
++ bBox[1] = bBox[0] + GetImageXSize() * md_Geotransform[1];
++ bBox[3] = md_Geotransform[3];
++ bBox[2] = bBox[3] + GetImageYSize() * md_Geotransform[5];
++ }
++ else
++ {
++ bBox[0] = 0;
++ bBox[1] = maptr_DS->GetRasterXSize() - 1;
++ bBox[2] = 0;
++ bBox[3] = maptr_DS->GetRasterYSize() - 1;
++ }
++}
++
++/************************************************************************/
++/* GetGeoMinMax() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the bounding box of a coverage under EPSG:4326.
++ *
++ * The method will fetch the bounding box of the coverage under EPSG:4326
++ * CRS. The sequence of values stored in array is: xmin, xmax, ymin, ymax
++ *
++ * @param bBox an existing four double buffer into which the geographic
++ * bounding box values will be placed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr AbstractDataset::GetGeoMinMax(double geoMinMax[])
++{
++ if (!mb_GeoTransformSet)
++ {
++ SetWCS_ErrorLocator("AbstractDataset::getGeoMinMax()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to get Geo-BoundingBox coordinates");
++ return CE_Failure;
++ }
++
++ geoMinMax[0] = md_Geotransform[0];
++ geoMinMax[1] = geoMinMax[0] + GetImageXSize() * md_Geotransform[1];
++ geoMinMax[3] = md_Geotransform[3];
++ geoMinMax[2] = geoMinMax[3] + GetImageYSize() * md_Geotransform[5];
++
++
++ if (mo_NativeCRS.IsGeographic() || Find_Compare_SubStr(ms_DataTypeName, "MODIS"))//for modis data
++ {
++ geoMinMax[0] = (geoMinMax[0] >= -180.0) ? geoMinMax[0] : -180.0;
++ geoMinMax[1] = (geoMinMax[1] <= 180.0) ? geoMinMax[1] : 180.0;
++ geoMinMax[2] = (geoMinMax[2] >= -90.0) ? geoMinMax[2] : -90.0;
++ geoMinMax[3] = (geoMinMax[3] <= 90.0) ? geoMinMax[3] : 90.0;
++ return CE_None;
++ }
++
++ OGRSpatialReference oGeoSRS;
++ oGeoSRS.CopyGeogCSFrom(&mo_NativeCRS);
++
++ My2DPoint llPt(geoMinMax[0], geoMinMax[2]);
++ My2DPoint urPt(geoMinMax[1], geoMinMax[3]);
++ if (CE_None != bBox_transFormmate(mo_NativeCRS, oGeoSRS, llPt, urPt))
++ {
++ SetWCS_ErrorLocator("AbstractDataset::getGeoMinMax()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to transform bounding box coordinates to geographic coordinates.");
++ return CE_Failure;
++ }
++
++ geoMinMax[0] = llPt.mi_X;
++ geoMinMax[1] = urPt.mi_X;
++ geoMinMax[2] = llPt.mi_Y;
++ geoMinMax[3] = urPt.mi_Y;
++
++ return CE_None;
++}
++
++
++/************************************************************************/
++/* GetImageXSize() */
++/************************************************************************/
++
++/**
++ * \brief Fetch coverage width in pixels.
++ *
++ * The method will return the width of coverage in pixels. GDAL API
++ * GetRasterXSize() will be called to generate the width value.
++ *
++ * @return the width in pixels of raster bands in this coverage.
++ */
++
++int AbstractDataset::GetImageXSize()
++{
++ return maptr_DS->GetRasterXSize();
++}
++
++/************************************************************************/
++/* GetImageYSize() */
++/************************************************************************/
++
++/**
++ * \brief Fetch coverage height in pixels.
++ *
++ * The method will return the height of coverage in pixels. GDAL API
++ * GetRasterYSize() will be called to generate the height value.
++ *
++ * @return the height in pixels of raster bands in this coverage.
++ */
++int AbstractDataset::GetImageYSize()
++{
++ return maptr_DS->GetRasterYSize();
++}
++
++/************************************************************************/
++/* GetCoverageBeginTime() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the begin date/time of a coverage.
++ *
++ * The method will return the begin date/time of a coverage. For MODIS data,
++ * each granule will cover a range of time; for TRMM data, the daily data
++ * will cover a whole day, and monthly data will cover a whole month.
++ *
++ * @return the string of begin date/time corresponding to the coverage.
++ */
++
++string AbstractDataset::GetCoverageBeginTime()
++{
++ return ms_CoverageBeginTime;
++}
++
++/************************************************************************/
++/* GetCoverageBeginTime() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the end date/time of a coverage.
++ *
++ * The method will return the end date/time of a coverage. For MODIS data,
++ * each granule will cover a range of time; for TRMM data, the daily data
++ * will cover a whole day, and monthly data will cover a whole month.
++ *
++ * @return the string of end date/time corresponding to the coverage.
++ */
++
++string AbstractDataset::GetCoverageEndTime()
++{
++ return ms_CoverageEndTime;
++}
++
++/************************************************************************/
++/* getCoverageSubType() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the coverage type.
++ *
++ * The method will return the type of the coverage, such as
++ * "ReferenceableDataset" and "RectifiedDataset".
++ *
++ * @return the string of coverage type.
++ */
++
++string AbstractDataset::GetCoverageSubType()
++{
++ return ms_CoverageSubType;
++}
++
++/************************************************************************/
++/* getFieldQuantityDef() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the field units of a coverage.
++ *
++ * The method will return the field units of coverage. For example to
++ * MOD09GQ(collection name) sur_refl_b01_1(dataset name) data, units equals
++ * to reflectance.
++ *
++ * @return the string of coverage field units.
++ */
++
++string AbstractDataset::GetFieldQuantityDef()
++{
++ return ms_FieldQuantityDef;
++}
++
++/************************************************************************/
++/* GetAllowValues() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the allow values of a coverage.
++ *
++ * The method will return the valid range of a coverage. For example to
++ * MOD09GQ(collection name) sur_refl_b01_1(dataset name) data, valid_range
++ * equals to (-100, 16000).
++ *
++ * @return the string of valid range of a coverage, in the forms of "min, max".
++ */
++
++string AbstractDataset::GetAllowValues()
++{
++ return ms_AllowRanges;
++}
++
++/************************************************************************/
++/* GetISO19115Metadata() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the coverage metadata which is compliant to ISO 19115:2003
++ * - GeoGraphic information -- Metadata; and ISO 19115(2):2009 - GeoGraphic
++ * information -- Metadata -- Part 2.
++ *
++ * The method will return the metadata of a coverage based on ISO 19115
++ * and ISO 19115(2).
++ *
++ * ISO 19115:2003 defines the schema required for
++ * describing geographic information and services. It provides information
++ * about the identification, the extent, the quality, the spatial and temporal
++ * schema, spatial reference, and distribution of digital geographic data.
++ *
++ * ISO 19115-2:2009 extends the existing geographic metadata standard by
++ * defining the schema required for describing imagery and gridded data.
++ * It provides information about the properties of the measuring equipment
++ * used to acquire the data, the geometry of the measuring process employed
++ * by the equipment, and the production process used to digitize the raw data.
++ * This extension deals with metadata needed to describe the derivation of
++ * geographic information from raw data, including the properties of the
++ * measuring system, and the numerical methods and computational procedures
++ * used in the derivation. The metadata required to address coverage data in
++ * general is addressed sufficiently in the general part of ISO 19115.
++ *
++ * @return the string of metadata of a coverage.
++ */
++
++string AbstractDataset::GetISO19115Metadata()
++{
++ return ms_ISO19115Metadata;
++}
++
++/************************************************************************/
++/* GetCoverageArchiveTime() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the archive date/time of this dataset.
++ *
++ * The method will return the archive date/time of dataset (granule).
++ *
++ * @return The string of archive date/time.
++ */
++
++string AbstractDataset::GetCoverageArchiveTime()
++{
++ return ms_CoverageArchiveTime;
++}
++
++/************************************************************************/
++/* GetCoveragePlatform() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the platform name of this dataset.
++ *
++ * The method will return the platform name of dataset (granule).
++ *
++ * @return The string of platform name.
++ */
++
++string AbstractDataset::GetCoveragePlatform()
++{
++ return ms_CoveragePlatform;
++}
++
++/************************************************************************/
++/* GetCoverageInstrument() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the instrument name of this dataset.
++ *
++ * The method will return the instrument name of dataset (granule).
++ *
++ * @return The string of instrument name.
++ */
++
++string AbstractDataset::GetCoverageInstrument()
++{
++ return ms_CoverageInstrument;
++}
++
++/************************************************************************/
++/* GetCoverageInstrument() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the sensor name of this dataset.
++ *
++ * The method will return the sensor name of dataset (granule).
++ *
++ * @return The string of sensor name.
++ */
++
++string AbstractDataset::GetCoverageSensor()
++{
++ return ms_CoverageSensor;
++}
++
++/************************************************************************/
++/* GetImageBandCount() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the number of raster bands on this dataset.
++ *
++ * The method will return the number of raster bands on this dataset. GDAL
++ * API GetRasterCount() will be called to get the count number.
++ *
++ * @return the number of raster bands on this dataset.
++ */
++
++int AbstractDataset::GetImageBandCount()
++{
++ return maptr_DS->GetRasterCount();
++}
++
++/************************************************************************/
++/* getMissingValue() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the filled value (missing value) of a coverage.
++ *
++ * The method will return the filled value of a coverage.
++ *
++ * @return the value of filled value of a coverage.
++ */
++
++const double& AbstractDataset::GetMissingValue()
++{
++ return md_MissingValue;
++}
++
++/************************************************************************/
++/* GetProjectionRef() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the native projection reference of a coverage.
++ *
++ * The method will return the the native projection reference of a coverage.
++ *
++ * @return the string of the native projection reference of a coverage.
++ */
++
++string AbstractDataset::GetProjectionRef()
++{
++ char* pszProjection = NULL;
++ mo_NativeCRS.exportToWkt(&pszProjection);
++ string tmpStr = pszProjection;
++ CPLFree(pszProjection);
++
++ return tmpStr;
++}
++
++/************************************************************************/
++/* SetMetaDataList() */
++/************************************************************************/
++
++/**
++ * \brief Set the metadata list for this coverage based on dataset object.
++ *
++ * The method will set the metadata list for the coverage based on its
++ * corresponding GDALDataset object. Will be implemented in the subclasses
++ * of AbstractDataset.
++ *
++ * @param hSrc the GDALDataset object corresponding to coverage.
++ *
++ * @return CE_Failure.
++ */
++
++CPLErr AbstractDataset::SetMetaDataList(GDALDataset* hSrc)
++{
++ return CE_Failure;
++}
++
++/************************************************************************/
++/* GetMetaDataList() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the metadata list for this coverage.
++ *
++ * The method will return the metadata list for the coverage.
++ *
++ * @return the list of metadate.
++ */
++
++vector<string> AbstractDataset::GetMetaDataList()
++{
++ return mv_MetaDataList;
++}
++
++/************************************************************************/
++/* GetBandList() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the contained band list of request coverage.
++ *
++ * The method will return the contained band list of request coverage.
++ *
++ * @return the band array.
++ */
++
++vector<int> AbstractDataset::GetBandList()
++{
++ return mv_BandList;
++}
++
++/************************************************************************/
++/* getNativeCRS_URN() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the native CRS code of coverage.
++ *
++ * The method will return the native CRS code of coverage.
++ *
++ * @return the string of the URN for native CRS of coverage.
++ */
++
++string AbstractDataset::GetNativeCRS_URN()
++{
++ string urn;
++
++ if (mo_NativeCRS.IsProjected())
++ {
++ const char* nativeAuthorityName =
++ mo_NativeCRS.GetAuthorityName("PROJCS");
++ const char* nativeAuthorityCode =
++ mo_NativeCRS.GetAuthorityCode("PROJCS");
++
++ urn = "urn:ogc:def:crs:";
++
++ if (nativeAuthorityName && (EQUAL(nativeAuthorityName,"EPSG")
++ || EQUAL(nativeAuthorityName,"OGP")
++ || EQUAL(nativeAuthorityName,"OGC")))
++ urn += (string) nativeAuthorityName + (string) ":6.3:";
++ else
++ urn += "CSISS:0.0:";
++
++ if (nativeAuthorityCode)
++ urn += (string) nativeAuthorityCode;
++ else
++ urn += "80000000";
++ }
++ else if (mo_NativeCRS.IsGeographic())
++ {
++ const char* geoAuthorityName = mo_NativeCRS.GetAuthorityName("GEOGCS");
++ const char* geoAuthorityCode = mo_NativeCRS.GetAuthorityCode("GEOGCS");
++
++ urn = "urn:ogc:def:crs:";
++ if (geoAuthorityName && (EQUAL(geoAuthorityName,"EPSG")
++ || EQUAL(geoAuthorityName,"OGP")
++ || EQUAL(geoAuthorityName,"OGC")))
++ urn += (string) geoAuthorityName + (string) ":6.3:";
++ else
++ urn += "CSISS:0.0:";
++
++ if (geoAuthorityCode)
++ urn += (string) geoAuthorityCode;
++ else
++ urn += "70000000";
++ }
++ else
++ urn = "urn:ogc:def:crs:OGC:0.0:imageCRS";
++
++ return urn;
++}
++
++/************************************************************************/
++/* GetGeoCRS_URN() */
++/************************************************************************/
++
++/**
++ * \brief Fetch the Geographic CRS code of coverage.
++ *
++ * The method will return the Geographic CRS code of coverage.
++ *
++ * @return the URN for Geographic CRS of coverage.
++ */
++
++string AbstractDataset::GetGeoCRS_URN()
++{
++ string urn;
++
++ if (mo_NativeCRS.IsProjected() || mo_NativeCRS.IsGeographic())
++ {
++ const char* geoAuthorityName = mo_NativeCRS.GetAuthorityName("GEOGCS");
++ const char* geoAuthorityCode = mo_NativeCRS.GetAuthorityCode("GEOGCS");
++
++ urn = "urn:ogc:def:crs:";
++ if (geoAuthorityName && (EQUAL(geoAuthorityName,"EPSG")
++ || EQUAL(geoAuthorityName,"OGP")
++ || EQUAL(geoAuthorityName,"OGC")))
++ urn += (string) geoAuthorityName + (string) ":6.3:";
++ else
++ urn += "CSISS:0.0:";
++
++ if (geoAuthorityCode)
++ urn += (string) geoAuthorityCode;
++ else
++ urn += "70000000";
++
++ }
++ else
++ urn = "urn:ogc:def:crs:OGC:0.0:imageCRS";
++
++ return urn;
++}
++
++/************************************************************************/
++/* IsCrossingIDL() */
++/************************************************************************/
++
++/**
++ * \brief Determine whether the extend of coverage cross the International
++ * Date Line (IDL).
++ *
++ * The method will return the status of whether the extend of coverage
++ * cross the International Date Line (IDL).
++ *
++ * @return the TRUE of the coverage extent cross the IDL, otherwise FALSE.
++ */
++
++int AbstractDataset::IsCrossingIDL()
++{
++ double bboxArray[4];
++ GetNativeBBox(bboxArray);
++
++ OGRSpatialReference latlonSRS;
++ latlonSRS.SetWellKnownGeogCS("WGS84");
++ My2DPoint llPtex(bboxArray[0], bboxArray[2]);
++ My2DPoint urPtex(bboxArray[1], bboxArray[3]);
++ bBox_transFormmate(mo_NativeCRS, latlonSRS, llPtex, urPtex);
++
++ int bCrossCenter = false;
++ if(urPtex.mi_X < 0 && llPtex.mi_X > 0)
++ bCrossCenter = true;
++
++ return bCrossCenter;
++}
++
++/************************************************************************/
++/* GetSuggestedWarpResolution() */
++/************************************************************************/
++
++/**
++ * \brief Get the suggested warp option, method 1.
++ *
++ * @return CE_Failure if an error occurs, otherwise CE_None.
++ */
++
++CPLErr AbstractDataset::GetSuggestedWarpResolution( OGRSpatialReference& dstCRS,
++ double adfDstGeoTransform[],
++ int &nPixels,
++ int &nLines)
++{
++ if (!dstCRS.IsProjected() && !dstCRS.IsGeographic())
++ {
++ adfDstGeoTransform[0] = 0;
++ adfDstGeoTransform[1] = 1;
++ adfDstGeoTransform[2] = 0;
++ adfDstGeoTransform[3] = 0;
++ adfDstGeoTransform[4] = 0;
++ adfDstGeoTransform[5] = 1;
++
++ nPixels = GetImageXSize();
++ nLines = GetImageYSize();
++
++ }
++ else if (dstCRS.IsSame(&mo_NativeCRS))
++ {
++ memcpy(adfDstGeoTransform, md_Geotransform, sizeof(double) * 6);
++ nPixels = GetImageXSize();
++ nLines = GetImageYSize();
++ }
++ else
++ {
++ char *pszDstWKT;
++ dstCRS.exportToWkt(&pszDstWKT);
++ char *pszSrcWKT;
++ mo_NativeCRS.exportToWkt(&pszSrcWKT);
++
++ void *hTransformArg = GDALCreateGenImgProjTransformer(maptr_DS.get(),
++ (const char*) pszSrcWKT, NULL, (const char*) pszDstWKT, TRUE, 1000.0, 0);
++ OGRFree(pszDstWKT);
++ OGRFree(pszSrcWKT);
++ if (hTransformArg == NULL)
++ {
++ SetWCS_ErrorLocator("AbstractDataset::GetSuggestedWarpResolution()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Create GDAL GenImgProjTransformer.");
++
++ return CE_Failure;
++ }
++ /* -------------------------------------------------------------------- */
++ /* Get approximate output definition. */
++ /* -------------------------------------------------------------------- */
++ if (GDALSuggestedWarpOutput(maptr_DS.get(), GDALGenImgProjTransform,
++ hTransformArg, adfDstGeoTransform, &nPixels, &nLines) != CE_None)
++ {
++ SetWCS_ErrorLocator("AbstractDataset::GetSuggestedWarpResolution()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Computing Output Resolution.");
++
++ return CE_Failure;
++ }
++
++ GDALDestroyGenImgProjTransformer(hTransformArg);
++ }
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetSuggestedWarpResolution2() */
++/************************************************************************/
++
++/**
++ * \brief Get the suggested warp option, method 2.
++ *
++ * @return CE_Failure if an error occurs, otherwise CE_None.
++ */
++
++CPLErr AbstractDataset::GetSuggestedWarpResolution2(OGRSpatialReference& dstCRS,
++ double adfDstGeoTransform[],
++ int &nPixels,
++ int &nLines)
++{
++ if (dstCRS.IsLocal())
++ {
++ adfDstGeoTransform[0] = 0;
++ adfDstGeoTransform[1] = 1;
++ adfDstGeoTransform[2] = 0;
++ adfDstGeoTransform[3] = 0;
++ adfDstGeoTransform[4] = 0;
++ adfDstGeoTransform[5] = 1;
++
++ nPixels = GetImageXSize();
++ nLines = GetImageYSize();
++ }
++ else if (dstCRS.IsSame(&mo_NativeCRS))
++ {
++ memcpy(adfDstGeoTransform, md_Geotransform, sizeof(double) * 6);
++ nPixels = GetImageXSize();
++ nLines = GetImageYSize();
++ }
++ else
++ {
++ double bboxArray[4];
++ GetNativeBBox(bboxArray);
++
++ My2DPoint llPt(bboxArray[0], bboxArray[2]);
++ My2DPoint urPt(bboxArray[1], bboxArray[3]);
++ if (CE_None != bBox_transFormmate(mo_NativeCRS, dstCRS, llPt, urPt))
++ {
++ SetWCS_ErrorLocator("AbstractDataset::GetSuggestedWarpResolution2()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Transform bounding box Coordinate.");
++ return CE_Failure;
++ }
++
++ double xRes, yRes;
++ if(IsCrossingIDL())
++ {
++ yRes = (urPt.mi_Y - llPt.mi_Y) / GetImageYSize();
++ xRes = fabs((llPt.mi_X - urPt.mi_X) / GetImageXSize());
++ nLines = (urPt.mi_Y - llPt.mi_Y) / yRes + 0.5;
++ nPixels = fabs((llPt.mi_X - urPt.mi_X) / xRes + 0.5);
++ }else
++ {
++ xRes = (urPt.mi_X - llPt.mi_X) / GetImageXSize();
++ yRes = (urPt.mi_Y - llPt.mi_Y) / GetImageYSize();
++ nPixels = (urPt.mi_X - llPt.mi_X) / xRes + 0.5;
++ nLines = (urPt.mi_Y - llPt.mi_Y) / yRes + 0.5;
++ }
++
++ xRes = MIN(xRes,yRes);
++ yRes = MIN(xRes,yRes);
++
++ adfDstGeoTransform[0] = llPt.mi_X;
++ adfDstGeoTransform[1] = xRes;
++ adfDstGeoTransform[2] = 0;
++ adfDstGeoTransform[3] = urPt.mi_Y;
++ adfDstGeoTransform[4] = 0;
++ adfDstGeoTransform[5] = -yRes;
++ }
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* DatasetWarper() */
++/************************************************************************/
++
++/**
++ * Wrap the dataset to a GDALDataset object based on input parameters.
++ *
++ * @return the warpped GDALDataset object.
++ */
++/************************************************************************/
++/* DatasetWarper() */
++/************************************************************************/
++
++/**
++ * \brief Wrap the dataset to a GDALDataset object based on input parameters.
++ *
++ * @return GDALDatset object.
++ */
++
++GDALDataset* AbstractDataset::DatasetWarper(int& IsRefDS,
++ OGRSpatialReference& dstCRS,
++ int& iDstRasterXsize,
++ int& iDstRasterYsize,
++ double pDstGeoTransform[],
++ GDALResampleAlg eResampleAlg)
++{
++ OGRSpatialReference locCRS=dstCRS;
++ if (dstCRS.IsLocal())
++ locCRS=mo_NativeCRS;
++
++ if((mo_NativeCRS.IsSame(&locCRS) &&
++ iDstRasterXsize == maptr_DS->GetRasterXSize() &&
++ iDstRasterYsize == maptr_DS->GetRasterYSize())&&
++ CPLIsEqual(md_Geotransform[0],pDstGeoTransform[0])&&
++ CPLIsEqual(md_Geotransform[1],pDstGeoTransform[1])&&
++ CPLIsEqual(md_Geotransform[3],pDstGeoTransform[3])&&
++ CPLIsEqual(md_Geotransform[5],pDstGeoTransform[5]))
++ {
++ IsRefDS = TRUE;
++ return maptr_DS.get();
++ }
++
++ char *sDstCRS_WKT;
++ locCRS.exportToWkt(&sDstCRS_WKT);
++
++ /* Create a memory data-set for re-projection */
++ GDALDriverH poDriver = GDALGetDriverByName("MEM");
++
++ int nBand = maptr_DS->GetRasterCount();
++ GDALDataset* hMemDS = (GDALDataset*) GDALCreate(poDriver, "", iDstRasterXsize,
++ iDstRasterYsize, nBand, GDALGetRasterDataType(maptr_DS->GetRasterBand(1)), NULL);
++ if (NULL == hMemDS)
++ {
++ GDALClose(poDriver);
++ OGRFree(sDstCRS_WKT);
++ return NULL;
++ }
++
++ hMemDS->SetProjection(sDstCRS_WKT);
++ hMemDS->SetGeoTransform(pDstGeoTransform);
++
++ for (int i = 1; i <= nBand; i++)
++ {
++ hMemDS->GetRasterBand(i)->SetNoDataValue(md_MissingValue);
++ }
++
++ /* -------------------------------------------------------------------- */
++ /* Perform the re-projection. */
++ /* -------------------------------------------------------------------- */
++ char *srcWKT;
++ mo_NativeCRS.exportToWkt(&srcWKT);
++ if (CE_None != GDALReprojectImage(maptr_DS.get(), srcWKT, hMemDS,
++ sDstCRS_WKT, eResampleAlg, 0, 0.125, NULL, NULL, NULL))
++ {
++ GDALClose(poDriver);
++ GDALClose(GDALDatasetH(hMemDS));
++ OGRFree(sDstCRS_WKT);
++ OGRFree(srcWKT);
++ return NULL;
++ }
++ IsRefDS = FALSE;
++ OGRFree(sDstCRS_WKT);
++ OGRFree(srcWKT);
++
++ return hMemDS;
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/5c/5c3da4f5eaa9825bf8d68c07943d2343d2cf05e2.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/5c/5c3da4f5eaa9825bf8d68c07943d2343d2cf05e2.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/5c/5c3da4f5eaa9825bf8d68c07943d2343d2cf05e2.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/5c/5c3da4f5eaa9825bf8d68c07943d2343d2cf05e2.svn-base 2014-03-03 15:47:37.810232939 +0100
+@@ -0,0 +1,150 @@
++/******************************************************************************
++ * $Id: AbstractDataset.h 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: AbstractDataset class definition
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 ABSTRACTDATASET_H_
++#define ABSTRACTDATASET_H_
++
++#include <vector>
++#include <memory>
++
++#include <gdal.h>
++#include <gdal_priv.h>
++#include <gdalwarper.h>
++#include <ogrsf_frmts.h>
++#include <ogr_spatialref.h>
++#include <cpl_conv.h>
++#include <cpl_minixml.h>
++#include <vrtdataset.h>
++
++#include "wcsUtil.h"
++
++using namespace std;
++
++/* ******************************************************************** */
++/* AbstractDataset */
++/* ******************************************************************** */
++
++//! Abstract dataset model definition. Based on GDAL dataset model.
++class AbstractDataset {
++
++protected:
++ auto_ptr<GDALDataset> maptr_DS;
++
++ // Coverage Information Related
++ string ms_CoverageID;
++ string ms_CoverageBeginTime;
++ string ms_CoverageEndTime;
++ string ms_CoverageSubType;
++ string ms_CoverageArchiveTime;
++ string ms_CoveragePlatform;
++ string ms_CoverageInstrument;
++ string ms_CoverageSensor;
++ string ms_SrcFilename;
++ string ms_DatasetName;
++ string ms_DataTypeName;
++ string ms_NativeFormat;
++ string ms_FieldQuantityDef;
++ string ms_AllowRanges;
++ string ms_ISO19115Metadata;
++
++ vector<int> mv_BandList;
++ vector<string> mv_MetaDataList;
++
++ double md_Geotransform[6];
++ double md_GeoMinMax[4]; // Order: xmin, xmax, ymin, ymax
++ double md_MissingValue;
++
++ int mb_GeoTransformSet;
++ int mb_IsVirtualDS;
++
++ OGRSpatialReference mo_NativeCRS;
++
++protected:
++ AbstractDataset();
++ virtual CPLErr SetNativeCRS();
++ virtual CPLErr SetGeoTransform();
++ virtual CPLErr SetGDALDataset(const int isSimple = 0);
++ virtual CPLErr SetMetaDataList(GDALDataset*);
++
++public:
++ AbstractDataset(const string&, vector<int> &);
++ virtual ~AbstractDataset();
++
++ GDALDataset* GetGDALDataset();
++
++ // Virtual Functions Definition
++ virtual CPLErr InitialDataset(const int isSimple = 0);
++
++ // Fetch Function Related
++ const OGRSpatialReference& GetNativeCRS();
++ const double& GetMissingValue();
++ int GetGeoTransform(double geoTrans[]);
++ vector<string> GetMetaDataList();
++ vector<int> GetBandList();
++ void GetNativeBBox(double bBox[]);
++ CPLErr GetGeoMinMax(double geoMinMax[]);
++
++ int GetImageBandCount();
++ int GetImageXSize();
++ int GetImageYSize();
++ string GetResourceFileName();
++ string GetDatasetName();
++ string GetDataTypeName();
++ string GetNativeFormat();
++ string GetCoverageID();
++ string GetDatasetDescription();
++ string GetNativeCRS_URN();
++ string GetGeoCRS_URN();
++ string GetProjectionRef();
++ string GetCoverageBeginTime();
++ string GetCoverageEndTime();
++ string GetCoverageSubType();
++ string GetFieldQuantityDef();
++ string GetAllowValues();
++ string GetISO19115Metadata();
++ string GetCoverageArchiveTime();
++ string GetCoveragePlatform();
++ string GetCoverageInstrument();
++ string GetCoverageSensor();
++
++ // Fetch Variables Status Related
++ int IsbGeoTransformSet();
++ int IsCrossingIDL();
++
++ CPLErr GetSuggestedWarpResolution(OGRSpatialReference& dstCRS, double adfDstGeoTransform[], int &nPixels,
++ int &nLines);
++ CPLErr GetSuggestedWarpResolution2(OGRSpatialReference& dstCRS, double adfDstGeoTransform[], int &nPixels,
++ int &nLines);
++
++ GDALDataset* DatasetWarper(int& IsRefDS, OGRSpatialReference& dstCRS, int& iDstRasterXsize, int& iDstRasterYsize,
++ double pDstGeoTransform[], GDALResampleAlg eResampleAlg = GRA_NearestNeighbour);
++};
++
++#endif /*ABSTRACTDATASET_H_*/
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/60/603732a6a8a375d944ca25f03c7720f3d4f8e069.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/60/603732a6a8a375d944ca25f03c7720f3d4f8e069.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/60/603732a6a8a375d944ca25f03c7720f3d4f8e069.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/60/603732a6a8a375d944ca25f03c7720f3d4f8e069.svn-base 2014-03-03 15:47:37.593566281 +0100
+@@ -0,0 +1,381 @@
++/******************************************************************************\r
++ * $Id: wcsUtil.h 2011-07-19 16:24:00Z $\r
++ *\r
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)\r
++ * for Earth Observation: Open Source Reference Implementation\r
++ * Purpose: WCS Utility Function definition\r
++ * Author: Yuanzheng Shao, yshao3@gmu.edu\r
++ *\r
++ ******************************************************************************\r
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>\r
++ *\r
++ * Permission is hereby granted, free of charge, to any person obtaining a\r
++ * copy of this software and associated documentation files (the "Software"),\r
++ * to deal in the Software without restriction, including without limitation\r
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
++ * and/or sell copies of the Software, and to permit persons to whom the\r
++ * Software is furnished to do so, subject to the following conditions:\r
++ *\r
++ * The above copyright notice and this permission notice shall be included\r
++ * in all copies or substantial portions of the Software.\r
++ *\r
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
++ * DEALINGS IN THE SOFTWARE.\r
++ ****************************************************************************/\r
++\r
++#ifndef WCSUTIL_H_\r
++#define WCSUTIL_H_\r
++\r
++#include <iostream>\r
++#include <fstream>\r
++#include <sstream>\r
++#include <vector>\r
++#include <stdlib.h>\r
++#include <time.h>\r
++\r
++#include <cpl_string.h>\r
++#include "wcs_error.h"\r
++#include "BoundingBox.h"\r
++\r
++using namespace std;\r
++\r
++#ifndef EQUAL\r
++#if defined(WIN32) || defined(WIN32CE)\r
++# define EQUALN(a,b,n) (strnicmp(a,b,n)==0)\r
++# define EQUAL(a,b) (stricmp(a,b)==0)\r
++#else\r
++# define EQUALN(a,b,n) (strncasecmp(a,b,n)==0)\r
++# define EQUAL(a,b) (strcasecmp(a,b)==0)\r
++#endif\r
++#endif\r
++\r
++#ifndef TRUE\r
++#define TRUE 1\r
++#endif\r
++#ifndef FALSE\r
++#define FALSE 0\r
++#endif\r
++\r
++#ifndef NULL\r
++#define NULL 0\r
++#endif\r
++\r
++#ifdef WINDOWS\r
++#define DELIMITER "\\"\r
++#else\r
++#define DELIMITER "/"\r
++#endif\r
++\r
++const int SHORT_NAME_LEN = 128;\r
++const int MAX_NAME_LEN = 512;\r
++const int MAX_LIST_LEN = 1024;\r
++const int MAX_LINE_LEN = 65536;\r
++\r
++\r
++// -----------------------------------------------------------------------\r
++// CGI (Common Gateway Interface) related class and functions\r
++// -----------------------------------------------------------------------\r
++enum CGI_METHOD_FLAG\r
++{\r
++ UN_KNOWN, HTTP_GET, HTTP_XML_POST\r
++};\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* WCSCGI */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \class WCSCGI "wcsUtil.h"\r
++ *\r
++ * WCSCGI class is used to acquire WCS request, both GET and POST method\r
++ * are supported.\r
++ */\r
++\r
++class WCSCGI\r
++{\r
++private:\r
++ string ms_CGIContent;\r
++ CGI_METHOD_FLAG me_CGIMethod;\r
++\r
++public:\r
++ WCSCGI()\r
++ {\r
++ me_CGIMethod = UN_KNOWN;\r
++ }\r
++\r
++ CPLErr Run();\r
++\r
++ string GetRqstContent()\r
++ {\r
++ return ms_CGIContent;\r
++ }\r
++\r
++ CGI_METHOD_FLAG GetCGImethod()\r
++ {\r
++ return me_CGIMethod;\r
++ }\r
++};\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* StringList */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++\r
++class StringList\r
++{\r
++private:\r
++ vector<string> strings;\r
++\r
++public:\r
++ StringList(const string& sstrings, const char delimiter);\r
++ StringList(const string& sstrings, const string& delimiters);\r
++ StringList(){ }\r
++\r
++ int indexof(string qstr);\r
++\r
++ void add(string newstr)\r
++ {\r
++ strings.push_back(newstr);\r
++ }\r
++\r
++ void clear()\r
++ {\r
++ strings.clear();\r
++ }\r
++\r
++ int size()\r
++ {\r
++ return strings.size();\r
++ }\r
++\r
++ string& operator [](int index)\r
++ {\r
++ return strings[index];\r
++ }\r
++\r
++ void append(StringList & s);\r
++ void append(const string sstrings, const char delimiter);\r
++ void append(const string sstrings, const string& delimiters);\r
++\r
++ string toString()\r
++ {\r
++ string s = "";\r
++ for (int i = 0; i < size(); i++)\r
++ s += strings[i];\r
++ return s;\r
++ }\r
++\r
++ string toString(const char delimiter)\r
++ {\r
++ string s = "";\r
++ for (int i = 0; i < size(); i++)\r
++ s += strings[i] + delimiter;\r
++ return s;\r
++ }\r
++\r
++ string toString(const string& delimiters)\r
++ {\r
++ string s = "";\r
++ for (int i = 0; i < size(); i++)\r
++ s += strings[i] + delimiters;\r
++ return s;\r
++ }\r
++};\r
++\r
++class S2C\r
++{\r
++\r
++private:\r
++ char buf[MAX_LINE_LEN];\r
++\r
++public:\r
++ S2C(string s)\r
++ {\r
++ s.copy(buf, string::npos);\r
++ buf[s.size()] = 0;\r
++ }\r
++\r
++ char * c_str()\r
++ {\r
++ return buf;\r
++ }\r
++\r
++};\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* KVP */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++\r
++class KVP\r
++{\r
++public:\r
++ string name, value;\r
++\r
++ KVP& operator =(const KVP &id)\r
++ {\r
++ name = id.name;\r
++ value = id.value;\r
++ return *this;\r
++ }\r
++\r
++ KVP& operator =(const KVP *pid)\r
++ {\r
++ name = pid->name;\r
++ value = pid->value;\r
++ return *this;\r
++ }\r
++\r
++ KVP(string n, string v) :\r
++ name(n), value(v)\r
++ {\r
++ }\r
++\r
++ KVP(string namevaluepair);\r
++};\r
++\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* KVPsReader */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++\r
++class KVPsReader\r
++{\r
++protected:\r
++ vector<KVP> m_kvps;\r
++\r
++public:\r
++ KVPsReader()\r
++ {\r
++ }\r
++\r
++ ~KVPsReader()\r
++ {\r
++ }\r
++\r
++ KVPsReader(const string& urlStr, const char &tok);\r
++\r
++ KVP& operator [](const int index)\r
++ {\r
++ return m_kvps[index];\r
++ }\r
++\r
++ int size()\r
++ {\r
++ return m_kvps.size();\r
++ }\r
++\r
++ string getValue(const string &keyname);\r
++ string getValue(const string &keyname, const string &defaultvalue);\r
++ vector<string> getValues(const string &keyname);\r
++};\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* CFGReader */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++class CFGReader\r
++{\r
++protected:\r
++ vector<KVP> kvps;\r
++\r
++public:\r
++ CFGReader(const string &configfilename);\r
++\r
++ KVP& operator [](const int index)\r
++ {\r
++ return kvps[index];\r
++ }\r
++\r
++ int size()\r
++ {\r
++ return kvps.size();\r
++ }\r
++\r
++ string getValue(const string &keyname);\r
++ string getValue(const string &keyname, const string &defaultvalue);\r
++};\r
++\r
++\r
++// -----------------------------------------------------------------------\r
++// Extra Template Functions\r
++// Exchange() --- used to exchange values\r
++// convertToString() --- convert value to string\r
++// convertFromString --- convert string to values\r
++// -----------------------------------------------------------------------\r
++template<class T>\r
++static void Exchange(T & a, T & b)\r
++{\r
++ T t;\r
++ t = a;\r
++ a = b;\r
++ b = t;\r
++}\r
++\r
++template <class T>\r
++static string convertToString(T &value)\r
++{\r
++ stringstream ss;\r
++ ss<<value;\r
++ string rtnstr = ss.str();\r
++ return rtnstr;\r
++}\r
++\r
++template <class T>\r
++static void convertFromString(T &value, const string& s)\r
++{\r
++ stringstream ss(s);\r
++ ss>>value;\r
++}\r
++\r
++\r
++// -----------------------------------------------------------------------\r
++// Extra Utility Functions\r
++// -----------------------------------------------------------------------\r
++CPL_C_START\r
++\r
++// String Operation Related\r
++int CPL_DLL CPL_STDCALL CsvburstCpp(const std::string& line, std::vector<std::string> &strSet, const char tok);\r
++int CPL_DLL CPL_STDCALL CsvburstComplexCpp(const string& line, vector<string> &strSet, const char* tok);\r
++int CPL_DLL CPL_STDCALL Find_Compare_SubStr(string line, string sub);\r
++void CPL_DLL CPL_STDCALL Strslip(const char* str, const char* arrStr[], const char leftdlm, const char rightdlm);\r
++string CPL_DLL CPL_STDCALL StrReplace(string& str, const string oldSubStr, const string newStr);\r
++string CPL_DLL CPL_STDCALL SPrintArray(GDALDataType eDataType, const void *paDataArray, int nValues, const char *pszDelimiter);\r
++string CPL_DLL CPL_STDCALL StrTrimHead(const string &str);\r
++string CPL_DLL CPL_STDCALL StrTrimTail(const string &str);\r
++string CPL_DLL CPL_STDCALL StrTrims(const std::string&, const char*);\r
++string CPL_DLL CPL_STDCALL StrTrim(const string &str);\r
++\r
++// Date Time Operation Related\r
++int CPL_DLL CPL_STDCALL CompareDateTime_GreaterThan(string time1, string time2);\r
++int CPL_DLL CPL_STDCALL ConvertDateTimeToSeconds(string datetime);\r
++string CPL_DLL CPL_STDCALL GetTimeString(int code);\r
++\r
++// Directory Operation Related\r
++CPLErr CPL_DLL CPL_STDCALL GetFileNameList(char* dir, std::vector<string> &strList);\r
++string CPL_DLL CPL_STDCALL MakeTempFile(string dir, string covID, string suffix);\r
++string CPL_DLL CPL_STDCALL GetUUID();\r
++\r
++// Request Parser Operation\r
++void CPL_DLL CPL_STDCALL GetSubSetTime(const string& subsetstr, vector<string> &subsetvalue);\r
++string CPL_DLL CPL_STDCALL GetSubSetLatLon(const string& subsetstr, vector<double> &subsetvalue);\r
++string CPL_DLL CPL_STDCALL GetSingleValue(const string& subsetstr);\r
++\r
++CPLErr CPL_DLL CPL_STDCALL GetTRMMBandList(string start, string end, std::vector<int> &bandList);\r
++void CPL_DLL CPL_STDCALL GetCornerPoints(const GDAL_GCP* &pGCPList, const int &nGCPs, My2DPoint& lowLeft, My2DPoint& upRight);\r
++\r
++CPL_C_END\r
++\r
++#endif /*WCSUTIL_H_*/\r
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/6e/6e49290949c78333bcb94209de0ac91b27fca46c.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/6e/6e49290949c78333bcb94209de0ac91b27fca46c.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/6e/6e49290949c78333bcb94209de0ac91b27fca46c.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/6e/6e49290949c78333bcb94209de0ac91b27fca46c.svn-base 2014-03-03 15:47:38.040232929 +0100
+@@ -0,0 +1,209 @@
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2002,2003 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++// (c) COPYRIGHT URI/MIT 1999
++// Please read the full copyright statement in the file COPYRIGHT_URI.
++//
++// Authors:
++// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
++
++
++// These functions are used by the CE evaluator
++//
++// 1/15/99 jhrg
++
++#include "config.h"
++
++#include <limits.h>
++
++#if 0
++#include <cstdlib> // used by strtod()
++#include <cerrno>
++#include <cmath>
++#endif
++#include <iostream>
++#if 0
++#include <vector>
++#include <algorithm>
++#endif
++
++// #include <gdal.h>
++// #include <gdal_priv.h>
++
++#define DODS_DEBUG
++
++#include "BaseType.h"
++
++#include "Str.h"
++#include "Array.h"
++#include "Grid.h"
++
++#include "Error.h"
++#include "debug.h"
++
++#include "DAP_Dataset.h"
++#include "reproj_functions.h"
++
++// We wrapped VC++ 6.x strtod() to account for a short coming
++// in that function in regards to "NaN". I don't know if this
++// still applies in more recent versions of that product.
++// ROM - 12/2007
++#ifdef WIN32
++#include <limits>
++double w32strtod(const char *, char **);
++#endif
++
++using namespace std;
++//using namespace libdap;
++
++namespace libdap {
++
++/**
++ * @todo The lat and lon arrays are passed in, but there's an assumption that the
++ * source data array and the two lat and lon arrays are the same shape. But the
++ * code does not actually test that.
++ *
++ * @todo Enable multiple bands paired with just the two lat/lon arrays? Not sure
++ * if that is a good idea...
++ */
++void function_swath2array(int argc, BaseType * argv[], DDS &, BaseType **btpp)
++{
++ DBG(cerr << "Entering function_swath2array..." << endl);
++
++ // Use the same documentation for both swath2array and swath2grid
++ string info = string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
++ + "<function name=\"swath2array\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid\">\n"
++ + "</function>\n";
++
++ if (argc == 0) {
++ Str *response = new Str("info");
++ response->set_value(info);
++ *btpp = response;
++ return;
++ }
++
++ // TODO Add optional fourth arg that lets the caller say which datum to use;
++ // default to WGS84
++ if (argc != 3)
++ throw Error("The function swath2array() requires three arguments. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *src = dynamic_cast<Array*>(argv[0]);
++ if (!src)
++ throw Error("The first argument to swath2array() must be a data array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *lat = dynamic_cast<Array*>(argv[1]);
++ if (!lat)
++ throw Error("The second argument to swath2array() must be a latitude array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *lon = dynamic_cast<Array*>(argv[2]);
++ if (!lon)
++ throw Error("The third argument to swath2array() must be a longitude array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ // The args passed into the function using argv[] are deleted after the call.
++
++ DAP_Dataset ds(src, lat, lon);
++
++ try {
++ ds.InitialDataset(0);
++
++ *btpp = ds.GetDAPArray();
++ }
++ catch (Error &e) {
++ DBG(cerr << "caught Error: " << e.get_error_message() << endl);
++ throw e;
++ }
++ catch(...) {
++ DBG(cerr << "caught unknown exception" << endl);
++ throw;
++ }
++
++ return;
++}
++
++/**
++ * @todo The lat and lon arrays are passed in, but there's an assumption that the
++ * source data array and the two lat and lon arrays are the same shape. But the
++ * code does not actually test that.
++ *
++ * @todo Enable multiple bands paired with just the two lat/lon arrays? Not sure
++ * if that is a good idea...
++ */
++void function_swath2grid(int argc, BaseType * argv[], DDS &, BaseType **btpp)
++{
++ DBG(cerr << "Entering function_swath2grid..." << endl);
++
++ string info = string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
++ + "<function name=\"swath2grid\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid\">\n"
++ + "</function>\n";
++
++ if (argc == 0) {
++ Str *response = new Str("info");
++ response->set_value(info);
++ *btpp = response;
++ return;
++ }
++
++ // TODO Add optional fourth arg that lets the caller say which datum to use;
++ // default to WGS84
++ if (argc != 3)
++ throw Error("The function swath2grid() requires three arguments. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *src = dynamic_cast<Array*>(argv[0]);
++ if (!src)
++ throw Error("The first argument to swath2grid() must be a data array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *lat = dynamic_cast<Array*>(argv[1]);
++ if (!lat)
++ throw Error("The second argument to swath2grid() must be a latitude array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ Array *lon = dynamic_cast<Array*>(argv[2]);
++ if (!lon)
++ throw Error("The third argument to swath2grid() must be a longitude array. See http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++
++ // The args passed into the function using argv[] are deleted after the call.
++
++ DAP_Dataset ds(src, lat, lon);
++
++ try {
++ ds.InitialDataset(0);
++
++ *btpp = ds.GetDAPGrid();
++ }
++ catch (Error &e) {
++ DBG(cerr << "caught Error: " << e.get_error_message() << endl);
++ throw e;
++ }
++ catch(...) {
++ DBG(cerr << "caught unknown exception" << endl);
++ throw;
++ }
++
++ return;
++}
++
++
++
++
++
++} // namespace libdap
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/70/709a0a2aa7313d6e4d90f84b63deb2616bfe3284.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/70/709a0a2aa7313d6e4d90f84b63deb2616bfe3284.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/70/709a0a2aa7313d6e4d90f84b63deb2616bfe3284.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/70/709a0a2aa7313d6e4d90f84b63deb2616bfe3284.svn-base 2014-03-03 15:47:38.036899596 +0100
+@@ -0,0 +1,1278 @@
++/******************************************************************************\r
++ * $Id: wcsUtil.cpp 2011-07-19 16:24:00Z $\r
++ *\r
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)\r
++ * for Earth Observation: Open Source Reference Implementation\r
++ * Purpose: WCS Utility Function implementation\r
++ * Author: Yuanzheng Shao, yshao3@gmu.edu\r
++ *\r
++ ******************************************************************************\r
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>\r
++ *\r
++ * Permission is hereby granted, free of charge, to any person obtaining a\r
++ * copy of this software and associated documentation files (the "Software"),\r
++ * to deal in the Software without restriction, including without limitation\r
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
++ * and/or sell copies of the Software, and to permit persons to whom the\r
++ * Software is furnished to do so, subject to the following conditions:\r
++ *\r
++ * The above copyright notice and this permission notice shall be included\r
++ * in all copies or substantial portions of the Software.\r
++ *\r
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
++ * DEALINGS IN THE SOFTWARE.\r
++ ****************************************************************************/\r
++\r
++#include <unistd.h>\r
++#include <dirent.h>\r
++#include <sys/stat.h>\r
++#include <stdexcept>\r
++#include <uuid/uuid.h>\r
++#include "wcsUtil.h"\r
++//#include "mfhdf.h"\r
++\r
++/************************************************************************/\r
++/* GetUUID() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Used to get UUID string.\r
++ *\r
++ * This method will return a UUID, such as: cd32eb56-412c-11e0-9cce-67750f871b94\r
++ *\r
++ * @return A generated UUID string.\r
++ */\r
++\r
++string CPL_STDCALL GetUUID()\r
++{\r
++ uuid_t uuid;\r
++ uuid_generate(uuid);\r
++ char uuidstr[36];\r
++ uuid_unparse(uuid, uuidstr);\r
++ return uuidstr;\r
++}\r
++\r
++/************************************************************************/\r
++/* SPrintArray() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Print a string based on coverage realted parameters.\r
++ *\r
++ * This method will return a UUID, such as: cd32eb56-412c-11e0-9cce-67750f871b94\r
++ *\r
++ * @return A generated UUID string.\r
++ */\r
++\r
++string CPL_STDCALL SPrintArray(GDALDataType eDataType, const void *paDataArray, int nValues, const char *pszDelimiter)\r
++{\r
++ char *pszString, *pszField;\r
++ int i, iFieldSize, iStringSize;\r
++\r
++ iFieldSize = 32 + strlen(pszDelimiter);\r
++ pszField = (char *) CPLMalloc(iFieldSize + 1);\r
++ iStringSize = nValues * iFieldSize + 1;\r
++ pszString = (char *) CPLMalloc(iStringSize);\r
++ memset(pszString, 0, iStringSize);\r
++ for (i = 0; i < nValues; i++)\r
++ {\r
++ switch (eDataType)\r
++ {\r
++ case GDT_Byte:\r
++ sprintf(pszField, "%d%s", ((GByte *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_UInt16:\r
++ sprintf(pszField, "%u%s", ((GUInt16 *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_Int16:\r
++ default:\r
++ sprintf(pszField, "%d%s", ((GInt16 *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_UInt32:\r
++ sprintf(pszField, "%u%s", ((GUInt32 *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_Int32:\r
++ sprintf(pszField, "%d%s", ((GInt32 *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_Float32:\r
++ sprintf(pszField, "%.7g%s", ((float *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_Float64:\r
++ sprintf(pszField, "%.15g%s", ((double *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ }\r
++ strcat(pszString, pszField);\r
++ }\r
++\r
++ CPLFree(pszField);\r
++\r
++ return string(pszString);\r
++}\r
++\r
++/************************************************************************/\r
++/* StrTrimHead() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Trim s string's head.\r
++ *\r
++ * This method will trim a string's head, remove the sapce and line break\r
++ * in the head of a string.\r
++ *\r
++ * @param str The string to be processed.\r
++ *\r
++ * @return A head-trimmed string.\r
++ */\r
++\r
++string CPL_STDCALL StrTrimHead(const string &str)\r
++{\r
++ string::size_type p = 0;\r
++ /* leading space? */\r
++ while ((p < str.size()) && (str[p] == ' ' || str[p] == '\t' || str[p] == 13 || str[p] == 10))\r
++ p++;\r
++ if (p >= str.size())\r
++ return "";\r
++ else\r
++ return str.substr(p);\r
++}\r
++\r
++/************************************************************************/\r
++/* StrTrimTail() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Trim s string's tail.\r
++ *\r
++ * This method will trim a string's tail, remove the sapce and line break\r
++ * in the tail of a string.\r
++ *\r
++ * @param str The string to be processed.\r
++ *\r
++ * @return A tail-trimmed string.\r
++ */\r
++\r
++string CPL_STDCALL StrTrimTail(const string &str)\r
++{\r
++ string::size_type p = str.size() - 1;\r
++ while (p >= 0 && (str[p] == ' ' || str[p] == '\t' || str[p] == 13 || str[p] == 10))\r
++ p--;\r
++ if (p < 0)\r
++ return "";\r
++ else\r
++ return str.substr(0, p + 1);\r
++}\r
++\r
++/************************************************************************/\r
++/* StrTrim() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Trim s string's head and tail.\r
++ *\r
++ * This method will trim a string's head and tail, remove the sapce and\r
++ * line break in both the head and end of a string.\r
++ *\r
++ * @param str The string to be processed.\r
++ *\r
++ * @return A trimmed string.\r
++ */\r
++\r
++string CPL_STDCALL StrTrim(const string &str)\r
++{\r
++ string s = StrTrimTail(str);\r
++ return StrTrimHead(s);\r
++}\r
++\r
++/************************************************************************/\r
++/* StrTrims() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Trim s string's head and tail based on delimiter string.\r
++ *\r
++ * This method will trim a string's head and tail based on delimiter\r
++ * string, and return the trimmed string.\r
++ *\r
++ * @param srcStr The string to be processed.\r
++ *\r
++ * @param tok The delimiter string used to trim the string.\r
++ *\r
++ * @return A trimmed string.\r
++ */\r
++\r
++string CPL_STDCALL StrTrims(const string& srcStr, const char* tok)\r
++{\r
++ if (srcStr.empty())\r
++ return srcStr;\r
++\r
++ string::size_type beginIdx, endIdx;\r
++ beginIdx = srcStr.find_first_not_of(tok);\r
++ endIdx = srcStr.find_last_not_of(tok);\r
++\r
++ if (beginIdx != string::npos && endIdx != string::npos)\r
++ return srcStr.substr(beginIdx, endIdx - beginIdx + 1);\r
++ else\r
++ return "";\r
++}\r
++\r
++/************************************************************************/\r
++/* Strslip() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Slice a string and split it into an array.\r
++ *\r
++ * This method will slice a string based on left and right delimiter, and then\r
++ * split the slipped part into an array.\r
++ *\r
++ * @param str The string to be processed, such as "longitude[15.5,23.5]"\r
++ *\r
++ * @param arrStr The two dimension array to place the sliced results.\r
++ *\r
++ * @param leftdlm The left delimiter used to slip the string, such as '['.\r
++ *\r
++ * @param rightdlm The right delimiter used to slip the string, such as ']'.\r
++ */\r
++\r
++void CPL_STDCALL Strslip(const char* str, const char* arrStr[], const char leftdlm, const char rightdlm)\r
++{\r
++ char* pdest1 = 0;\r
++ char* pdest2 = 0;\r
++\r
++ arrStr[0] = str;\r
++ pdest1 = (char*)strchr(str, leftdlm);\r
++ if (!pdest1)\r
++ {\r
++ arrStr[1] = str;\r
++ return;\r
++ }\r
++\r
++ pdest2 = (char*)strrchr(str, rightdlm);\r
++ if (!pdest2)\r
++ return;\r
++\r
++ arrStr[1] = pdest1 + 1;\r
++ *pdest1 = '\0';\r
++ *pdest2 = '\0';\r
++\r
++ return;\r
++}\r
++\r
++/************************************************************************/\r
++/* CsvburstComplexCpp() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Slice a string based on single or multiple delimiter(s), and\r
++ * then store the results to array.\r
++ *\r
++ * This method will slice a string based on specified delimiter(s), and then\r
++ * place the sliced string parts to a array.\r
++ *\r
++ * @param line The string to be processed.\r
++ *\r
++ * @param strSet The array to place the sliced results.\r
++ *\r
++ * @param tok The delimiter string used to slice the string.\r
++ *\r
++ * @return The size of the sliced parts.\r
++ */\r
++\r
++int CPL_STDCALL CsvburstComplexCpp(const string& line, vector<string> &strSet, const char *tok)\r
++{\r
++ if (line.empty() || line == "")\r
++ return 0;\r
++\r
++ strSet.clear();\r
++ string::size_type firstPos, idx;\r
++\r
++ firstPos = idx = 0;\r
++ idx = line.find_first_of(tok, firstPos);\r
++\r
++ while (idx != string::npos)\r
++ {\r
++ string tmpStr = StrTrim(line.substr(firstPos, (idx - firstPos)));\r
++ if (!tmpStr.empty() && tmpStr != "")\r
++ strSet.push_back(tmpStr);\r
++\r
++ firstPos = idx + 1;\r
++ if (firstPos == string::npos)\r
++ break;\r
++ idx = line.find_first_of(tok, firstPos);\r
++ }\r
++\r
++ if (firstPos != string::npos)\r
++ {\r
++ strSet.push_back(StrTrim(line.substr(firstPos)));\r
++ }\r
++\r
++ return strSet.size();\r
++}\r
++\r
++/************************************************************************/\r
++/* CsvburstCpp() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Slice a string based on single delimiter, and then store the results to array.\r
++ *\r
++ * This method will slice a string based on specified single delimiter, and then\r
++ * place the sliced string parts to a array.\r
++ *\r
++ * @param line The string to be processed, such as "12,34,56".\r
++ *\r
++ * @param strSet The array to place the sliced results.\r
++ *\r
++ * @param tok The delimiter character used to slice the string, such as ','.\r
++ *\r
++ * @return The size of the sliced parts.\r
++ */\r
++\r
++int CPL_STDCALL CsvburstCpp(const string& line, vector<string> &strSet, const char tok)\r
++{\r
++ if (line.empty() || line == "")\r
++ return 0;\r
++\r
++ strSet.clear();\r
++ string::size_type firstPos, idx;\r
++ string::size_type panfuPos;\r
++ panfuPos = 0;\r
++ firstPos = idx = 0;\r
++\r
++ idx = line.find_first_of(tok, firstPos);\r
++\r
++ while (idx != string::npos)\r
++ {\r
++ if(line[idx-2] == '\"' || line[idx-2] == '\'')//Add By Yuanzheng Shao\r
++ {\r
++ firstPos = idx + 1;\r
++ if (firstPos == string::npos)\r
++ break;\r
++ panfuPos = idx-2;\r
++ idx = line.find_first_of(tok, firstPos);\r
++\r
++ string tmpStr = StrTrim(line.substr(panfuPos, (idx - panfuPos)));\r
++ if (!tmpStr.empty() && tmpStr != "")\r
++ strSet.push_back(tmpStr);\r
++\r
++ firstPos = idx + 1;\r
++ idx = line.find_first_of(tok, firstPos);\r
++ }\r
++ else\r
++ {\r
++ string tmpStr = StrTrim(line.substr(firstPos, (idx - firstPos)));\r
++ if (!tmpStr.empty() && tmpStr != "")\r
++ strSet.push_back(tmpStr);\r
++\r
++ firstPos = idx + 1;\r
++ if (firstPos == string::npos)\r
++ break;\r
++ idx = line.find_first_of(tok, firstPos);\r
++ }\r
++ }\r
++\r
++ if (firstPos != string::npos)\r
++ {\r
++ strSet.push_back(StrTrim(line.substr(firstPos)));\r
++ }\r
++\r
++ return strSet.size();\r
++}\r
++\r
++/************************************************************************/\r
++/* Find_Compare_SubStr() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Find the substring in a string.\r
++ *\r
++ * This method will find a substring in a string.\r
++ *\r
++ * @param line The string to be processed.\r
++ *\r
++ * @param sub The substring to be compared.\r
++ *\r
++ * @return TRUE if find the substring, otherwise FALSE.\r
++ */\r
++\r
++int CPL_STDCALL Find_Compare_SubStr(string line, string sub)\r
++{\r
++ if (line.empty() || line == "" || sub.empty() || sub == "")\r
++ return 0;\r
++\r
++ for (unsigned int i = 0; i < line.size(); ++i)\r
++ {\r
++ line[i] = (char) toupper((char) line[i]);\r
++ }\r
++ for (unsigned int j = 0; j < sub.size(); ++j)\r
++ {\r
++ sub[j] = (char) toupper((char) sub[j]);\r
++ }\r
++\r
++ if (string::npos == line.find(sub))\r
++ return 0;\r
++ else\r
++ return 1;\r
++}\r
++\r
++/************************************************************************/\r
++/* GetFileNameList() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch the file name list under the specified directory.\r
++ *\r
++ * This method will fetch the file name list under the specified directory,\r
++ * and store the results to a array.\r
++ *\r
++ * @param dir The directory name.\r
++ *\r
++ * @param strList The array used to place the results.\r
++ *\r
++ * @return CE_None on success or CE_Failure on failure.\r
++ */\r
++\r
++CPLErr CPL_STDCALL GetFileNameList(char* dir, vector<string> &strList)\r
++{\r
++ char pwdBuf[256];\r
++ char *pwd=getcwd (pwdBuf, 256);\r
++ DIR *dp;\r
++ struct dirent *entry;\r
++ struct stat statbuf;\r
++ if ((dp = opendir(dir)) == NULL)\r
++ {\r
++ SetWCS_ErrorLocator("getFileNameList()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Open Director %s", dir);\r
++ return CE_Failure;\r
++ }\r
++\r
++ if (dir[strlen(dir) - 1] == '/')\r
++ dir[strlen(dir) - 1] = '\0';\r
++\r
++ chdir(dir);\r
++\r
++ while ((entry = readdir(dp)) != NULL)\r
++ {\r
++ lstat(entry->d_name, &statbuf);\r
++ if (S_ISDIR(statbuf.st_mode))\r
++ {\r
++ /* Found a directory, but ignore . and .. */\r
++ if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)\r
++ continue;\r
++ /* Recurse at a new indent level */\r
++ string subdir = dir;\r
++ subdir = subdir + "/" + entry->d_name;\r
++ GetFileNameList((char*)subdir.c_str(), strList);\r
++ }\r
++ else if (S_ISREG(statbuf.st_mode))\r
++ {\r
++ string fname = getcwd(NULL, 0);\r
++ fname = fname + "/" + entry->d_name;\r
++ strList.push_back(fname);\r
++ }\r
++ }\r
++ chdir(pwd);\r
++ closedir(dp);\r
++\r
++ return CE_None;\r
++}\r
++\r
++/************************************************************************/\r
++/* Julian2Date() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Convert the Julian days to date string.\r
++ *\r
++ * This method will convert the days of year to its date string (YYYY-MM-DD);\r
++ *\r
++ * @param year The year of days.\r
++ *\r
++ * @param days The Julian days.\r
++ *\r
++ * @return The date string.\r
++ */\r
++\r
++string Julian2Date(int year, int days)\r
++{\r
++ bool leapyear = ((year%4==0 && year%100!=0) || year%400==0) ? true : false;\r
++ int month, day;\r
++\r
++ int leapArr[24] = {1, 31, 32, 60, 61, 91, 92, 121, 122, 152, 153, 182, 183, 213, 214, 244,\r
++ 245, 274, 275, 305, 306, 335, 336, 366};\r
++ int unLeArr[24] = {1, 31, 32, 59, 60, 90, 91, 120, 121, 151, 152, 181, 182, 212, 213, 243,\r
++ 244, 273, 274, 304, 305, 334, 335, 365};\r
++\r
++ if(leapyear) {\r
++ for (int i = 0; i < 24; i += 2) {\r
++ if(days >= leapArr[i] && days <= leapArr[i+1]) {\r
++ month = int(i/2) + 1;\r
++ day = days - leapArr[i] + 1;\r
++ break;\r
++ }\r
++ }\r
++ } else {\r
++ for (int i=0; i < 24; i += 2) {\r
++ if(days >= unLeArr[i] && days <= unLeArr[i+1]) {\r
++ month = int(i/2) + 1;\r
++ day = days - unLeArr[i] + 1;\r
++ break;\r
++ }\r
++ }\r
++ }\r
++\r
++ string monthStr = month<10 ? "0" + convertToString(month) : convertToString(month);\r
++ string dayStr = day<10 ? "0" + convertToString(day) : convertToString(day);\r
++\r
++ return convertToString(year) + "-" + monthStr + "-" + dayStr;\r
++}\r
++\r
++/************************************************************************/\r
++/* GetTRMMBandList() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch the day's list for TRMM data based on the range of date/time.\r
++ *\r
++ * This method will find day's list for TRMM data based on specified date/time\r
++ * range, and store the results to a array.\r
++ *\r
++ * @param start The start date/time.\r
++ *\r
++ * @param end The end date/time.\r
++ *\r
++ * @param bandList The array used to place the results.\r
++ *\r
++ * @return CE_None on success or CE_Failure on failure.\r
++ */\r
++\r
++CPLErr CPL_STDCALL GetTRMMBandList(string start, string end, std::vector<int> &bandList)\r
++{\r
++ //calculate 2000-06-01's days, start's days, end's days\r
++ if(EQUAL(start.c_str(), "") && EQUAL(end.c_str(), ""))\r
++ return CE_None;\r
++\r
++ string june1str = start.substr(0, 4) + "-06-01";\r
++ long int june1sec = ConvertDateTimeToSeconds(june1str);\r
++ long int startsec = 0, endsec = 0;\r
++\r
++ if(!EQUAL(start.c_str(), ""))\r
++ startsec = ConvertDateTimeToSeconds(start);\r
++ if(!EQUAL(end.c_str(), ""))\r
++ endsec = ConvertDateTimeToSeconds(end);\r
++\r
++ int sdays = (int)(startsec - june1sec)/(24*3600) + 1;\r
++ int edays = (int)(endsec - june1sec)/(24*3600) + 1;\r
++\r
++ sdays = (sdays < 0) ? 0 : sdays;\r
++ edays = (edays < 0) ? sdays : edays;\r
++\r
++ for(int i = sdays; i <= edays; i++)\r
++ bandList.push_back(i);\r
++\r
++ return CE_None;\r
++}\r
++\r
++\r
++/************************************************************************/\r
++/* GetTimeString() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch the current system time to a string.\r
++ *\r
++ * This method will get the current system time, and convert it to a string.\r
++ * The return date/time has two formats:\r
++ * 1: YYYYMMDDHHMMSS\r
++ * 2: YYYY-MM-DDTHH:MM:SSZ\r
++ *\r
++ * @param code The return string's format.\r
++ *\r
++ * @return The string corresponding to current system time.\r
++ */\r
++\r
++string GetTimeString(int code)\r
++{\r
++ struct tm* ptime;\r
++ time_t now;\r
++ time(&now);\r
++ ptime = localtime(&now);\r
++ int year = ptime->tm_year + 1900;\r
++ int month = ptime->tm_mon + 1;\r
++ int day = ptime->tm_mday;\r
++ int hour = ptime->tm_hour;\r
++ int minute = ptime->tm_min;\r
++ int second = ptime->tm_sec;\r
++ string ye, mo, da, ho, mi, se;\r
++ ye = convertToString(year);\r
++ mo = (month < 10) ? "0" + convertToString(month) : convertToString(month);\r
++ da = (day < 10) ? "0" + convertToString(day) : convertToString(day);\r
++ ho = (hour < 10) ? "0" + convertToString(hour) : convertToString(hour);\r
++ mi = (minute < 10) ? "0" + convertToString(minute) : convertToString(minute);\r
++ se = (second < 10) ? "0" + convertToString(second) : convertToString(second);\r
++\r
++ string timestring;\r
++ if(code == 1)\r
++ {\r
++ string part1 = ye + mo + da;\r
++ string part2 = ho + mi + se;\r
++ timestring = part1.append(part2);\r
++ }\r
++ else if(code == 2)\r
++ {\r
++ string part1 = ye + "-" + mo + "-" + da + "T";\r
++ string part2 = ho + ":" + mi + ":" + se + "Z";\r
++ timestring = part1.append(part2);\r
++ }\r
++\r
++ return timestring;\r
++}\r
++\r
++/************************************************************************/\r
++/* MakeTempFile() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Generate a temporary file path.\r
++ *\r
++ * This method will generate a path for temporary file or output file,\r
++ * which is based on coverage identifier.\r
++ *\r
++ * @param dir The directory of the temporary file.\r
++ *\r
++ * @param covID The coverage identifier.\r
++ *\r
++ * @param suffix The suffix of the file format.\r
++ *\r
++ * @return The full path of the temporary file.\r
++ */\r
++\r
++string MakeTempFile(string dir, string covID, string suffix)\r
++{\r
++ string sOutFileName;\r
++\r
++ if (!dir.empty() && dir != "")\r
++ {\r
++ if (dir[dir.length() - 1] != '/')\r
++ {\r
++ dir += "/";\r
++ }\r
++ }\r
++ if (!suffix.empty() && suffix != "")\r
++ {\r
++ if (suffix[0] != '.')\r
++ suffix = "." + suffix;\r
++ }\r
++\r
++ if(covID == "")\r
++ {\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }\r
++ else if (EQUALN(covID.c_str(),"HDF4_EOS:EOS_SWATH:",19) ||\r
++ EQUALN(covID.c_str(),"HDF4_EOS:EOS_GRID:",18) ||\r
++ EQUALN(covID.c_str(),"HDF5:",5))\r
++ {\r
++ vector<string> strSet;\r
++ int n = CsvburstCpp(covID, strSet, ':');\r
++ if(n == 5){//Terra&Aqua\r
++ string srcFilePath = StrTrims(strSet[2], "\'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ string datasetname = StrTrims(strSet[4], "\'\"");\r
++ datasetname = StrReplace(datasetname, " ", "_");\r
++ sOutFileName = dir + srcFileName + "." + datasetname + "." + GetTimeString(1) + suffix;\r
++ }else if(n == 3) {//Aura\r
++ string srcFilePath = StrTrims(strSet[1], "\'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ string datasetname = StrTrims(strSet[2], "\'\"");\r
++ datasetname = StrReplace(datasetname, "//", "");\r
++ datasetname = StrReplace(datasetname, "/", "_");\r
++ datasetname = StrReplace(datasetname, " ", "");\r
++ sOutFileName = dir + srcFileName + "." + datasetname + "." + GetTimeString(1) + suffix;\r
++ }else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }else if(EQUALN( covID.c_str(), "GOES:NetCDF:",12))\r
++ {\r
++ vector<string> strSet;\r
++ int n = CsvburstCpp(covID, strSet, ':');\r
++ if(n == 4){\r
++ string srcFilePath = StrTrims(strSet[2], " \'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ sOutFileName = dir + srcFileName + "." + GetTimeString(1) + suffix;\r
++ }else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }\r
++ else if(EQUALN(covID.c_str(),"GEOTIFF:",8))\r
++ {\r
++ vector<string> strSet;\r
++ int n = CsvburstCpp(covID, strSet, ':');\r
++ if(n == 3){\r
++ string srcFilePath = StrTrims(strSet[1], " \'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ sOutFileName = dir + srcFileName + "." + GetTimeString(1) + suffix;\r
++ }else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }\r
++ else if(EQUALN(covID.c_str(),"TRMM:",5))\r
++ {\r
++ vector<string> strSet;\r
++ int n = CsvburstCpp(covID, strSet, ':');\r
++ if(n == 3){\r
++ string srcFilePath = StrTrims(strSet[1], " \'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ sOutFileName = dir + srcFileName + "." + GetTimeString(1) + suffix;\r
++ }else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }\r
++ else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++\r
++ return sOutFileName;\r
++}\r
++\r
++/************************************************************************/\r
++/* StringList() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Constructor for StringList.\r
++ */\r
++\r
++StringList::StringList(const string& sstrings, const char delimiter)\r
++{\r
++ string str = sstrings + delimiter;\r
++ string::size_type np, op = 0;\r
++ while ((op < str.size())\r
++ && ((np = str.find(delimiter, op)) != string::npos))\r
++ {\r
++ add(str.substr(op, np - op));\r
++ op = ++np;\r
++ }\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list constructor\r
++// -----------------------------------------------------------------------\r
++StringList::StringList(const string& sstrings, const string& delimiters)\r
++{\r
++ string str = sstrings + delimiters;\r
++ string::size_type np, op = 0;\r
++ while ((op < str.size()) && ((np = str.find(delimiters, op))\r
++ != string::npos))\r
++ {\r
++ add(str.substr(op, np - op));\r
++ op = np + delimiters.length();\r
++ }\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list -- append\r
++// -----------------------------------------------------------------------\r
++void StringList::append(StringList & s)\r
++{\r
++ for (int i = 0; i < s.size(); i++)\r
++ add(s[i]);\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list -- append with delimiter\r
++// -----------------------------------------------------------------------\r
++void StringList::append(const string sstrings, const char delimiter)\r
++{\r
++ StringList n(sstrings, delimiter);\r
++ append(n);\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list -- append with delimiters\r
++// -----------------------------------------------------------------------\r
++void StringList::append(const string sstrings, const string& delimiters)\r
++{\r
++ StringList n(sstrings, delimiters);\r
++ append(n);\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list -- return the index for query string\r
++// -----------------------------------------------------------------------\r
++int StringList::indexof(string qstr)\r
++{\r
++ for (int i = 0; i < size(); i++)\r
++ {\r
++ if (strings[i] == qstr)\r
++ return i;\r
++ }\r
++ return -1;\r
++}\r
++\r
++/************************************************************************/\r
++/* KVP() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Constructor for KVP.\r
++ *\r
++ * @param namevaluepair The key-value pair.\r
++ */\r
++\r
++KVP::KVP(string namevaluepair)\r
++{\r
++ StringList ss(namevaluepair, '=');\r
++ if (ss.size() == 2)\r
++ {\r
++ name = StrTrim(ss[0]);\r
++ value = StrTrim(ss[1]);\r
++ }\r
++ else\r
++ {\r
++ name = namevaluepair;\r
++ value = "";\r
++ }\r
++}\r
++\r
++/************************************************************************/\r
++/* CFGReader() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Constructor for CFGReader.\r
++ *\r
++ * This method is used to load the configuration file for WCS. Each configuration\r
++ * item looks like a key-value pair, CFGReader() will read the file to memory and\r
++ * store the parameters to a KVP array.\r
++ *\r
++ * @param configfilename The full path of the configuration file.\r
++ */\r
++\r
++CFGReader::CFGReader(const string &configfilename)\r
++{\r
++ ifstream cfgfile(configfilename.c_str());\r
++ if (!cfgfile)\r
++ {\r
++ SetWCS_ErrorLocator("CFGReader");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to open configure file.");\r
++ throw runtime_error("");\r
++ }\r
++\r
++ char line[MAX_LINE_LEN];\r
++ while (!cfgfile.eof())\r
++ {\r
++ cfgfile.getline(line, MAX_LINE_LEN - 1, '\n');\r
++ if (!cfgfile.fail())\r
++ {\r
++ if (line[0] != '#')\r
++ {\r
++ KVP kvp(line);\r
++ kvps.push_back(kvp);\r
++ }\r
++ }\r
++ }\r
++\r
++ cfgfile.close();\r
++}\r
++\r
++/************************************************************************/\r
++/* getValue() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch a configured item's value.\r
++ *\r
++ * This method is used to fetch a items value from a configuration file.\r
++ *\r
++ * @param keyname The item's name.\r
++ *\r
++ * @return The result string.\r
++ */\r
++\r
++string CFGReader::getValue(const string &keyname)\r
++{\r
++ for (int i = 0; i < size(); i++)\r
++ {\r
++ if (EQUAL(kvps[i].name.c_str(), keyname.c_str()))\r
++ return kvps[i].value;\r
++ }\r
++\r
++ return "";\r
++}\r
++\r
++/************************************************************************/\r
++/* getValue() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch a configured item's value, with default value.\r
++ *\r
++ * This method is used to fetch a items value from a configuration file,\r
++ * if not found, use the default value.\r
++ *\r
++ * @param keyname The item's name.\r
++ *\r
++ * @param defaultvalue The item's default value.\r
++ *\r
++ * @return The result string.\r
++ */\r
++\r
++string CFGReader::getValue(const string &keyname, const string &defaultvalue)\r
++{\r
++ string ret = getValue(keyname);\r
++ if (ret.empty() || ret == "")\r
++ return defaultvalue;\r
++ else\r
++ return ret;\r
++}\r
++\r
++/************************************************************************/\r
++/* Run() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief The entry point for CGI program.\r
++ *\r
++ * This method is used to fetch CGI parameters. Supports both HTTP GET\r
++ * and POST method. POST content could be KVPs and XML string, and GET\r
++ * content must be KVPs.\r
++ *\r
++ * @return CE_None on success or CE_Failure on failure.\r
++ */\r
++\r
++CPLErr WCSCGI::Run()\r
++{\r
++ /* get request parameters*/\r
++ char *gm = getenv("REQUEST_METHOD");\r
++ if (NULL == gm)\r
++ {\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Get \"REQUEST_METHOD\" Environment variable.");\r
++ return CE_Failure;\r
++ }\r
++\r
++ if (EQUAL(gm, "POST"))\r
++ me_CGIMethod = HTTP_XML_POST;\r
++ else if (EQUAL(gm, "GET"))\r
++ me_CGIMethod = HTTP_GET;\r
++ else\r
++ me_CGIMethod = UN_KNOWN;\r
++\r
++ switch (me_CGIMethod)\r
++ {\r
++ case HTTP_XML_POST:\r
++ {\r
++ char* aString = getenv("CONTENT_LENGTH");\r
++ if (NULL == aString || aString[0] == '\0')\r
++ {\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Get \"CONTENT_LENGTH\" Environment variable.");\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ return CE_Failure;\r
++ }\r
++\r
++ unsigned int cLength = atoi(aString);\r
++\r
++ string cString;\r
++ cString.resize(cLength + 1);\r
++\r
++ if (cLength != fread((char*) cString.c_str(), 1, cLength, stdin))\r
++ {\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Read POST Data Stream from Internet.");\r
++ return CE_Failure;\r
++ }\r
++\r
++ cString = StrReplace(cString, "&s;", "%26");\r
++ cString = StrReplace(cString, "&", "%26");\r
++\r
++ string tmpStr = CPLUnescapeString(cString.c_str(), NULL, CPLES_URL);\r
++ ms_CGIContent = CPLUnescapeString((char*) tmpStr.c_str(), NULL, CPLES_XML);\r
++\r
++ string::size_type beginIdx, endIdx;\r
++\r
++ beginIdx = ms_CGIContent.find("<?");\r
++ endIdx = ms_CGIContent.rfind(">");\r
++ //The post contents could be KVPs\r
++ if (beginIdx != string::npos && endIdx != string::npos)\r
++ ms_CGIContent = ms_CGIContent.substr(beginIdx, endIdx - beginIdx + 1);\r
++ }\r
++ break;\r
++ case HTTP_GET:\r
++ {\r
++ string tmpStr = getenv("QUERY_STRING");\r
++ tmpStr = StrReplace(tmpStr, "&s;", "%26");\r
++ tmpStr = StrReplace(tmpStr, "&", "%26");\r
++ if (tmpStr.empty() || tmpStr == "")\r
++ {\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "No \"QUERY_STRING\" Content.");\r
++ return CE_Failure;\r
++ }\r
++\r
++ ms_CGIContent = CPLUnescapeString((char*) tmpStr.c_str(), NULL, CPLES_URL);\r
++ }\r
++ break;\r
++ default:\r
++ {\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Unkown \"REQUEST_METHOD\".");\r
++ return CE_Failure;\r
++ }\r
++ }\r
++\r
++ return CE_None;\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// KVPsReader constructor\r
++// -----------------------------------------------------------------------\r
++KVPsReader::KVPsReader(const string& urlStr, const char &tok)\r
++{\r
++ StringList strLit(urlStr, tok);\r
++\r
++ for (int i = 0; i < strLit.size(); ++i)\r
++ {\r
++ KVP kvp(StrTrim(strLit[i]));\r
++ m_kvps.push_back(kvp);\r
++ }\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// KVPsReader get value function\r
++// -----------------------------------------------------------------------\r
++string KVPsReader::getValue(const string &keyname)\r
++{\r
++ for (unsigned int i = 0; i < m_kvps.size(); i++)\r
++ {\r
++ if (EQUAL(m_kvps[i].name.c_str() , keyname.c_str()))\r
++ return m_kvps[i].value;\r
++ }\r
++ return "";\r
++}\r
++\r
++\r
++vector<string> KVPsReader::getValues(const string &keyname)\r
++{\r
++ vector<string> valuesList;\r
++ for (unsigned int i = 0; i < m_kvps.size(); i++)\r
++ {\r
++ if (EQUAL(m_kvps[i].name.c_str() , keyname.c_str()))\r
++ valuesList.push_back(m_kvps[i].value);\r
++ }\r
++ return valuesList;\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// KVPsReader get value function, with default value\r
++// -----------------------------------------------------------------------\r
++string KVPsReader::getValue(const string &keyname, const string &defaultvalue)\r
++{\r
++ string ret = getValue(keyname);\r
++ if (ret.empty() || ret == "")\r
++ return defaultvalue;\r
++ else\r
++ return ret;\r
++}\r
++\r
++/************************************************************************/\r
++/* StrReplace() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Replace a string.\r
++ *\r
++ * This method is used to replace a string with specified substring.\r
++ *\r
++ * @param str The string needs to be processed.\r
++ *\r
++ * @param oldSubStr The substring needs to be replaced.\r
++ *\r
++ * @param newStr The string will replace the oldSubStr.\r
++ *\r
++ * @return The processed string.\r
++ */\r
++\r
++string CPL_STDCALL StrReplace(string& str, const string oldSubStr, const string newStr)\r
++{\r
++ while(true)\r
++ {\r
++ string::size_type pos(0);\r
++ if( ( pos = str.find(oldSubStr) ) != string::npos )\r
++ {\r
++ str.replace( pos, oldSubStr.length(), newStr );\r
++ }else {\r
++ break;\r
++ }\r
++ }\r
++ return str;\r
++}\r
++\r
++/************************************************************************/\r
++/* GetSingleValue() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Get a single value from a special KVP part.\r
++ *\r
++ * This method is used to get value from a special KVP part.\r
++ *\r
++ * @param subsetstr The string needs to be processed, such as "subset=Long(11)".\r
++ *\r
++ * @return The processed string, such as "11".\r
++ */\r
++\r
++string CPL_STDCALL GetSingleValue(const string& subsetstr)\r
++{\r
++ string::size_type idx1 = subsetstr.find_last_of('(');\r
++ string::size_type idx2 = subsetstr.find_last_of(')');\r
++\r
++ return StrTrim(subsetstr.substr(idx1 + 1, idx2 - idx1 -1));\r
++}\r
++\r
++/************************************************************************/\r
++/* GetSubSetLatLon() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Get a subset spatial extent in WCS 2.0 request.\r
++ *\r
++ * This method is used to get values of spatial extent and place the values\r
++ * in an array, and return the CRS code for the coordinates of the extent.\r
++ *\r
++ * @param subsetstr The string needs to be processed,\r
++ * such as "subset=Lat,http://www.opengis.net/def/crs/EPSG/0/4326(32,47)".\r
++ *\r
++ * @param subsetvalue The array to place the spatial extent values.\r
++ *\r
++ * @return The processed string, such as "EPSG:4326".\r
++ */\r
++\r
++string CPL_STDCALL GetSubSetLatLon(const string& subsetstr, vector<double> &subsetvalue)\r
++{\r
++ string::size_type idx1 = subsetstr.find_last_of('(');\r
++ string::size_type idx2 = subsetstr.find_last_of(')');\r
++\r
++ string value = StrTrim(subsetstr.substr(idx1 + 1, idx2 - idx1 -1));\r
++ vector<string> tmpV;\r
++ CsvburstCpp(value, tmpV, ',');\r
++\r
++ for(unsigned int i = 0; i < tmpV.size(); i++)\r
++ {\r
++ double curD;\r
++ convertFromString(curD, tmpV.at(i));\r
++ subsetvalue.push_back(curD);\r
++ }\r
++\r
++ string subsetProj;\r
++ idx1 = subsetstr.find(',');\r
++ idx2 = subsetstr.find('(');\r
++ if(idx1 > idx2) \r
++ {\r
++ subsetProj = "EPSG:4326";\r
++ }\r
++ else\r
++ {\r
++ value = StrTrim(subsetstr.substr(idx1 + 1, idx2 - idx1 - 1));\r
++ if(value.find("http") != string::npos)\r
++ {\r
++ string::size_type idx3 = value.find_last_of('/');\r
++ subsetProj = "EPSG:" + value.substr(idx3 + 1);\r
++ }\r
++ else\r
++ {\r
++ subsetProj = value;\r
++ }\r
++\r
++ }\r
++\r
++ return subsetProj;\r
++}\r
++\r
++//subset=phenomenonTime("2006-08-01","2006-08-22T09:22:00Z")&\r
++//subset=phenomenonTime("2006-08-01")&\r
++void CPL_STDCALL GetSubSetTime(const string& subsetstr, vector<string> &subsetvalue)\r
++{\r
++ string::size_type idx1 = subsetstr.find_last_of('(');\r
++ string::size_type idx2 = subsetstr.find_last_of(')');\r
++ string value = StrTrim(subsetstr.substr(idx1 + 1, idx2 - idx1 - 1));\r
++ string valueN = StrReplace(value, "\"", "");\r
++ CsvburstCpp(valueN, subsetvalue, ',');\r
++}\r
++\r
++//time type 1: 2006-08-22T09:22:00Z\r
++//time type 1: 2006-08-01\r
++int CPL_STDCALL CompareDateTime_GreaterThan(string time1, string time2)\r
++{\r
++ time_t retval1 = 0;\r
++ time_t retval2 = 0;\r
++\r
++ struct tm storage1 = {0,0,0,0,0,0,0,0,0};\r
++ struct tm storage2 = {0,0,0,0,0,0,0,0,0};\r
++\r
++ char *p1 = NULL;\r
++ char *p2 = NULL;\r
++\r
++ if(time1.find("T") != string::npos && time1.find("Z") != string::npos)\r
++ p1 = (char *)strptime(time1.c_str(), "%Y-%m-%dT%H:%M:%SZ", &storage1);\r
++ else\r
++ p1 = (char *)strptime(time1.c_str(), "%Y-%m-%d", &storage1);\r
++\r
++ if(time2.find("T") != string::npos && time2.find("Z") != string::npos)\r
++ p2 = (char *)strptime(time2.c_str(), "%Y-%m-%dT%H:%M:%SZ", &storage2);\r
++ else\r
++ p2 = (char *)strptime(time2.c_str(), "%Y-%m-%d", &storage2);\r
++\r
++ retval1 = mktime(&storage1);\r
++ retval2 = mktime(&storage2);\r
++\r
++ if(retval1 == retval2)\r
++ return 0;\r
++ else if(retval1 > retval2)\r
++ return 1;\r
++ else\r
++ return -1;\r
++\r
++}\r
++\r
++int CPL_STDCALL ConvertDateTimeToSeconds(string datetime)\r
++{\r
++ time_t retval1 = 0;\r
++ struct tm storage1 = {0,0,0,0,0,0,0,0,0};\r
++ char *p1 = NULL;\r
++\r
++ if(datetime.find("T") != string::npos && datetime.find("Z") != string::npos)\r
++ p1 = (char *)strptime(datetime.c_str(), "%Y-%m-%dT%H:%M:%SZ", &storage1);\r
++ else\r
++ p1 = (char *)strptime(datetime.c_str(), "%Y-%m-%d", &storage1);\r
++\r
++ retval1 = mktime(&storage1);\r
++\r
++ return retval1;\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// Find lower-left and upper-right corner point coordinate\r
++// -----------------------------------------------------------------------\r
++void CPL_STDCALL GetCornerPoints(const GDAL_GCP* &pGCPList, const int &nGCPs, My2DPoint& lowLeft, My2DPoint& upRight)\r
++{\r
++ double xLeft = (numeric_limits<double>::max)();\r
++ double xRight = -xLeft;\r
++ double yLower = (numeric_limits<double>::max)();\r
++ double yUpper = -yLower;\r
++\r
++ for (int j = 0; j < nGCPs; j++)\r
++ {\r
++ yUpper = MAX(yUpper,pGCPList[j].dfGCPY);\r
++ yLower = MIN(yLower,pGCPList[j].dfGCPY);\r
++ if(pGCPList[j].dfGCPX != -999)//test MOD021KM.A2000065.1900.005.2008235220315.hdf, error GCP X value (-999)\r
++ xLeft = MIN(xLeft,pGCPList[j].dfGCPX);\r
++ xRight = MAX(xRight,pGCPList[j].dfGCPX);\r
++ }\r
++\r
++ lowLeft.mi_X = xLeft;\r
++ lowLeft.mi_Y = yLower;\r
++ upRight.mi_X = xRight;\r
++ upRight.mi_Y = yUpper;\r
++\r
++ return;\r
++}\r
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/82/82ef297cba5eb92b8c25159c74318bee457c1f00.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/82/82ef297cba5eb92b8c25159c74318bee457c1f00.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/82/82ef297cba5eb92b8c25159c74318bee457c1f00.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/82/82ef297cba5eb92b8c25159c74318bee457c1f00.svn-base 2014-03-03 15:47:37.983566265 +0100
+@@ -0,0 +1,106 @@
++
++# Build libswath2grid, part of libdap.
++
++AUTOMAKE_OPTIONS = foreign
++
++AM_CPPFLAGS = -I$(top_srcdir)/GNU -I$(top_srcdir) -I$(top_srcdir)/tests -I$(top_srcdir)/dispatch $(XML2_CFLAGS) $(CURL_CFLAGS)
++AM_LDADD =
++
++if CPPUNIT
++AM_CPPFLAGS += $(CPPUNIT_CFLAGS)
++AM_LDADD += $(CPPUNIT_LIBS)
++endif
++
++# These are not used by automake but are often useful for certain types of
++# debugging. The best way to use these is to run configure as:
++# export CXXFLAGS='...'; ./configure --disable-shared
++# the --disable-shared is not required, but it seems to help with debuggers.
++CXXFLAGS_DEBUG = -g3 -O0 -Wall -W -Wcast-align -Werror
++TEST_COV_FLAGS = -ftest-coverage -fprofile-arcs
++
++# SUBDIRS =
++# DIST_SUBDIRS =
++
++# This determines what gets built by make check
++check_PROGRAMS = $(UNIT_TESTS)
++
++# This determines what gets run by 'make check.'
++# Now (12/20/12) this fails; don't run until it works.
++# TESTS = $(UNIT_TESTS)
++
++
++noinst_LTLIBRARIES = libswath2grid.la
++
++libswath2grid_la_SOURCES = $(SRCS) $(HDRS)
++libswath2grid_la_CPPFLAGS = $(GDAL_CFLAGS) $(XML2_CFLAGS) $(DAP_SERVER_CFLAGS) $(DAP_CLIENT_CFLAGS) -I$(top_srcdir)/dispatch
++libswath2grid_la_LDFLAGS =
++libswath2grid_la_LIBADD = $(GDAL_LDFLAGS) $(DAP_SERVER_LIBS) $(DAP_CLIENT_LIBS)
++
++SRCS = AbstractDataset.cpp wcs_error.cpp \
++BoundingBox.cpp wcsUtil.cpp DAP_Dataset.cpp reproj_functions.cc
++
++# NC_GOES_Dataset.cpp NC_GOES_Dataset.h
++
++HDRS = AbstractDataset.h wcs_error.h \
++BoundingBox.h wcsUtil.h DAP_Dataset.h reproj_functions.h
++
++if CPPUNIT
++UNIT_TESTS = s2gTest
++
++else
++UNIT_TESTS =
++
++check-local:
++ @echo ""
++ @echo "**********************************************************"
++ @echo "You must have cppunit 1.12.x or greater installed to run *"
++ @echo "check target in unit-tests directory *"
++ @echo "**********************************************************"
++ @echo ""
++endif
++
++s2gTest_SOURCES = s2gTest.cc
++s2gTest_CPPFLAGS = $(AM_CPPFLAGS) $(DAP_SERVER_CFLAGS) $(DAP_CLIENT_CFLAGS) $(GDAL_CFLAGS)
++s2gTest_LDADD = -ltest-types libswath2grid.la $(AM_LDADD) $(DAP_SERVER_LIBS) $(DAP_CLIENT_LIBS) $(GDAL_LDFLAGS)
++
++if LIBDAP
++check-dap:
++ @echo ""
++ @echo "**********************************************************"
++ @echo "USING DAP "
++ @echo "DAP_CLIENT_CFLAGS: " $(DAP_CLIENT_CFLAGS)
++ @echo "DAP_SERVER_CFLAGS: " $(DAP_SERVER_CFLAGS)
++ @echo "DAP_CLIENT_LIBS: " $(DAP_CLIENT_LIBS)
++ @echo "DAP_SERVER_LIBS: " $(DAP_SERVER_LIBS)
++ @echo "**********************************************************"
++ @echo ""
++else
++check-dap:
++ @echo ""
++ @echo "**********************************************************"
++ @echo " Unable to locate DAP libraries!"
++ @echo "**********************************************************"
++ @echo ""
++endif
++
++
++if GDAL_FOUND
++check-gdal:
++ @echo ""
++ @echo "**********************************************************"
++ @echo "Using gdal. "
++ @echo "GDAL_CFLAGS: " $(GDAL_CFLAGS)
++ @echo "GDAL_LDFLAGS: " $(GDAL_LDFLAGS)
++ @echo "**********************************************************"
++ @echo ""
++else
++check-gdal:
++ @echo ""
++ @echo "**********************************************************"
++ @echo "You must have gdal 12.15.12 or greater installed to run"
++ @echo "check target in unit-tests directory "
++ @echo "GDAL_VERSION: '$(GDAL_VERSION)'"
++ @echo "prefix: '$(prefix)'"
++ @echo "**********************************************************"
++ @echo ""
++endif
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/84/8411727990dab1414d2bd0e9918fa8c2350fea4b.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/84/8411727990dab1414d2bd0e9918fa8c2350fea4b.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/84/8411727990dab1414d2bd0e9918fa8c2350fea4b.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/84/8411727990dab1414d2bd0e9918fa8c2350fea4b.svn-base 2014-03-03 15:47:37.400232956 +0100
+@@ -0,0 +1,13 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<request reqID ="some_unique_value" >
++ <setContext name="dap_format">dap2</setContext>
++ <setContext name="xdap_accept">3.3</setContext>
++ <setContainer name="c" space="catalog">/data/nc/OWS_9_Data/AIRS_570672/AIRS_AQUA_L1B_BRIGHTNESS_20101026_1617.nc.gz</setContainer>
++ <define name="d">
++ <container name="c">
++ <constraint>swath2grid()</constraint>
++ </container>
++ </define>
++ <get type="dods" definition="d"/>
++</request>
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/84/84572441d00db760c377120e09ab68451d54d4a4.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/84/84572441d00db760c377120e09ab68451d54d4a4.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/84/84572441d00db760c377120e09ab68451d54d4a4.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/84/84572441d00db760c377120e09ab68451d54d4a4.svn-base 2014-03-03 15:47:37.846899604 +0100
+@@ -0,0 +1,13 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<request reqID ="some_unique_value" >
++ <setContext name="dap_format">dap2</setContext>
++ <setContext name="xdap_accept">3.3</setContext>
++ <setContainer name="c" space="catalog">/data/nc/OWS_9_Data/AIRS_570672/AIRS_AQUA_L1B_BRIGHTNESS_20101026_1617.nc.gz</setContainer>
++ <define name="d">
++ <container name="c">
++ <constraint>swath2grid(topog,Latitude,Longitude)</constraint>
++ </container>
++ </define>
++ <get type="dods" definition="d"/>
++</request>
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/a1/a171586f7cd3757d03bb9b30306a4d2e0b053077.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/a1/a171586f7cd3757d03bb9b30306a4d2e0b053077.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/a1/a171586f7cd3757d03bb9b30306a4d2e0b053077.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/a1/a171586f7cd3757d03bb9b30306a4d2e0b053077.svn-base 2014-03-03 15:47:37.590232948 +0100
+@@ -0,0 +1,668 @@
++
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2012 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++// Tests for the AISResources class.
++
++#include <cppunit/TextTestRunner.h>
++#include <cppunit/extensions/TestFactoryRegistry.h>
++#include <cppunit/extensions/HelperMacros.h>
++
++#define DODS_DEBUG
++//#define DODS_DEBUG2
++
++#include "BaseType.h"
++#include "Array.h"
++#include "Grid.h"
++
++#include "reproj_functions.h"
++
++#include "test/TestTypeFactory.h"
++
++#include "util.h"
++#include "debug.h"
++
++#define THREE_ARRAY_1_DDS "three_array_1.dds"
++#define THREE_ARRAY_1_DAS "three_array_1.das"
++
++using namespace CppUnit;
++using namespace libdap;
++using namespace std;
++
++int test_variable_sleep_interval = 0;
++
++/**
++ * Splits the string on the passed char. Returns vector of substrings.
++ * TODO make this work on situations where multiple spaces doesn't hose the split()
++ */
++static vector<string> &split(const string &s, char delim, vector<string> &elems) {
++ stringstream ss(s);
++ string item;
++ while (getline(ss, item, delim)) {
++ elems.push_back(item);
++ }
++ return elems;
++}
++
++/**
++ * Splits the string on the passed char. Returns vector of substrings.
++ */
++static vector<string> split(const string &s, char delim = ' ') {
++ vector<string> elems;
++ return split(s, delim, elems);
++}
++
++class s2gTest:public TestFixture
++{
++private:
++ DDS * dds;
++ TestTypeFactory btf;
++ ConstraintEvaluator ce;
++public:
++ s2gTest():dds(0)
++ {}
++ ~s2gTest()
++ {}
++
++ void setUp()
++ {
++ try {
++ dds = new DDS(&btf);
++ string dds_file = /*(string)TEST_SRC_DIR + "/" +*/ THREE_ARRAY_1_DDS ;
++ dds->parse(dds_file);
++ DAS das;
++ string das_file = /*(string)TEST_SRC_DIR + "/" +*/ THREE_ARRAY_1_DAS ;
++ das.parse(das_file);
++ dds->transfer_attributes(&das);
++
++ DBG(dds->print_xml(stderr, false, "noBlob"));
++
++ // Load values into the array variables
++ Array & t = dynamic_cast < Array & >(*dds->var("t"));
++ Array & lon = dynamic_cast < Array & >(*dds->var("lon"));
++ Array & lat = dynamic_cast < Array & >(*dds->var("lat"));
++
++ dods_float64 t_vals[10][10];
++ for (int i = 0; i < 10; ++i)
++ for (int j = 0; j < 10; ++j)
++ t_vals[i][j] = j + (i * 10);
++ t.set_value(&t_vals[0][0], 100);
++ t.set_read_p(true);
++
++ // Read real lat/lon values from a Level 1B file ascii dump
++ fstream input("AIRS_AQUA_L1B_BRIGHTNESS_20101026_1617.nc.gz.ascii.txt", fstream::in);
++ if (input.eof() || input.fail())
++ throw Error("Could not open lat/lon data in SetUp.");
++ // Read a line of text to get to the start of the data.
++ string line;
++ getline(input, line);
++ if (input.eof() || input.fail())
++ throw Error("Could not read lat/lon data in SetUp.");
++
++ dods_float64 lon_vals[10][10];
++ for (int i = 0; i < 10; ++i) {
++ getline(input, line);
++ if (input.eof() || input.fail())
++ throw Error("Could not read lon data from row " + long_to_string(i) + " in SetUp.");
++ vector<string> vals = split(line, ',');
++ for (unsigned int j = 1; j < vals.size(); ++j) {
++ DBG2(cerr << "loading in lon value: " << vals[j] << "' " << atof(vals[j].c_str()) << endl;)
++ lon_vals[i][j-1] = atof(vals[j].c_str());
++ }
++ }
++ lon.set_value(&lon_vals[0][0], 100);
++ lon.set_read_p(true);
++
++ dods_float64 lat_vals[10][10];
++ for (int i = 0; i < 10; ++i) {
++ getline(input, line);
++ if (input.eof() || input.fail())
++ throw Error("Could not read lat data from row " + long_to_string(i) + " in SetUp.");
++ vector<string> vals = split(line, ',');
++ for (unsigned int j = 1; j < vals.size(); ++j) {
++ DBG2(cerr << "loading in lat value: " << vals[j] << "' " << atof(vals[j].c_str()) << endl;)
++ lat_vals[i][j-1] = atof(vals[j].c_str());
++ }
++ }
++ lat.set_value(&lat_vals[0][0], 100);
++ lat.set_read_p(true);
++ }
++
++ catch (Error & e) {
++ cerr << "SetUp (Error): " << e.get_error_message() << endl;
++ throw;
++ }
++ catch(std::exception &e) {
++ cerr << "SetUp (std::exception): " << e.what() << endl;
++ throw;
++ }
++ }
++
++ void tearDown()
++ {
++ delete dds; dds = 0;
++ }
++
++ CPPUNIT_TEST_SUITE( s2gTest );
++
++ CPPUNIT_TEST(no_arguments_test);
++ CPPUNIT_TEST(array_return_test);
++ CPPUNIT_TEST(grid_return_test);
++
++ CPPUNIT_TEST_SUITE_END();
++
++ void no_arguments_test()
++ {
++ try {
++ BaseType *btp = 0;
++ function_swath2array(0, 0, *dds, &btp);
++ CPPUNIT_ASSERT(true);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"no_arguments_test() should not have failed");
++ }
++ }
++
++ void array_return_test()
++ {
++ try {
++ BaseType *argv[3];
++ argv[0] = dds->var("t");
++ argv[1] = dds->var("lon");
++ argv[2] = dds->var("lat");
++
++ BaseType *btp = 0;
++ function_swath2array(3, argv, *dds, &btp);
++
++ DBG(cerr << "btp->name(): " << btp->name() << endl);
++ CPPUNIT_ASSERT(btp->name() == "t");
++ CPPUNIT_ASSERT(btp->type() == dods_array_c);
++
++ // Extract data; I know it's 10x16 from debugging output
++ dods_float64 values[10][16];
++ Array *a = static_cast<Array*>(btp);
++ a->value(&values[0][0]);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_FAIL("array_return_test");
++ }
++ }
++
++#if 0
++ void one_argument_not_a_grid_test()
++ {
++ try {
++ BaseType *argv[1];
++ argv[0] = dds->var("lat");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this, although it is not a grid");
++ BaseType *btp = 0;
++ function_grid(1, argv, *dds, &btp);
++ CPPUNIT_ASSERT(!"one_argument_not_a_grid_test() should have failed");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(true);
++ }
++ }
++
++ void map_not_in_grid_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "3<second<=7";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ CPPUNIT_ASSERT(!"map_not_in_grid_test() should have failed");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(true);
++ }
++ }
++
++ void one_dim_grid_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "3<first<=7";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ Grid &g = dynamic_cast<Grid&>(*btp);
++
++ //Grid &g = dynamic_cast<Grid&>(*argv[0]);
++ Array &m = dynamic_cast<Array&>(**g.map_begin());
++ CPPUNIT_ASSERT(m.dimension_start(m.dim_begin(), true) == 4);
++ CPPUNIT_ASSERT(m.dimension_stop(m.dim_begin(), true) == 7);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"one_dim_grid_test() should have worked");
++ }
++ }
++
++ void one_dim_grid_two_expressions_test()
++ {
++ try {
++ BaseType *argv[3];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++
++ argv[1] = new Str("");
++ string expression = "first>3";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ argv[2] = new Str("");
++ expression = "first<=7";
++ dynamic_cast<Str*>(argv[2])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[2])->set_read_p(true);
++
++ //function_grid(3, argv, *dds);
++ BaseType *btp = 0;
++ function_grid(3, argv, *dds, &btp);
++ Grid &g = dynamic_cast<Grid&>(*btp);
++
++ //Grid &g = dynamic_cast<Grid&>(*function_grid(3, argv, *dds));
++ //Grid &g = dynamic_cast<Grid&>(*argv[0]);
++ Array &m = dynamic_cast<Array&>(**g.map_begin());
++ CPPUNIT_ASSERT(m.dimension_start(m.dim_begin(), true) == 4);
++ CPPUNIT_ASSERT(m.dimension_stop(m.dim_begin(), true) == 7);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"one_dim_grid_two_expressions_test() should have worked");
++ }
++ }
++
++ void one_dim_grid_descending_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("b");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "3<first<=7";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ Grid &g = dynamic_cast<Grid&>(*btp);
++
++ //function_grid(2, argv, *dds);
++ //Grid &g = dynamic_cast<Grid&>(*function_grid(2, argv, *dds));
++ //Grid &g = dynamic_cast<Grid&>(*argv[0]);
++ Array &m = dynamic_cast<Array&>(**g.map_begin());
++ CPPUNIT_ASSERT(m.dimension_start(m.dim_begin(), true) == 2);
++ CPPUNIT_ASSERT(m.dimension_stop(m.dim_begin(), true) == 5);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"one_dim_grid_test() should have worked");
++ }
++ }
++
++ void one_dim_grid_two_expressions_descending_test()
++ {
++ try {
++ BaseType *argv[3];
++ argv[0] = dds->var("b");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++
++ argv[1] = new Str("");
++ string expression = "first>3";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ argv[2] = new Str("");
++ expression = "first<=7";
++ dynamic_cast<Str*>(argv[2])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[2])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(3, argv, *dds, &btp);
++ Grid &g = dynamic_cast<Grid&>(*btp);
++
++ //function_grid(3, argv, *dds);
++ //Grid &g = dynamic_cast<Grid&>(*function_grid(3, argv, *dds));
++ //Grid &g = dynamic_cast<Grid&>(*argv[0]);
++ Array &m = dynamic_cast<Array&>(**g.map_begin());
++ CPPUNIT_ASSERT(m.dimension_start(m.dim_begin(), true) == 2);
++ CPPUNIT_ASSERT(m.dimension_stop(m.dim_begin(), true) == 5);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"one_dim_grid_two_expressions_test() should have worked");
++ }
++ }
++
++ void one_dim_grid_noninclusive_values_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "7<first<=3";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ //Grid &g = dynamic_cast<Grid&>(*btp);
++
++ // function_grid(2, argv, *dds);
++
++ CPPUNIT_ASSERT(!"one_dim_grid_noninclusive_values_test() should not have worked");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(true);
++ }
++ }
++
++ // grid() is not required to handle this case. This test is not used.
++ void values_outside_map_range_test()
++ {
++ try {
++ BaseType *argv[2];
++ argv[0] = dds->var("a");
++ CPPUNIT_ASSERT(argv[0] && "dds->var should find this");
++ argv[1] = new Str("");
++ string expression = "3<=first<20";
++ dynamic_cast<Str*>(argv[1])->val2buf(&expression);
++ dynamic_cast<Str*>(argv[1])->set_read_p(true);
++
++ BaseType *btp = 0;
++ function_grid(2, argv, *dds, &btp);
++ //Grid &g = dynamic_cast<Grid&>(*btp);
++
++ // function_grid(2, argv, *dds);
++
++ CPPUNIT_ASSERT(!"values_outside_map_range_test() should not have worked");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(true);
++ }
++ }
++
++ // linear_scale tests
++ void linear_scale_args_test() {
++ try {
++ BaseType *btp = 0;
++ function_linear_scale(0, 0, *dds, &btp);
++ CPPUNIT_ASSERT(true);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"linear_scale_args_test: should not throw Error");
++ }
++ }
++
++ void linear_scale_array_test() {
++ try {
++ Array *a = dynamic_cast<Grid&>(*dds->var("a")).get_array();
++ CPPUNIT_ASSERT(a);
++ BaseType *argv[3];
++ argv[0] = a;
++ argv[1] = new Float64("");
++ dynamic_cast<Float64*>(argv[1])->set_value(0.1);//m
++ argv[2] = new Float64("");
++ dynamic_cast<Float64*>(argv[2])->set_value(10);//b
++ BaseType *scaled = 0;
++ function_linear_scale(3, argv, *dds, &scaled);
++ CPPUNIT_ASSERT(scaled->type() == dods_array_c
++ && scaled->var()->type() == dods_float64_c);
++ double *values = extract_double_array(dynamic_cast<Array*>(scaled));
++ CPPUNIT_ASSERT(values[0] == 10);
++ CPPUNIT_ASSERT(values[1] == 10.1);
++ CPPUNIT_ASSERT(values[9] == 10.9);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"Error in linear_scale_grid_test()");
++ }
++ }
++
++ void linear_scale_grid_test() {
++ try {
++ Grid *g = dynamic_cast<Grid*>(dds->var("a"));
++ CPPUNIT_ASSERT(g);
++ BaseType *argv[3];
++ argv[0] = g;
++ argv[1] = new Float64("");
++ dynamic_cast<Float64*>(argv[1])->set_value(0.1);
++ argv[2] = new Float64("");
++ dynamic_cast<Float64*>(argv[2])->set_value(10);
++ BaseType *scaled = 0;
++ function_linear_scale(3, argv, *dds, &scaled);
++ CPPUNIT_ASSERT(scaled->type() == dods_grid_c);
++ Grid *g_s = dynamic_cast<Grid*>(scaled);
++ CPPUNIT_ASSERT(g_s->get_array()->var()->type() == dods_float64_c);
++ double *values = extract_double_array(g_s->get_array());
++ CPPUNIT_ASSERT(values[0] == 10);
++ CPPUNIT_ASSERT(values[1] == 10.1);
++ CPPUNIT_ASSERT(values[9] == 10.9);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"Error in linear_scale_grid_test()");
++ }
++ }
++
++ void linear_scale_grid_attributes_test() {
++ try {
++ Grid *g = dynamic_cast<Grid*>(dds->var("a"));
++ CPPUNIT_ASSERT(g);
++ BaseType *argv[1];
++ argv[0] = g;
++ BaseType *scaled = 0;
++ function_linear_scale(1, argv, *dds, &scaled);
++ CPPUNIT_ASSERT(scaled->type() == dods_grid_c);
++ Grid *g_s = dynamic_cast<Grid*>(scaled);
++ CPPUNIT_ASSERT(g_s->get_array()->var()->type() == dods_float64_c);
++ double *values = extract_double_array(g_s->get_array());
++ CPPUNIT_ASSERT(values[0] == 10);
++ CPPUNIT_ASSERT(values[1] == 10.1);
++ CPPUNIT_ASSERT(values[9] == 10.9);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"Error in linear_scale_grid_test()");
++ }
++ }
++
++ // This tests the case where attributes are not found
++ void linear_scale_grid_attributes_test2() {
++ try {
++ Grid *g = dynamic_cast<Grid*>(dds->var("b"));
++ CPPUNIT_ASSERT(g);
++ BaseType *argv[1];
++ argv[0] = g;
++ BaseType *btp = 0;
++ function_linear_scale(1, argv, *dds, &btp);
++ CPPUNIT_FAIL("Should not get here; no params passed and no attributes set for grid 'b'");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT("Caught exception");
++ }
++ }
++
++ void linear_scale_scalar_test() {
++ try {
++ Int32 *i = new Int32("linear_scale_test_int32");
++ CPPUNIT_ASSERT(i);
++ i->set_value(1);
++ BaseType *argv[3];
++ argv[0] = i;
++ argv[1] = new Float64("");
++ dynamic_cast<Float64*>(argv[1])->set_value(0.1);//m
++ argv[2] = new Float64("");
++ dynamic_cast<Float64*>(argv[2])->set_value(10);//b
++ BaseType *scaled = 0;
++ function_linear_scale(3, argv, *dds, &scaled);
++ CPPUNIT_ASSERT(scaled->type() == dods_float64_c);
++
++ CPPUNIT_ASSERT(dynamic_cast<Float64*>(scaled)->value() == 10.1);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT(!"Error in linear_scale_scalar_test()");
++ }
++ }
++
++
++ void function_dap_1_test() {
++ try {
++ Int32 *i = new Int32("function_dap_1_test_int32");
++ CPPUNIT_ASSERT(i);
++ i->set_value(2);
++ BaseType *argv[1];
++ argv[0] = i;
++
++ ConstraintEvaluator unused;
++ function_dap(1, argv, *dds, unused);
++
++ CPPUNIT_ASSERT(dds->get_dap_major() == 2);
++ CPPUNIT_ASSERT(dds->get_dap_minor() == 0);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_FAIL("Error in function_dap_1_test(): " + e.get_error_message());
++ }
++ }
++
++ void function_dap_2_test() {
++ try {
++ Float64 *d = new Float64("function_dap_1_test_float64");
++ CPPUNIT_ASSERT(d);
++ d->set_value(3.2);
++ BaseType *argv[1];
++ argv[0] = d;
++
++ ConstraintEvaluator unused;
++ function_dap(1, argv, *dds, unused);
++
++ CPPUNIT_ASSERT(dds->get_dap_major() == 3);
++ CPPUNIT_ASSERT(dds->get_dap_minor() == 2);
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_FAIL("Error in function_dap_2_test(): " + e.get_error_message());
++ }
++ }
++
++ void function_dap_3_test() {
++ try {
++ cerr <<"In function_dap_3_test" << endl;
++ ConstraintEvaluator unused;
++ function_dap(0, 0, *dds, unused);
++
++ CPPUNIT_FAIL("Should have thrown an exception on no args");
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_ASSERT("Pass: Caught exception");
++ }
++ }
++#endif
++ void grid_return_test()
++ {
++ try {
++ BaseType *argv[3];
++ argv[0] = dds->var("t");
++ argv[1] = dds->var("lon");
++ argv[2] = dds->var("lat");
++
++ cerr << "Input values:" << endl;
++ dods_float64 t_vals[10][10];
++ Array *a = static_cast<Array*>(argv[0]);
++ a->value(&t_vals[0][0]);
++ for (int i = 0; i < 10; ++i) {
++ for (int j = 0; j < 10; ++j) {
++ cerr << "t[" << i << "][" << j << "]: " << t_vals[i][j] << endl;
++ }
++ }
++
++ BaseType *btp = 0;
++ function_swath2grid(3, argv, *dds, &btp);
++
++ DBG(cerr << "btp->name(): " << btp->name() << endl);
++ CPPUNIT_ASSERT(btp->name() == "t");
++ CPPUNIT_ASSERT(btp->type() == dods_grid_c);
++
++ // Extract data; I know it's 10x16 from debugging output
++ dods_float64 values[10][16];
++ Grid *g = static_cast<Grid*>(btp);
++ g->get_array()->value(&values[0][0]);
++
++ Grid::Map_iter m = g->map_begin();
++ dods_float64 lat[10];
++ static_cast<Array*>(*m)->value(&lat[0]);
++
++ ++m;
++ dods_float64 lon[16];
++ static_cast<Array*>(*m)->value(&lon[0]);
++
++ cerr << "Output values:" << endl;
++ for (int i = 0; i < 10; ++i) {
++ for (int j = 0; j < 16; ++j) {
++ cerr << "t[" << i << "][" << j << "] == lon: " << lon[j] << ", lat: " << lat[i] << " val: " << values[i][j] << endl;
++ }
++ }
++ }
++ catch (Error &e) {
++ DBG(cerr << e.get_error_message() << endl);
++ CPPUNIT_FAIL("array_return_test");
++ }
++ }
++};
++
++CPPUNIT_TEST_SUITE_REGISTRATION(s2gTest);
++
++int
++main( int, char** )
++{
++ CppUnit::TextTestRunner runner;
++ runner.addTest( CppUnit::TestFactoryRegistry::getRegistry().makeTest() );
++
++ bool wasSuccessful = runner.run( "", false ) ;
++
++ return wasSuccessful ? 0 : 1;
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/a3/a3f498cd850e8312c27336b44b772bc06e45db56.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/a3/a3f498cd850e8312c27336b44b772bc06e45db56.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/a3/a3f498cd850e8312c27336b44b772bc06e45db56.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/a3/a3f498cd850e8312c27336b44b772bc06e45db56.svn-base 2014-03-03 15:47:37.810232939 +0100
+@@ -0,0 +1,10 @@
++# three_array_1.das
++#
++# Created on: Dec 12, 2012
++# Author: jimg
++
++Attributes {
++ t{}
++ lon{}
++ lat{}
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/a4/a48ca81df02968d388c1aff08bdb983200a5cb0f.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/a4/a48ca81df02968d388c1aff08bdb983200a5cb0f.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/a4/a48ca81df02968d388c1aff08bdb983200a5cb0f.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/a4/a48ca81df02968d388c1aff08bdb983200a5cb0f.svn-base 2014-03-03 15:47:37.980232932 +0100
+@@ -0,0 +1,13 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<request reqID ="some_unique_value" >
++ <setContext name="dap_format">dap2</setContext>
++ <setContext name="xdap_accept">3.3</setContext>
++ <setContainer name="c" space="catalog">/data/nc/OWS_9_Data/AIRS_570672/AIRS_AQUA_L1B_BRIGHTNESS_20101026_1617.nc.gz</setContainer>
++ <define name="d">
++ <container name="c">
++ <constraint>swath2grid(topog,Latitude,Longitude)</constraint>
++ </container>
++ </define>
++ <get type="das" definition="d"/>
++</request>
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/bc/bceeadf67b7c887a5453ff7cc4e625483701f4e3.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/bc/bceeadf67b7c887a5453ff7cc4e625483701f4e3.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/bc/bceeadf67b7c887a5453ff7cc4e625483701f4e3.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/bc/bceeadf67b7c887a5453ff7cc4e625483701f4e3.svn-base 2014-03-03 15:47:37.403566289 +0100
+@@ -0,0 +1,109 @@
++
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2002,2003 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++// (c) COPYRIGHT URI/MIT 1999
++// Please read the full copyright statement in the file COPYRIGHT_URI.
++//
++// Authors:
++// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
++
++// Declarations for CE functions.
++//
++// 1/15/99 jhrg
++
++#ifndef _reproj_functions_h
++#define _reproj_functions_h
++
++#include "BESAbstractModule.h"
++#include "ServerFunction.h"
++#include "ServerFunctionsList.h"
++
++namespace libdap {
++
++void function_swath2array(int argc, BaseType * argv[], DDS &, BaseType **btpp);
++void function_swath2grid(int argc, BaseType * argv[], DDS &, BaseType **btpp);
++
++
++class SwathToGrid: public libdap::ServerFunction {
++public:
++ SwathToGrid()
++ {
++ setName("swath2grid");
++ setDescriptionString("This function echos back it's arguments as DAP data.");
++ setUsageString("swath2grid(dataArray, latitudeArray, longitudeArray)");
++ setRole("http://services.opendap.org/dap4/server-side-function/swath2grid");
++ setDocUrl("http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2grid");
++ setFunction(libdap::function_swath2grid);
++ setVersion("1.0");
++ }
++ virtual ~SwathToGrid()
++ {
++ }
++
++};
++
++class SwathToArray: public libdap::ServerFunction {
++public:
++ SwathToArray()
++ {
++ setName("swath2array");
++ setDescriptionString("This function echos back it's arguments as DAP data.");
++ setUsageString("swath2array(dataArray, latitudeArray, longitudeArray)");
++ setRole("http://services.opendap.org/dap4/server-side-function/swath2array");
++ setDocUrl("http://docs.opendap.org/index.php/Server_Side_Processing_Functions#swath2array");
++ setFunction(libdap::function_swath2array);
++ setVersion("1.0");
++ }
++ virtual ~SwathToArray()
++ {
++ }
++
++};
++
++
++class ReProjectionFunctions: public BESAbstractModule {
++public:
++ ReProjectionFunctions()
++ {
++ libdap::ServerFunctionsList::TheList()->add_function(new libdap::SwathToGrid());
++
++ libdap::ServerFunctionsList::TheList()->add_function(new libdap::SwathToArray());
++
++ }
++ virtual ~ReProjectionFunctions()
++ {
++ }
++ virtual void initialize(const string &modname);
++ virtual void terminate(const string &modname);
++
++ virtual void dump(ostream &strm) const;
++};
++
++
++
++
++} // namespace libdap
++
++#endif // _reproj_functions_h
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/bd/bd5bb3aeffa01d2e79bad1eba81402eb23ce33cd.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/bd/bd5bb3aeffa01d2e79bad1eba81402eb23ce33cd.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/bd/bd5bb3aeffa01d2e79bad1eba81402eb23ce33cd.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/bd/bd5bb3aeffa01d2e79bad1eba81402eb23ce33cd.svn-base 2014-03-03 15:47:37.976899599 +0100
+@@ -0,0 +1,137 @@
++/******************************************************************************
++ * $Id: BoundingBox.h 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: BoundingBox class definition
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 BOUNDINGBOX_H_
++#define BOUNDINGBOX_H_
++
++#include <gdal.h>
++#include <ogr_spatialref.h>
++#include <limits>
++#include <stdlib.h>
++
++using namespace std;
++
++/************************************************************************/
++/* ==================================================================== */
++/* My2DPoint */
++/* ==================================================================== */
++/************************************************************************/
++
++/**
++ * \class My2DPoint "BoundingBox.h"
++ *
++ * My2DPoint class is used to store the point coordinates.
++ */
++
++class My2DPoint
++{
++public:
++ double mi_X;
++ double mi_Y;
++
++ virtual ~My2DPoint();
++
++ My2DPoint()
++ {
++ mi_X = 0;
++ mi_Y = 0;
++ }
++
++ My2DPoint(const double& xx, const double& yy) :
++ mi_X(xx), mi_Y(yy)
++ {
++ }
++
++ My2DPoint(const My2DPoint& p) :
++ mi_X(p.mi_X), mi_Y(p.mi_Y)
++ {
++ }
++
++ My2DPoint& operator =(const My2DPoint& p)
++ {
++ mi_X = p.mi_X;
++ mi_Y = p.mi_Y;
++ return *this;
++ }
++};
++
++/************************************************************************/
++/* ==================================================================== */
++/* BoundingBox */
++/* ==================================================================== */
++/************************************************************************/
++
++/**
++ * \class BoundingBox "BoundingBox.h"
++ *
++ * BoundingBox class is used to transform bounding box between different
++ * Coordinate Reference System.
++ */
++
++class BoundingBox
++{
++public:
++ My2DPoint mo_LowerLeftPT;
++ My2DPoint mo_UpperRightPT;
++ OGRSpatialReference mo_CRS;
++
++ BoundingBox(const My2DPoint& llpt, const My2DPoint& urpt, OGRSpatialReference& crs) :
++ mo_LowerLeftPT(llpt), mo_UpperRightPT(urpt), mo_CRS(crs)
++ {
++
++ }
++
++ BoundingBox(OGRSpatialReference& crs) :
++ mo_LowerLeftPT(0,0), mo_UpperRightPT(0,0), mo_CRS(crs)
++ {
++
++ }
++ BoundingBox& operator =(const BoundingBox& box)
++ {
++ mo_LowerLeftPT = box.mo_LowerLeftPT;
++ mo_UpperRightPT = box.mo_UpperRightPT;
++ mo_CRS = box.mo_CRS;
++ return *this;
++ }
++
++ BoundingBox();
++ virtual ~BoundingBox();
++
++ BoundingBox Transform(OGRSpatialReference&, int&);
++ BoundingBox TransformWorkExtend(OGRSpatialReference&, int&);
++ BoundingBox Transform(const double*);
++};
++
++CPLErr CPL_DLL CPL_STDCALL bBox_transFormmate( OGRSpatialReference&,
++ OGRSpatialReference&,
++ My2DPoint& lowLeft,
++ My2DPoint& upRight);
++
++#endif /* BOUNDINGBOX_H_ */
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/d2/d2f2e54b019cc687d4f25e9e0e840b3d0e0cdaec.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/d2/d2f2e54b019cc687d4f25e9e0e840b3d0e0cdaec.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/d2/d2f2e54b019cc687d4f25e9e0e840b3d0e0cdaec.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/d2/d2f2e54b019cc687d4f25e9e0e840b3d0e0cdaec.svn-base 2014-03-03 15:47:37.846899604 +0100
+@@ -0,0 +1,48 @@
++BES.ServerAdministrator=root@null.dev
++
++BES.User=user_name
++BES.Group=group_name
++
++BES.LogName=./bes.log
++BES.LogVerbose=no
++
++BES.modules=dap,cmd,nc,h4,fong,fonc
++BES.module.dap=@libdir@/bes/libdap_module.so
++BES.module.cmd=@libdir@/bes/libdap_xml_module.so
++
++BES.module.nc=@libdir@/bes/libnc_module.so
++BES.module.h4=@libdir@/bes/libhdf4_module.so
++
++BES.module.fong=@libdir@/bes/libfong_module.so
++BES.module.fonc=@libdir@/bes/libfonc_module.so
++
++BES.Catalog.catalog.RootDirectory=@abs_top_srcdir@
++BES.Data.RootDirectory=/dev/null
++
++BES.Catalog.catalog.TypeMatch=nc:.*.nc(.bz2|.gz|.Z)?$;h4:.*.(hdf|HDF|eos)(.bz2|.gz|.Z)?$;
++
++BES.Catalog.catalog.Include=;
++BES.Catalog.catalog.Exclude=^\..*;
++
++BES.FollowSymLinks=No
++BES.Catalog.catalog.FollowSymLinks=No
++
++BES.ServerPort=10002
++
++BES.CacheDir=/tmp
++BES.CachePrefix=bes_cache
++BES.CacheSize=500
++
++BES.Container.Persistence=strict
++
++BES.Memory.GlobalArea.EmergencyPoolSize=1
++BES.Memory.GlobalArea.MaximumHeapSize=20
++BES.Memory.GlobalArea.Verbose=no
++BES.Memory.GlobalArea.ControlHeap=no
++
++BES.ProcessManagerMethod=multiple
++
++BES.DefaultResponseMethod=POST
++
++FONg.TempDirectory=@abs_top_srcdir@/tests
++
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/d9/d934c25630e184bf0b7bcaf42ac44a390652631c.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/d9/d934c25630e184bf0b7bcaf42ac44a390652631c.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/d9/d934c25630e184bf0b7bcaf42ac44a390652631c.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/d9/d934c25630e184bf0b7bcaf42ac44a390652631c.svn-base 2014-03-03 15:47:37.843566270 +0100
+@@ -0,0 +1,360 @@
++/******************************************************************************
++ * $Id: BoundingBox.cpp 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: BoundingBox class implementation, enable transform bounding box
++ * between different CRS
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 <vector>
++#include <iostream>
++
++#include "BoundingBox.h"
++#include "wcs_error.h"
++
++using namespace std;
++
++My2DPoint::~My2DPoint()
++{
++
++}
++
++BoundingBox::BoundingBox()
++{
++
++}
++
++BoundingBox::~BoundingBox()
++{
++
++}
++
++BoundingBox BoundingBox::TransformWorkExtend(OGRSpatialReference &dstCRS, int &IsOK)
++{
++ if (mo_CRS.IsSame(&dstCRS))
++ {
++ IsOK = TRUE;
++ return *this;
++ }
++
++ OGRCoordinateTransformation *poCT = OGRCreateCoordinateTransformation(&mo_CRS, &dstCRS);
++ if (poCT == NULL)
++ {
++ IsOK = FALSE;
++ return *this;
++ }
++
++ double xdes = (mo_UpperRightPT.mi_X - mo_LowerLeftPT.mi_X) / 100;
++
++ if (mo_CRS.IsGeographic()
++ && mo_UpperRightPT.mi_X < mo_LowerLeftPT.mi_X
++ && mo_LowerLeftPT.mi_X > 0 && mo_UpperRightPT.mi_X < 0)
++ {
++ xdes = (360 + mo_UpperRightPT.mi_X - mo_LowerLeftPT.mi_X) / 100;
++ }
++
++ vector<double> x;
++ vector<double> y;
++ //up and down edge
++ for (double stepX = mo_LowerLeftPT.mi_X; stepX < mo_UpperRightPT.mi_X; stepX
++ += xdes)
++ {
++ x.push_back(stepX);
++ y.push_back(mo_UpperRightPT.mi_Y);
++ x.push_back(stepX);
++ y.push_back(mo_LowerLeftPT.mi_Y);
++ }
++ x.push_back(mo_UpperRightPT.mi_X);
++ y.push_back(mo_UpperRightPT.mi_Y);
++ x.push_back(mo_UpperRightPT.mi_X);
++ y.push_back(mo_LowerLeftPT.mi_Y);
++
++ double yMin = numeric_limits<double>::max();
++ double yMax = numeric_limits<double>::min();
++
++ int k = 0;
++ vector<int> bSuccess;
++ vector<double> tmpX;
++ vector<double> tmpY;
++
++ for (unsigned int i = 0; i < x.size(); i++)
++ {
++ tmpX.push_back(x[i]);
++ tmpY.push_back(y[i]);
++ bSuccess.push_back(0);
++ }
++
++ poCT->TransformEx(x.size(), &tmpX[0], &tmpY[0], NULL, &bSuccess[0]);
++
++ for (unsigned int n = 0; n < x.size(); n++)
++ {
++ if (bSuccess[n])
++ {
++ ++k;
++ yMin = MIN(yMin,tmpY[n]);
++ yMax = MAX(yMax,tmpY[n]);
++ }
++ }
++
++ if (k < 80)
++ {
++ IsOK = FALSE;
++ OCTDestroyCoordinateTransformation(poCT);
++ return *this;
++ }
++
++ //find xmin on left edge and xmax on right edge
++ double xMin;
++ double xMax;
++
++ double tmpPTX[2];
++ double tmpPTY[2];
++
++ int isSucc[2];
++
++ tmpPTX[0] = mo_LowerLeftPT.mi_X;
++ tmpPTX[1] = mo_LowerLeftPT.mi_X;
++ tmpPTY[0] = mo_LowerLeftPT.mi_Y;
++ tmpPTY[1] = mo_UpperRightPT.mi_Y;
++
++ poCT->TransformEx(2, tmpPTX, tmpPTY, NULL, isSucc);
++ if (isSucc[0] && isSucc[1])
++ {
++ xMin = MIN(tmpPTX[0],tmpPTX[1]);
++ }
++ else
++ {
++ OCTDestroyCoordinateTransformation(poCT);
++ IsOK = FALSE;
++ return *this;
++ }
++
++ tmpPTX[0] = mo_UpperRightPT.mi_X;
++ tmpPTX[1] = mo_UpperRightPT.mi_X;
++ tmpPTY[0] = mo_UpperRightPT.mi_Y;
++ tmpPTY[1] = mo_LowerLeftPT.mi_Y;
++
++ poCT->TransformEx(2, tmpPTX, tmpPTY, NULL, isSucc);
++ if (isSucc[0] && isSucc[1])
++ {
++ xMax = MAX(tmpPTX[0],tmpPTX[1]);
++ }
++ else
++ {
++ OCTDestroyCoordinateTransformation(poCT);
++ IsOK = FALSE;
++ return *this;
++ }
++
++ BoundingBox bbox(My2DPoint(xMin, yMin), My2DPoint(xMax, yMax), dstCRS);
++
++ if (dstCRS.IsGeographic())
++ {
++ if (xMin > 180)
++ xMin = xMin - 360;
++ if (xMax > 180)
++ xMax = xMax - 360;
++
++ if (xMin >= 180.)
++ xMin = 180.;
++ if (xMin <= -180.)
++ xMin = -180.;
++ if (xMax >= 180.)
++ xMax = 180.;
++ if (xMax <= -180.)
++ xMax = -180.;
++
++ if (yMin < 0.)
++ yMin = 0.;
++ if (yMax > 90.)
++ yMax = 90.;
++ }
++ OCTDestroyCoordinateTransformation(poCT);
++ IsOK = TRUE;
++ return BoundingBox(My2DPoint(xMin, yMin), My2DPoint(xMax, yMax), dstCRS);
++}
++
++BoundingBox BoundingBox::Transform(const double GeoTransform[])
++{
++ My2DPoint llPt;
++ My2DPoint urPt;
++ llPt.mi_X = GeoTransform[0] + GeoTransform[1] * mo_LowerLeftPT.mi_X + GeoTransform[2] * mo_LowerLeftPT.mi_Y;
++ llPt.mi_Y = GeoTransform[3] + GeoTransform[4] * mo_LowerLeftPT.mi_X + GeoTransform[5] * mo_LowerLeftPT.mi_Y;
++ urPt.mi_X = GeoTransform[0] + GeoTransform[1] * mo_UpperRightPT.mi_X + GeoTransform[2] * mo_UpperRightPT.mi_Y;
++ urPt.mi_Y = GeoTransform[3] + GeoTransform[4] * mo_UpperRightPT.mi_X + GeoTransform[5] * mo_UpperRightPT.mi_Y;
++
++ return BoundingBox(llPt,urPt,mo_CRS);
++}
++
++/**
++ * Transform Coordinates of lowercorner_left and upcorner_right
++ * lowLeft, upRight.
++ * the return value has considered the case of image area crossing 180/-180 longitude line,
++ * so lowLeft.x maybe bigger than upRight.x
++ */
++CPLErr CPL_STDCALL bBox_transFormmate(OGRSpatialReference& oSrcCRS,
++ OGRSpatialReference& oDesCRS, My2DPoint& lowLeft, My2DPoint& upRight)
++{
++ if (oSrcCRS.IsSame(&oDesCRS))
++ return CE_None;
++
++ OGRCoordinateTransformation *poCT = OGRCreateCoordinateTransformation(&oSrcCRS, &oDesCRS);
++ if (poCT == NULL)
++ {
++ SetWCS_ErrorLocator("bBox_transFormmate()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Create \"OGRCoordinateTransformation\"");
++ return CE_Failure;
++ }
++
++ double xdes = (upRight.mi_X - lowLeft.mi_X) / 100;
++ if (oSrcCRS.IsGeographic() && upRight.mi_X < lowLeft.mi_X && lowLeft.mi_X > 0 && upRight.mi_X < 0)
++ {
++ xdes = (360 + upRight.mi_X - lowLeft.mi_X) / 100;
++ }
++
++ vector<double> x, y;
++ //up and down edge
++ for (double stepX = lowLeft.mi_X; stepX < upRight.mi_X; stepX += xdes)
++ {
++ x.push_back(stepX);
++ y.push_back(upRight.mi_Y);
++ x.push_back(stepX);
++ y.push_back(lowLeft.mi_Y);
++ }
++ x.push_back(upRight.mi_X);
++ y.push_back(upRight.mi_Y);
++ x.push_back(upRight.mi_X);
++ y.push_back(lowLeft.mi_Y);
++
++ double yMin = numeric_limits<double>::max();
++ double yMax = -numeric_limits<double>::max();
++
++ int k = 0;
++ vector<int> bSuccess;
++ vector<double> tmpX;
++ vector<double> tmpY;
++
++ for (unsigned int i = 0; i < x.size(); i++)
++ {
++ tmpX.push_back(x[i]);
++ tmpY.push_back(y[i]);
++ bSuccess.push_back(0);
++ }
++
++ poCT->TransformEx(x.size(), &tmpX[0], &tmpY[0], NULL, &bSuccess[0]);
++
++ for (unsigned int n = 0; n < x.size(); n++)
++ {
++ if (bSuccess[n])
++ {
++ ++k;
++ yMin = MIN(yMin,tmpY[n]);
++ yMax = MAX(yMax,tmpY[n]);
++ }
++ }
++
++ if (k < 80)
++ {
++ OCTDestroyCoordinateTransformation(poCT);
++ SetWCS_ErrorLocator("bBox_transFormmate()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Transform Coordinates");
++ return CE_Failure;
++ }
++
++ double xMin;
++ double xMax;
++
++ //find xmin on left edge and xmax on right edge
++ double tmpPTX[2];
++ double tmpPTY[2];
++ int isOK[2];
++
++ tmpPTX[0] = lowLeft.mi_X;
++ tmpPTX[1] = lowLeft.mi_X;
++ tmpPTY[0] = upRight.mi_Y;
++ tmpPTY[1] = lowLeft.mi_Y;
++
++ poCT->TransformEx(2, tmpPTX, tmpPTY, NULL, isOK);
++ if (isOK[0] && isOK[1])
++ {
++ xMin = MIN(tmpPTX[0],tmpPTX[1]);
++ }
++ else
++ {
++ OCTDestroyCoordinateTransformation(poCT);
++ SetWCS_ErrorLocator("bBox_transFormmate()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Transform Coordinates");
++ return CE_Failure;
++ }
++
++ tmpPTX[0] = upRight.mi_X;
++ tmpPTX[1] = upRight.mi_X;
++ tmpPTY[0] = upRight.mi_Y;
++ tmpPTY[1] = lowLeft.mi_Y;
++
++ poCT->TransformEx(2, tmpPTX, tmpPTY, NULL, isOK);
++ if (isOK[0] && isOK[1])
++ {
++ xMax = MAX(tmpPTX[0],tmpPTX[1]);
++ }
++ else
++ {
++ SetWCS_ErrorLocator("bBox_transFormmate()");
++ OCTDestroyCoordinateTransformation(poCT);
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Transform Coordinates");
++ return CE_Failure;
++ }
++
++ lowLeft.mi_X = xMin;
++ lowLeft.mi_Y = yMin;
++ upRight.mi_X = xMax;
++ upRight.mi_Y = yMax;
++
++ if (oDesCRS.IsGeographic())
++ {
++ if (xMin > 180)
++ lowLeft.mi_X = xMin - 360;
++ if (xMax > 180)
++ upRight.mi_X = xMax - 360;
++
++ if (lowLeft.mi_X >= 180.)
++ lowLeft.mi_X = 180.;
++ if (lowLeft.mi_X <= -180.)
++ lowLeft.mi_X = -180.;
++ if (upRight.mi_X >= 180.)
++ upRight.mi_X = 180.;
++ if (upRight.mi_X <= -180.)
++ upRight.mi_X = -180.;
++
++ if (lowLeft.mi_Y <= -90.)
++ lowLeft.mi_Y = -90.;
++ if (upRight.mi_Y >= 90.)
++ upRight.mi_Y = 90.;
++ }
++ OCTDestroyCoordinateTransformation(poCT);
++
++ return CE_None;
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/db/dbe4c7bb62ab52db2ffe9a04dcc82422b69d5bff.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/db/dbe4c7bb62ab52db2ffe9a04dcc82422b69d5bff.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/db/dbe4c7bb62ab52db2ffe9a04dcc82422b69d5bff.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/db/dbe4c7bb62ab52db2ffe9a04dcc82422b69d5bff.svn-base 2014-03-03 15:47:37.980232932 +0100
+@@ -0,0 +1,124 @@
++/******************************************************************************
++ * $Id: NC_GOES_Dataset.h 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: NC_GOES_Dataset class definition
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 NC_GOES_DATASET_H_
++#define NC_GOES_DATASET_H_
++
++#include <string>
++#include "AbstractDataset.h"
++#include "wcsUtil.h"
++
++using namespace std;
++
++/************************************************************************/
++/* ==================================================================== */
++/* NC_GOES_Dataset */
++/* ==================================================================== */
++/************************************************************************/
++
++//! NC_GOES_Dataset is a subclass of AbstractDataset, used to process NOAA GOES data.
++
++/**
++ * \class NC_GOES_Dataset "NC_GOES_Dataset.h"
++ *
++ * GOES satellites provide the kind of continuous monitoring necessary for
++ * intensive data analysis. They circle the Earth in a geosynchronous orbit,
++ * which means they orbit the equatorial plane of the Earth at a speed
++ * matching the Earth's rotation. This allows them to hover continuously
++ * over one position on the surface. The geosynchronous plane is about
++ * 35,800 km (22,300 miles) above the Earth, high enough to allow the
++ * satellites a full-disc view of the Earth. Because they stay above a
++ * fixed spot on the surface, they provide a constant vigil for the atmospheric
++ * "triggers" for severe weather conditions such as tornadoes, flash floods,
++ * hail storms, and hurricanes. When these conditions develop the GOES
++ * satellites are able to monitor storm development and track their movements.
++ *
++ * GOES satellite imagery is also used to estimate rainfall during
++ * the thunderstorms and hurricanes for flash flood warnings, as well
++ * as estimates snowfall accumulations and overall extent of snow cover.
++ * Such data help meteorologists issue winter storm warnings and spring
++ * snow melt advisories. Satellite sensors also detect ice fields and map
++ * the movements of sea and lake ice.
++ *
++ * For more inforamtion about NOAA GOES data, please access
++ * <a href=http://www.oso.noaa.gov/GOES/>http://www.oso.noaa.gov/GOES/</a>
++ *
++ * NC_GOES_Dataset is a subclass of AbstractDataset, which is used to
++ * process GOES Imager and Sounder products.
++ */
++
++class NC_GOES_Dataset : public AbstractDataset
++{
++protected:
++ string m_ncLatDataSetName;
++ string m_ncLonDataSetName;
++ string m_ncCoverageIDName;
++ int mi_RectifiedImageXSize;
++ int mi_RectifiedImageYSize;
++ int mi_GoesSrcImageXSize;
++ int mi_GoesSrcImageYSize;
++
++ double mb_LatLonBBox[4];
++ double mdSrcGeoMinX;
++ double mdSrcGeoMinY;
++ double mdSrcGeoMaxX;
++ double mdSrcGeoMaxY;
++
++ vector<GDAL_GCP> m_gdalGCPs;
++
++public:
++ CPLErr SetGCPGeoRef4VRTDataset(GDALDataset* );
++ CPLErr SetGeoBBoxAndGCPs(GDALDataset* hSrcDS);
++ CPLErr RectifyGOESDataSet();
++ CPLErr setResampleStandard(GDALDataset* hSrcDS, int& xRSValue, int& yRSValue);
++
++ int isValidLatitude(const double &lat)
++ {
++ return (lat >= -90 && lat <= 90);
++ }
++ int isValidLongitude(const double &lon)
++ {
++ return (lon >= -180 && lon <= 180);
++ }
++
++ virtual CPLErr SetGeoTransform();
++ virtual CPLErr SetMetaDataList(GDALDataset* hSrcDS);
++ virtual CPLErr SetNativeCRS();
++ virtual CPLErr SetGDALDataset(const int isSimple=0);
++ virtual CPLErr InitialDataset(const int isSimple=0);
++ virtual CPLErr GetGeoMinMax(double geoMinMax[]);
++
++public:
++ NC_GOES_Dataset();
++ NC_GOES_Dataset(const string& id, vector<int> &rBandList);
++ virtual ~NC_GOES_Dataset();
++};
++
++#endif /* NC_GOES_DATASET_H_ */
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/ed/ed878e0243e84e5e05dc18b0ec24d13ce9146358.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/ed/ed878e0243e84e5e05dc18b0ec24d13ce9146358.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/ed/ed878e0243e84e5e05dc18b0ec24d13ce9146358.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/ed/ed878e0243e84e5e05dc18b0ec24d13ce9146358.svn-base 2014-03-03 15:47:37.806899605 +0100
+@@ -0,0 +1,730 @@
++
++// -*- mode: c++; c-basic-offset:4 -*-
++
++// This file is part of libdap, A C++ implementation of the OPeNDAP Data
++// Access Protocol.
++
++// Copyright (c) 2012 OPeNDAP, Inc.
++// Author: James Gallagher <jgallagher@opendap.org>
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2.1 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++//
++// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
++
++#include <cstdlib>
++
++#define DODS_DEBUG
++
++#include "DAP_Dataset.h"
++
++#include "Array.h"
++#include "Grid.h"
++#include "Float64.h"
++
++#include "ce_functions.h"
++#include "util.h"
++#include "debug.h"
++
++using namespace libdap;
++using namespace std;
++
++#if 0
++#define GOES_TIME_DEBUG FALSE
++#endif
++
++namespace libdap {
++
++DAP_Dataset::DAP_Dataset()
++{
++}
++
++/************************************************************************/
++/* ~DAP_Dataset() */
++/************************************************************************/
++
++/**
++ * \brief Destroy an open DAP_Dataset object.
++ *
++ * This is the accepted method of closing a DAP_Dataset dataset and
++ * deallocating all resources associated with it.
++ */
++
++DAP_Dataset::~DAP_Dataset()
++{
++}
++
++/************************************************************************/
++/* DAP_Dataset() */
++/************************************************************************/
++
++/**
++ * \brief Create an DAP_Dataset object.
++ *
++ * This is the accepted method of creating a DAP_Dataset object and
++ * allocating all resources associated with it.
++ *
++ * @param id The coverage identifier.
++ *
++ * @param rBandList The field list selected for this coverage. For TRMM
++ * daily data, the user could specify multiple days range in request.
++ * Each day is seemed as one field.
++ *
++ * @return A DAP_Dataset object.
++ */
++
++DAP_Dataset::DAP_Dataset(const string& id, vector<int> &rBandList) :
++ AbstractDataset(id, rBandList)
++{
++ md_MissingValue = 0;
++ mb_GeoTransformSet = FALSE;
++}
++
++/**
++ * @brief Initialize a DAP Dataset using Array objects already read.
++ *
++ *
++ */
++
++DAP_Dataset::DAP_Dataset(Array *src, Array *lat, Array *lon) :
++ AbstractDataset(), m_src(src), m_lat(lat), m_lon(lon)
++{
++#if 1
++ // TODO Remove these?
++ DBG(cerr << "Registering GDAL drivers" << endl);
++ GDALAllRegister();
++ OGRRegisterAll();
++#endif
++
++ CPLSetErrorHandler(CPLQuietErrorHandler);
++
++ // Read this from the 'missing_value' or '_FillValue' attributes
++ string missing_value = m_src->get_attr_table().get_attr("missing_value");
++ if (missing_value.empty())
++ missing_value = m_src->get_attr_table().get_attr("_FillValue");
++
++ if (!missing_value.empty())
++ md_MissingValue = atof(missing_value.c_str());
++ else
++ md_MissingValue = 0;
++
++ mb_GeoTransformSet = FALSE;
++}
++
++/************************************************************************/
++/* InitialDataset() */
++/************************************************************************/
++
++/**
++ * \brief Initialize the GOES dataset with NetCDF format.
++
++ * This method is the implementation for initializing a GOES dataset with NetCDF format.
++ * Within this method, SetNativeCRS(), SetGeoTransform() and SetGDALDataset()
++ * will be called to initialize an GOES dataset.
++ *
++ * @note To use this, call this method and then access the GDALDataset that
++ * contains the reprojected array using maptr_DS.get().
++ *
++ * @param isSimple the WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::InitialDataset(const int isSimple)
++{
++ DBG(cerr << "In InitialDataset" << endl);
++
++ // Might break that operation out so the remap is a separate call
++ if (CE_None != SetNativeCRS() || CE_None != SetGeoTransform())
++ throw Error("Could not set the dataset native CRS or the GeoTransform.");
++
++ DBG(cerr << "Before SetGDALDataset" << endl);
++
++ if (CE_None != SetGDALDataset(isSimple)) {
++ GDALClose(maptr_DS.release());
++ throw Error("Could not reproject the dataset.");
++ }
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetDAPArray() */
++/************************************************************************/
++
++/**
++ * @brief Build a DAP Array from the GDALDataset
++ */
++Array *DAP_Dataset::GetDAPArray()
++{
++ DBG(cerr << "In GetDAPArray" << endl);
++ DBG(cerr << "maptr_DS: " << maptr_DS.get() << endl);
++ DBG(cerr << "raster band count: " << maptr_DS->GetRasterCount() << endl);
++
++ // There should be just one band
++ if (maptr_DS->GetRasterCount() != 1)
++ throw Error("In function swath2grid(), expected a single raster band.");
++
++ // Get the x and y dimensions of the raster band
++ int x = maptr_DS->GetRasterXSize();
++ int y = maptr_DS->GetRasterYSize();
++ GDALRasterBand *rb = maptr_DS->GetRasterBand(1);
++ if (!rb)
++ throw Error("In function swath2grid(), could not access the raster data.");
++
++ // Since the DAP_Dataset code works with all data values as doubles,
++ // Assume the raster band has GDAL type GDT_Float64, but test anyway
++ if (GDT_Float64 != rb->GetRasterDataType())
++ throw Error("In function swath2grid(), expected raster data to be of type double.");
++
++ DBG(cerr << "Destination array will have dimensions: " << x << ", " << y << endl);
++
++ Array *a = new Array(m_src->name(), new Float64(m_src->name()));
++
++ // Make the result array have two dimensions
++ Array::Dim_iter i = m_src->dim_begin();
++
++ a->append_dim(x, m_src->dimension_name(i));
++ ++i;
++
++ if (i == m_src->dim_end())
++ throw Error("In function swath2grid(), expected source array to have two dimensions (2).");
++
++ a->append_dim(y, m_src->dimension_name(i));
++
++ // Poke in the data values
++ /* RasterIO ( GDALRWFlag eRWFlag,
++ int nXOff,
++ int nYOff,
++ int nXSize,
++ int nYSize,
++ void * pData,
++ int nBufXSize,
++ int nBufYSize,
++ GDALDataType eBufType,
++ int nPixelSpace,
++ int nLineSpace
++ ) */
++ vector<double> data(x * y);
++ rb->RasterIO(GF_Read, 0, 0, x, y, &data[0], x, y, GDT_Float64, 0, 0);
++
++ // NB: set_value() copies into new storage
++ a->set_value(data, data.size());
++
++ // Now poke in some attributes
++ // TODO Make these CF attributes
++ string projection_info = maptr_DS->GetProjectionRef();
++ string gcp_projection_info = maptr_DS->GetGCPProjection();
++
++ // This sets the instance variable that holds the geotransform coefs. These
++ // are needed by the GetDAPGrid() method.
++ if (CE_None != maptr_DS->GetGeoTransform (m_geo_transform_coef))
++ throw Error("In function swath2grid(), could not access the geo transform data.");
++
++ DBG(cerr << "projection_info: " << projection_info << endl);
++ DBG(cerr << "gcp_projection_info: " << gcp_projection_info << endl);
++ DBG(cerr << "geo_transform coefs: " << double_to_string(m_geo_transform_coef[0]) << endl);
++
++ AttrTable &attr = a->get_attr_table();
++ attr.append_attr("projection", "String", projection_info);
++ attr.append_attr("gcp_projection", "String", gcp_projection_info);
++ for (unsigned int i = 0; i < sizeof(m_geo_transform_coef); ++i) {
++ attr.append_attr("geo_transform_coefs", "String", double_to_string(m_geo_transform_coef[i]));
++ }
++
++ return a;
++}
++
++/************************************************************************/
++/* GetDAPGrid() */
++/************************************************************************/
++
++/**
++ * @brief Build a DAP Grid from the GDALDataset
++ */
++Grid *DAP_Dataset::GetDAPGrid()
++{
++ DBG(cerr << "In GetDAPGrid" << endl);
++
++ Array *a = GetDAPArray();
++ Array::Dim_iter i = a->dim_begin();
++ int lon_size = a->dimension_size(i);
++ int lat_size = a->dimension_size(++i);
++
++ Grid *g = new Grid(a->name());
++ g->add_var_nocopy(a, array);
++
++ // Add maps; assume lon, lat; only two dimensions
++ Array *lon = new Array("longitude", new Float64("longitude"));
++ lon->append_dim(lon_size);
++
++ vector<double> data(max(lon_size, lat_size)); // (re)use this for both lon and lat
++
++ // Compute values
++ // u = a*x + b*y
++ // v = c*x + d*y
++ // u,v --> x,y --> lon,lat
++ // The constants a, b, c, d are given by the 1, 2, 4, and 5 entries in the geotransform array.
++
++ if (m_geo_transform_coef[2] != 0)
++ throw Error("The transformed data's Geographic projection should not be rotated.");
++ for (int j = 0; j < lon_size; ++j) {
++ data[j] = m_geo_transform_coef[1] * j + m_geo_transform_coef[0];
++ }
++
++ // load (copy) values
++ lon->set_value(&data[0], lon_size);
++ // Set the map
++ g->add_var_nocopy(lon, maps);
++
++ // Now do the latitude map
++ Array *lat = new Array("latitude", new Float64("latitude"));
++ lat->append_dim(lat_size);
++
++ if (m_geo_transform_coef[4] != 0)
++ throw Error("The transformed data's Geographic projection should not be rotated.");
++ for (int k = 0; k < lat_size; ++k) {
++ data[k] = m_geo_transform_coef[5] * k + m_geo_transform_coef[3];
++ }
++
++ lat->set_value(&data[0], lat_size);
++ g->add_var_nocopy(lat, maps);
++
++ return g;
++}
++
++/************************************************************************/
++/* SetNativeCRS() */
++/************************************************************************/
++
++/**
++ * \brief Set the Native CRS for a GOES dataset.
++ *
++ * The method will set the CRS for a GOES dataset as an native CRS.
++ *
++ * Since the original GOES data adopt satellite CRS to recored its value,
++ * like MODIS swath data, each data point has its corresponding latitude
++ * and longitude value, those coordinates could be fetched in another two fields.
++ *
++ * The native CRS for GOES Imager and Sounder data is assigned to EPSG:4326 if
++ * both the latitude and longitude are existed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetNativeCRS()
++{
++ DBG(cerr << "In SetNativeCRS" << endl);
++
++ mo_NativeCRS.SetWellKnownGeogCS("WGS84");
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetGeoTransform() */
++/************************************************************************/
++
++/**
++ * \brief Set the affine GeoTransform matrix for a GOES data.
++ *
++ * The method will set a GeoTransform matrix for a GOES data
++ * by parsing the coordinates values existed in longitude and latitude field.
++ *
++ * The CRS for the bounding box is EPSG:4326.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetGeoTransform()
++{
++ DBG(cerr << "In SetGeoTransform" << endl);
++
++ // TODO Look at this; is this correct
++ // Assume the array is two dimensional
++ Array::Dim_iter i = m_src->dim_begin();
++#if 0
++ // ORIGINAL code; maybe wrong
++ int nXSize = m_src->dimension_size(i, true);
++ int nYSize = m_src->dimension_size(i + 1, true);
++#endif
++ // Data are in row-major order, so the first dim is the Y-axis value
++ int nYSize = m_src->dimension_size(i, true);
++ int nXSize = m_src->dimension_size(i + 1, true);
++
++ mi_SrcImageXSize = nXSize;
++ mi_SrcImageYSize = nYSize;
++
++ SetGeoBBoxAndGCPs(nXSize, nYSize);
++
++ double resX, resY;
++ if (mdSrcGeoMinX > mdSrcGeoMaxX && mdSrcGeoMinX > 0 && mdSrcGeoMaxX < 0)
++ resX = (360 + mdSrcGeoMaxX - mdSrcGeoMinX) / (nXSize - 1);
++ else
++ resX = (mdSrcGeoMaxX - mdSrcGeoMinX) / (nXSize - 1);
++
++ resY = (mdSrcGeoMaxY - mdSrcGeoMinY) / (nYSize - 1);
++
++ double res = MIN(resX, resY);
++
++ if (mdSrcGeoMinX > mdSrcGeoMaxX && mdSrcGeoMinX > 0 && mdSrcGeoMaxX < 0)
++ mi_RectifiedImageXSize = (int) ((360 + mdSrcGeoMaxX - mdSrcGeoMinX) / res) + 1;
++ else
++ mi_RectifiedImageXSize = (int) ((mdSrcGeoMaxX - mdSrcGeoMinX) / res) + 1;
++
++ mi_RectifiedImageYSize = (int) fabs((mdSrcGeoMaxY - mdSrcGeoMinY) / res) + 1;
++
++ DBG(cerr << "Source image size: " << nXSize << ", " << nYSize << endl);
++ DBG(cerr << "Rectified image size: " << mi_RectifiedImageXSize << ", " << mi_RectifiedImageYSize << endl);
++
++ md_Geotransform[0] = mdSrcGeoMinX;
++ md_Geotransform[1] = res;
++ md_Geotransform[2] = 0;
++ md_Geotransform[3] = mdSrcGeoMaxY;
++ md_Geotransform[4] = 0;
++ md_Geotransform[5] = -res;
++ mb_GeoTransformSet = TRUE;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetGeoBBoxAndGCPs() */
++/************************************************************************/
++
++/**
++ * \brief Set the native geographical bounding box and GCP array for a GOES data.
++ *
++ * The method will set the native geographical bounding box
++ * by comparing the coordinates values existed in longitude and latitude field.
++ *
++ * @param poVDS The GDAL dataset returned by calling GDALOpen() method.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++void DAP_Dataset::SetGeoBBoxAndGCPs(int nXSize, int nYSize)
++{
++ DBG(cerr << "In SetGeoBBoxAndGCPs" << endl);
++
++ // reuse the Dim_iter for both lat and lon arrays
++ Array::Dim_iter i = m_lat->dim_begin();
++ int nLatXSize = m_lat->dimension_size(i, true);
++ int nLatYSize = m_lat->dimension_size(i + 1, true);
++ i = m_lon->dim_begin();
++ int nLonXSize = m_lon->dimension_size(i, true);
++ int nLonYSize = m_lon->dimension_size(i + 1, true);
++
++ if (nXSize != nLatXSize || nLatXSize != nLonXSize || nYSize != nLatYSize || nLatYSize != nLonYSize)
++ throw Error("The size of latitude/longitude and data field does not match.");
++
++#if 0
++ /*
++ * Re-sample Standards:
++ * Height | Width
++ * (0, 500) every other one pixel
++ * [500, 1000) every other two pixels
++ * [1000,1500) every other three pixels
++ * [1500,2000) every other four pixels
++ * ... ...
++ */
++
++ int xSpace = 1;
++ int ySpace = 1;
++ //setResampleStandard(poVDS, xSpace, ySpace);
++
++ // TODO understand how GMU picked this value.
++ // xSpace and ySpace are the stride values for sampling in
++ // the x and y dimensions.
++ const int RESAMPLE_STANDARD = 500;
++
++ xSpace = int(nXSize / RESAMPLE_STANDARD) + 2;
++ ySpace = int(nYSize / RESAMPLE_STANDARD) + 2;
++#endif
++
++ m_lat->read();
++ m_lon->read();
++ double *dataLat = extract_double_array(m_lat);
++ double *dataLon = extract_double_array(m_lon);
++
++ DBG(cerr << "Past lat/lon data read" << endl);
++
++ try {
++
++ mdSrcGeoMinX = 360;
++ mdSrcGeoMaxX = -360;
++ mdSrcGeoMinY = 90;
++ mdSrcGeoMaxY = -90;
++
++ // Sample every other row and column
++ int xSpace = 2;
++ int ySpace = 2;
++
++ int nGCPs = 0;
++ GDAL_GCP gdalCGP;
++
++ for (int iLine = 0; iLine < nYSize - ySpace; iLine += ySpace) {
++ for (int iPixel = 0; iPixel < nXSize - xSpace; iPixel += xSpace) {
++ double x = *(dataLon + (iLine * nYSize) + iPixel);
++ double y = *(dataLat + (iLine * nYSize) + iPixel);
++
++ if (isValidLongitude(x) && isValidLatitude(y)) {
++ char pChr[64];
++ snprintf(pChr, 64, "%d", ++nGCPs);
++ GDALInitGCPs(1, &gdalCGP);
++ gdalCGP.pszId = strdup(pChr);
++ gdalCGP.pszInfo = strdup("");
++ gdalCGP.dfGCPLine = iLine;
++ gdalCGP.dfGCPPixel = iPixel;
++ gdalCGP.dfGCPX = x;
++ gdalCGP.dfGCPY = y;
++
++ DBG2(cerr << "iLine, iPixel: " << iLine << ", " << iPixel << " --> x,y: " << x << ", " << y << endl);
++
++ gdalCGP.dfGCPZ = 0;
++ m_gdalGCPs.push_back(gdalCGP);
++
++ mdSrcGeoMinX = MIN(mdSrcGeoMinX, gdalCGP.dfGCPX);
++ mdSrcGeoMaxX = MAX(mdSrcGeoMaxX, gdalCGP.dfGCPX);
++ mdSrcGeoMinY = MIN(mdSrcGeoMinY, gdalCGP.dfGCPY);
++ mdSrcGeoMaxY = MAX(mdSrcGeoMaxY, gdalCGP.dfGCPY);
++ }
++ }
++ }
++ }
++ catch (...) {
++ delete[] dataLat;
++ delete[] dataLon;
++ throw;
++ }
++
++ delete[] dataLat;
++ delete[] dataLon;
++
++ DBG(cerr << "Leaving SetGeoBBoxAndGCPs" << endl);
++}
++
++/************************************************************************/
++/* SetGDALDataset() */
++/************************************************************************/
++
++/**
++ * \brief Make a 'memory' dataset with one band
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetGDALDataset(const int isSimple)
++{
++ DBG(cerr << "In SetGDALDataset" << endl);
++
++ // NB: mi_RectifiedImageXSize & Y are set in SetGeoTransform()
++ GDALDataType eBandType = GDT_Float64;
++ // VRT, which was used in the original sample code, is not supported in this context, so I used MEM
++ GDALDriverH poDriver = GDALGetDriverByName("MEM");
++ if (!poDriver) {
++ throw Error("Failed to get MEM driver (" + string(CPLGetLastErrorMsg()) + ").");
++ }
++
++ GDALDataset* satDataSet = (GDALDataset*) GDALCreate(poDriver, "", mi_RectifiedImageXSize, mi_RectifiedImageYSize,
++ 1, eBandType, NULL);
++ if (!satDataSet) {
++ GDALClose(poDriver);
++ throw Error("Failed to create MEM dataSet (" + string(CPLGetLastErrorMsg()) + ").");
++ }
++
++ GDALRasterBand *poBand = satDataSet->GetRasterBand(1);
++ poBand->SetNoDataValue(md_MissingValue);
++
++ m_src->read();
++ double *data = extract_double_array(m_src);
++ if (CE_None != poBand->RasterIO(GF_Write, 0, 0, mi_RectifiedImageXSize, mi_RectifiedImageYSize, data,
++ mi_SrcImageXSize, mi_SrcImageYSize, eBandType, 0, 0)) {
++ GDALClose((GDALDatasetH) satDataSet);
++ throw Error("Failed to set satellite data band to MEM DataSet (" + string(CPLGetLastErrorMsg()) + ").");
++ }
++ delete[] data;
++
++ //set GCPs for this VRTDataset
++ if (CE_None != SetGCPGeoRef4VRTDataset(satDataSet)) {
++ GDALClose((GDALDatasetH) satDataSet);
++ throw Error("Could not georeference the virtual dataset (" + string(CPLGetLastErrorMsg()) + ").");
++ }
++
++ DBG(cerr << "satDataSet: " << satDataSet << endl);
++
++ maptr_DS.reset(satDataSet);
++
++ if (isSimple)
++ return CE_None;
++
++ return RectifyGOESDataSet();
++}
++
++/************************************************************************/
++/* SetGCPGeoRef4VRTDataset() */
++/************************************************************************/
++
++/**
++ * \brief Set the GCP array for the VRT dataset.
++ *
++ * This method is used to set the GCP array to created VRT dataset based on GDAL
++ * method SetGCPs().
++ *
++ * @param poVDS The VRT dataset.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetGCPGeoRef4VRTDataset(GDALDataset* poVDS)
++{
++ char* psTargetSRS;
++ mo_NativeCRS.exportToWkt(&psTargetSRS);
++
++#if (__GNUC__ >=4 && __GNUC_MINOR__ > 1)
++ if (CE_None != poVDS->SetGCPs(m_gdalGCPs.size(), (GDAL_GCP*) (m_gdalGCPs.data()), psTargetSRS)) {
++ OGRFree(psTargetSRS);
++ throw Error("Failed to set GCPs.");
++ }
++#else
++ {
++ if(CE_None!=poVDS->SetGCPs(m_gdalGCPs.size(), (GDAL_GCP*)&m_gdalGCPs[0], psTargetSRS))
++ {
++ OGRFree( psTargetSRS );
++ throw Error("Failed to set GCPs.");
++ }
++ }
++#endif
++
++ OGRFree(psTargetSRS);
++
++ return CE_None;
++}
++#if 0
++/************************************************************************/
++/* SetMetaDataList() */
++/************************************************************************/
++
++/**
++ * \brief Set the metadata list for this coverage.
++ *
++ * The method will set the metadata list for the coverage based on its
++ * corresponding GDALDataset object.
++ *
++ * @param hSrc the GDALDataset object corresponding to coverage.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::SetMetaDataList(GDALDataset* hSrcDS)
++{
++ // TODO Remove
++#if 0
++ mv_MetaDataList.push_back("Product_Description=The data was created by GMU WCS from NOAA GOES satellite data.");
++ mv_MetaDataList.push_back("unit=GVAR");
++ mv_MetaDataList.push_back("FillValue=0");
++ ms_FieldQuantityDef = "GVAR";
++ ms_AllowRanges = "0 65535";
++ ms_CoveragePlatform = "GOES-11";
++ ms_CoverageInstrument = "GOES-11";
++ ms_CoverageSensor = "Imager";
++#endif
++
++ return CE_None;
++}
++#endif
++/************************************************************************/
++/* GetGeoMinMax() */
++/************************************************************************/
++
++/**
++ * \brief Get the min/max coordinates of laitutude and longitude.
++ *
++ * The method will fetch the min/max coordinates of laitutude and longitude.
++ *
++ * @param geoMinMax an existing four double buffer into which the
++ * native geographical bounding box values will be placed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::GetGeoMinMax(double geoMinMax[])
++{
++ if (!mb_GeoTransformSet)
++ return CE_Failure;
++
++ geoMinMax[0] = mdSrcGeoMinX;
++ geoMinMax[2] = mdSrcGeoMinY;
++ geoMinMax[1] = mdSrcGeoMaxX;
++ geoMinMax[3] = mdSrcGeoMaxY;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* RectifyGOESDataSet() */
++/************************************************************************/
++
++/**
++ * \brief Convert the GOES dataset from satellite CRS project to grid CRS.
++ *
++ * The method will convert the GOES dataset from satellite CRS project to
++ * grid CRS based on GDAL API GDALReprojectImage;
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr DAP_Dataset::RectifyGOESDataSet()
++{
++ DBG(cerr << "In RectifyGOESDataSet" << endl);
++
++ char *pszDstWKT;
++ mo_NativeCRS.exportToWkt(&pszDstWKT);
++
++ GDALDriverH poDriver = GDALGetDriverByName("VRT"); // MEM
++ GDALDataset* rectDataSet = (GDALDataset*) GDALCreate(poDriver, "", mi_RectifiedImageXSize, mi_RectifiedImageYSize,
++ maptr_DS->GetRasterCount(), maptr_DS->GetRasterBand(1)->GetRasterDataType(), NULL);
++ if (NULL == rectDataSet) {
++ GDALClose(poDriver);
++ OGRFree(pszDstWKT);
++ throw Error("Failed to create \"MEM\" dataSet.");
++ }
++
++ rectDataSet->SetProjection(pszDstWKT);
++ rectDataSet->SetGeoTransform(md_Geotransform);
++
++ DBG(cerr << "rectDataSet: " << rectDataSet << endl);
++ DBG(cerr << "satDataSet: " << maptr_DS.get() << endl);
++
++ // FIXME Magic value of 0.125
++ if (CE_None != GDALReprojectImage(maptr_DS.get(), NULL, rectDataSet, pszDstWKT,
++ GRA_Lanczos /*GRA_NearestNeighbour*/, 0, 0.0/*0.125*/, NULL, NULL, NULL)) {
++ GDALClose(rectDataSet);
++ GDALClose(poDriver);
++ OGRFree(pszDstWKT);
++ throw Error("Failed to re-project satellite data from GCP CRS to geographical CRS.");
++ }
++
++ OGRFree(pszDstWKT);
++ GDALClose(maptr_DS.release());
++
++ maptr_DS.reset(rectDataSet);
++
++ DBG(cerr << "Leaving RectifyGOESDataSet" << endl);
++
++ return CE_None;
++}
++
++} // namespace libdap
+diff -Nur bes-3.12.0/functions.orig/swath2grid/.svn/pristine/ee/eed03539b992d9d129c49278cfb7203c371bfd39.svn-base bes-3.12.0/functions/swath2grid/.svn/pristine/ee/eed03539b992d9d129c49278cfb7203c371bfd39.svn-base
+--- bes-3.12.0/functions.orig/swath2grid/.svn/pristine/ee/eed03539b992d9d129c49278cfb7203c371bfd39.svn-base 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/.svn/pristine/ee/eed03539b992d9d129c49278cfb7203c371bfd39.svn-base 2014-03-03 15:47:37.976899599 +0100
+@@ -0,0 +1,625 @@
++/******************************************************************************
++ * $Id: TRMM_Dataset.cpp 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: NC_GOES_Dataset implementation for NOAA GOES data
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 "NC_GOES_Dataset.h"
++
++using namespace std;
++
++#define GOES_TIME_DEBUG FALSE
++
++NC_GOES_Dataset::NC_GOES_Dataset()
++{
++}
++
++/************************************************************************/
++/* ~NC_GOES_Dataset() */
++/************************************************************************/
++
++/**
++ * \brief Destroy an open NC_GOES_Dataset object.
++ *
++ * This is the accepted method of closing a NC_GOES_Dataset dataset and
++ * deallocating all resources associated with it.
++ */
++
++NC_GOES_Dataset::~NC_GOES_Dataset()
++{
++}
++
++/************************************************************************/
++/* NC_GOES_Dataset() */
++/************************************************************************/
++
++/**
++ * \brief Create an NC_GOES_Dataset object.
++ *
++ * This is the accepted method of creating a NC_GOES_Dataset object and
++ * allocating all resources associated with it.
++ *
++ * @param id The coverage identifier.
++ *
++ * @param rBandList The field list selected for this coverage. For TRMM
++ * daily data, the user could specify multiple days range in request.
++ * Each day is seemed as one field.
++ *
++ * @return A NC_GOES_Dataset object.
++ */
++
++NC_GOES_Dataset::NC_GOES_Dataset(const string& id, vector<int> &rBandList) :
++ AbstractDataset(id, rBandList)
++{
++ md_MissingValue = 0;
++ mb_GeoTransformSet = FALSE;
++}
++
++/************************************************************************/
++/* InitialDataset() */
++/************************************************************************/
++
++/**
++ * \brief Initialize the GOES dataset with NetCDF format.
++
++ * This method is the implementation for initializing a GOES dataset with NetCDF format.
++ * Within this method, SetNativeCRS(), SetGeoTransform() and SetGDALDataset()
++ * will be called to initialize an GOES dataset.
++ *
++ * @param isSimple the WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::InitialDataset(const int isSimple)
++{
++ vector<string> strSet;
++ unsigned int n = CsvburstCpp(ms_CoverageID, strSet, ':');
++ if (n != 4)
++ {
++ SetWCS_ErrorLocator("NC_GOES_Dataset::InitialDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Incorrect coverage ID.");
++ return CE_Failure;
++ }
++
++ ms_DataTypeName = strSet[0] + ":" + strSet[1];
++ ms_SrcFilename = StrTrims(strSet[2], " \'\"");
++ ms_DatasetName = strSet[3];
++
++ m_ncLatDataSetName = "NETCDF:" + ms_SrcFilename + ":latitude";
++ m_ncLonDataSetName = "NETCDF:" + ms_SrcFilename + ":longitude";
++ m_ncCoverageIDName = strSet[1] + ":" + strSet[2] + ":" + strSet[3];
++
++ GDALDataset* pSrc = (GDALDataset*) GDALOpenShared(m_ncCoverageIDName.c_str(), GA_ReadOnly);
++ if (pSrc == NULL)
++ {
++ SetWCS_ErrorLocator("NC_GOES_Dataset::InitialDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to open file \"%s\".", ms_SrcFilename.c_str());
++ return CE_Failure;
++ }
++
++ ms_NativeFormat = GDALGetDriverShortName(pSrc->GetDriver());
++
++ //setmetalist
++ SetMetaDataList(pSrc);
++
++ //set noValue
++ unsigned int nBandCount = pSrc->GetRasterCount();
++ if (nBandCount < 1)
++ {
++ GDALClose(pSrc);
++ SetWCS_ErrorLocator("NC_GOES_Dataset::InitialDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "The GOES file does not contain any raster band.");
++ return CE_Failure;
++ }
++
++ maptr_DS.reset(pSrc);
++
++ //set moNativeCRS and mGeoTransform
++ if (CE_None != SetNativeCRS() ||
++ CE_None != SetGeoTransform() ||
++ CE_None != SetGDALDataset(isSimple))
++ {
++ GDALClose(maptr_DS.release());
++ return CE_Failure;
++ }
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetNativeCRS() */
++/************************************************************************/
++
++/**
++ * \brief Set the Native CRS for a GOES dataset.
++ *
++ * The method will set the CRS for a GOES dataset as an native CRS.
++ *
++ * Since the original GOES data adopt satellite CRS to recored its value,
++ * like MODIS swath data, each data point has its corresponding latitude
++ * and longitude value, those coordinates could be fetched in another two fields.
++ *
++ * The native CRS for GOES Imager and Sounder data is assigned to EPSG:4326 if
++ * both the latitude and longitude are existed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetNativeCRS()
++{
++ if (CE_None == AbstractDataset::SetNativeCRS())
++ return CE_None;
++
++ GDALDataset* hLatDS = (GDALDataset*) GDALOpen(m_ncLatDataSetName.c_str(), GA_ReadOnly);
++ GDALDataset* hLonDS = (GDALDataset*) GDALOpen(m_ncLonDataSetName.c_str(), GA_ReadOnly);
++
++ if(hLatDS == NULL) {
++ m_ncLatDataSetName = "NETCDF:\"" + ms_SrcFilename + "\":lat";
++ hLatDS = (GDALDataset*) GDALOpen(m_ncLatDataSetName.c_str(), GA_ReadOnly);
++ }
++
++ if(hLonDS == NULL) {
++ m_ncLonDataSetName = "NETCDF:\"" + ms_SrcFilename + "\":lon";
++ hLonDS = (GDALDataset*) GDALOpen(m_ncLonDataSetName.c_str(), GA_ReadOnly);
++ }
++
++ if (hLatDS == NULL || hLonDS == NULL)
++ {
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetNativeCRS()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to open latitude/longitude sub-dataset.");
++ return CE_Failure;
++ }
++
++ mo_NativeCRS.SetWellKnownGeogCS("WGS84");
++
++ GDALClose(hLatDS);
++ GDALClose(hLonDS);
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetGeoTransform() */
++/************************************************************************/
++
++/**
++ * \brief Set the affine GeoTransform matrix for a GOES data.
++ *
++ * The method will set a GeoTransform matrix for a GOES data
++ * by parsing the coordinates values existed in longitude and latitude field.
++ *
++ * The CRS for the bounding box is EPSG:4326.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetGeoTransform()
++{
++ if (CE_None == AbstractDataset::SetGeoTransform())
++ return CE_None;
++
++ if (CE_None != SetGeoBBoxAndGCPs(maptr_DS.get()))
++ return CE_Failure;
++
++ double resX, resY;
++ if (mdSrcGeoMinX > mdSrcGeoMaxX && mdSrcGeoMinX > 0 && mdSrcGeoMaxX < 0)
++ resX = (360 + mdSrcGeoMaxX - mdSrcGeoMinX) / (maptr_DS->GetRasterXSize() - 1);
++ else
++ resX = (mdSrcGeoMaxX - mdSrcGeoMinX) / (maptr_DS->GetRasterXSize() - 1);
++
++ resY = (mdSrcGeoMaxY - mdSrcGeoMinY) / (maptr_DS->GetRasterYSize() - 1);
++
++ double res = MIN(resX,resY);
++
++ if (mdSrcGeoMinX > mdSrcGeoMaxX && mdSrcGeoMinX > 0 && mdSrcGeoMaxX < 0)
++ mi_RectifiedImageXSize = (int)((360 + mdSrcGeoMaxX - mdSrcGeoMinX) / res) + 1;
++ else
++ mi_RectifiedImageXSize = (int)((mdSrcGeoMaxX - mdSrcGeoMinX) / res) + 1;
++
++ mi_RectifiedImageYSize = (int)fabs((mdSrcGeoMaxY - mdSrcGeoMinY) / res) + 1;
++
++ md_Geotransform[0] = mdSrcGeoMinX;
++ md_Geotransform[1] = res;
++ md_Geotransform[2] = 0;
++ md_Geotransform[3] = mdSrcGeoMaxY;
++ md_Geotransform[4] = 0;
++ md_Geotransform[5] = -res;
++ mb_GeoTransformSet = TRUE;
++
++ return CE_None;
++}
++
++CPLErr NC_GOES_Dataset::setResampleStandard(GDALDataset* hSrcDS, int& xRSValue, int& yRSValue)
++{
++ static int RESAMPLE_STANDARD = 500;
++ int nXSize = hSrcDS->GetRasterXSize();
++ int nYSize = hSrcDS->GetRasterYSize();
++
++ xRSValue = int(nXSize / RESAMPLE_STANDARD) + 2;
++ yRSValue = int(nYSize / RESAMPLE_STANDARD) + 2;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetGeoBBoxAndGCPs() */
++/************************************************************************/
++
++/**
++ * \brief Set the native geographical bounding box and GCP array for a GOES data.
++ *
++ * The method will set the native geographical bounding box
++ * by comparing the coordinates values existed in longitude and latitude field.
++ *
++ * @param poVDS The GDAL dataset returned by calling GDALOpen() method.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetGeoBBoxAndGCPs(GDALDataset* poVDS)
++{
++ GDALDataset* hLatDS = (GDALDataset*) GDALOpen(m_ncLatDataSetName.c_str(), GA_ReadOnly);
++ GDALDataset* hLonDS = (GDALDataset*) GDALOpen(m_ncLonDataSetName.c_str(), GA_ReadOnly);
++
++ int nXSize = poVDS->GetRasterXSize();
++ int nYSize = poVDS->GetRasterYSize();
++
++ mi_GoesSrcImageXSize = nXSize;
++ mi_GoesSrcImageYSize = nYSize;
++
++ int nLatXSize = hLatDS->GetRasterXSize();
++ int nLatYSize = hLatDS->GetRasterYSize();
++ int nLonXSize = hLonDS->GetRasterXSize();
++ int nLonYSize = hLonDS->GetRasterYSize();
++
++ if (nXSize != nLatXSize || nLatXSize != nLonXSize || nYSize != nLatYSize || nLatYSize != nLonYSize)
++ {
++ GDALClose(hLatDS);
++ GDALClose(hLonDS);
++
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetGeoBBoxAndGCPs()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "The size of latitude/longitude and data field does not match.");
++
++ return CE_Failure;
++ }
++
++ /*
++ * Re-sample Standards:
++ * Height | Width
++ * (0, 500) every other one pixel
++ * [500, 1000) every other two pixels
++ * [1000,1500) every other three pixels
++ * [1500,2000) every other four pixels
++ * ... ...
++ */
++
++ int xSpace = 1;
++ int ySpace = 1;
++ setResampleStandard(poVDS, xSpace, ySpace);
++
++ int nGCPs = 0;
++ GDAL_GCP gdalCGP;
++
++ GDALRasterBand *poBandLat = hLatDS->GetRasterBand(1);
++ GDALRasterBand *poBandLon = hLonDS->GetRasterBand(1);
++ GDALDataType eDT = poBandLat->GetRasterDataType();
++ void *dataLat = NULL;
++ void *dataLon = NULL;
++
++ mdSrcGeoMinX = 360;
++ mdSrcGeoMaxX = -360;
++ mdSrcGeoMinY = 90;
++ mdSrcGeoMaxY = -90;
++
++ switch (eDT)
++ {
++ case GDT_Float32: //For GOES Imager and Sounder data
++ {
++ dataLat = (float *) CPLMalloc(nXSize * sizeof(float));
++ dataLon = (float *) CPLMalloc(nXSize * sizeof(float));
++
++ for (int iLine = 0; iLine < nYSize; iLine += ySpace)
++ {
++ if (iLine >= nYSize)
++ iLine = nYSize - 1;
++
++ poBandLat->RasterIO(GF_Read, 0, iLine, nXSize, 1, dataLat, nXSize, 1, GDT_Float32, 0, 0);
++ poBandLon->RasterIO(GF_Read, 0, iLine, nXSize, 1, dataLon, nXSize, 1, GDT_Float32, 0, 0);
++
++ for (int iPixel = 0; iPixel < nXSize; iPixel += xSpace)
++ {
++ if(iPixel >= nXSize)
++ iPixel = nXSize - 1;
++ double x = *((float *) dataLon + iPixel);
++ double y = *((float *) dataLat + iPixel);
++ if (isValidLongitude(x) && isValidLatitude(y))
++ {
++ char pChr[64];
++ sprintf(pChr, "%d", ++nGCPs);
++ GDALInitGCPs(1, &gdalCGP);
++ gdalCGP.pszId = strdup(pChr);
++ gdalCGP.pszInfo = strdup("");
++ gdalCGP.dfGCPLine = iLine;
++ gdalCGP.dfGCPPixel = iPixel;
++ gdalCGP.dfGCPX = x;
++ gdalCGP.dfGCPY = y;
++ gdalCGP.dfGCPZ = 0;
++ m_gdalGCPs.push_back(gdalCGP);
++ mdSrcGeoMinX = MIN(mdSrcGeoMinX,gdalCGP.dfGCPX );
++ mdSrcGeoMaxX = MAX(mdSrcGeoMaxX,gdalCGP.dfGCPX);
++ mdSrcGeoMinY = MIN(mdSrcGeoMinY,gdalCGP.dfGCPY);
++ mdSrcGeoMaxY = MAX(mdSrcGeoMaxY,gdalCGP.dfGCPY);
++ }
++ }
++ }
++
++ VSIFree((float *) dataLat);
++ VSIFree((float *) dataLon);
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ GDALClose(hLatDS);
++ GDALClose(hLonDS);
++
++ return CE_None;
++}
++
++
++/************************************************************************/
++/* SetGDALDataset() */
++/************************************************************************/
++
++/**
++ * \brief Set the GDALDataset object to GOES Imager and Sounder dataset.
++ *
++ * This method is used to set the GOES Imager and Sounder dataset based on GDAL
++ * class VRTDataset.
++ *
++ * @param isSimple the WCS request type. When user executing a DescribeCoverage
++ * request, isSimple is set to 1, and for GetCoverage, is set to 0.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetGDALDataset(const int isSimple)
++{
++ for(int i = 1; i <= maptr_DS->GetRasterCount(); ++i)
++ mv_BandList.push_back(i);
++
++ VRTDataset *poVDS = (VRTDataset *)VRTCreate(mi_RectifiedImageXSize, mi_RectifiedImageYSize);
++ if (poVDS == NULL)
++ {
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetGDALDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to create VRT DataSet.");
++ return CE_Failure;
++ }
++
++ VRTSourcedRasterBand *poVRTBand = NULL;
++ GDALRasterBand *poSrcBand = NULL;
++ GDALDataType eBandType;
++ for (unsigned int i = 0; i < mv_BandList.size(); i++)
++ {
++ poSrcBand = maptr_DS->GetRasterBand(mv_BandList[i]);
++ eBandType = poSrcBand->GetRasterDataType();
++ poVDS->AddBand(eBandType, NULL);
++ poVRTBand = (VRTSourcedRasterBand *) poVDS->GetRasterBand(i + 1);
++ poVRTBand->SetNoDataValue(md_MissingValue);
++
++ if (CE_None != poVRTBand->AddSimpleSource(poSrcBand, 0, 0,
++ mi_RectifiedImageXSize, mi_RectifiedImageYSize, 0, 0,
++ mi_RectifiedImageXSize, mi_RectifiedImageYSize, NULL, md_MissingValue))
++ {
++ GDALClose((GDALDatasetH) poVDS);
++ SetWCS_ErrorLocator("NC_GOES_Dataset::setGDALDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Add Simple Source into VRT DataSet.");
++ return CE_Failure;
++ }
++ }
++
++ //set GCPs for this VRTDataset
++ if (CE_None != SetGCPGeoRef4VRTDataset(poVDS))
++ {
++ GDALClose((GDALDatasetH) poVDS);
++ return CE_Failure;
++ }
++
++ GDALClose(maptr_DS.release());
++ maptr_DS.reset(poVDS);
++
++ if (isSimple)
++ return CE_None;
++
++ return RectifyGOESDataSet();
++}
++
++/************************************************************************/
++/* SetGCPGeoRef4VRTDataset() */
++/************************************************************************/
++
++/**
++ * \brief Set the GCP array for the VRT dataset.
++ *
++ * This method is used to set the GCP array to created VRT dataset based on GDAL
++ * method SetGCPs().
++ *
++ * @param poVDS The VRT dataset.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetGCPGeoRef4VRTDataset(GDALDataset* poVDS)
++{
++ char* psTargetSRS;
++ mo_NativeCRS.exportToWkt(&psTargetSRS);
++
++#if (__GNUC__ >=4 && __GNUC_MINOR__ > 1)
++ if (CE_None != poVDS->SetGCPs(m_gdalGCPs.size(), (GDAL_GCP*) (m_gdalGCPs.data()), psTargetSRS))
++ {
++ OGRFree(psTargetSRS);
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetGCPGeoRef4VRTDataset()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to set GCPs.");
++
++ return CE_Failure;
++ }
++#else
++ {
++ if(CE_None!=poVDS->SetGCPs(m_gdalGCPs.size(), (GDAL_GCP*)&m_gdalGCPs[0], psTargetSRS))
++ {
++ OGRFree( psTargetSRS );
++ SetWCS_ErrorLocator("NC_GOES_Dataset::SetGCPGeoRef4VRTDataset()");
++ WCS_Error(CE_Failure,OGC_WCS_NoApplicableCode,"Failed to set GCPs.");
++
++ return CE_Failure;
++ }
++ }
++#endif
++
++ OGRFree(psTargetSRS);
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* SetMetaDataList() */
++/************************************************************************/
++
++/**
++ * \brief Set the metadata list for this coverage.
++ *
++ * The method will set the metadata list for the coverage based on its
++ * corresponding GDALDataset object.
++ *
++ * @param hSrc the GDALDataset object corresponding to coverage.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::SetMetaDataList(GDALDataset* hSrcDS)
++{
++ mv_MetaDataList.push_back("Product_Description=The data was created by GMU WCS from NOAA GOES satellite data.");
++ mv_MetaDataList.push_back("unit=GVAR");
++ mv_MetaDataList.push_back("FillValue=0");
++ ms_FieldQuantityDef = "GVAR";
++ ms_AllowRanges = "0 65535";
++ ms_CoveragePlatform = "GOES-11";
++ ms_CoverageInstrument = "GOES-11";
++ ms_CoverageSensor = "Imager";
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetGeoMinMax() */
++/************************************************************************/
++
++/**
++ * \brief Get the min/max coordinates of laitutude and longitude.
++ *
++ * The method will fetch the min/max coordinates of laitutude and longitude.
++ *
++ * @param geoMinMax an existing four double buffer into which the
++ * native geographical bounding box values will be placed.
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::GetGeoMinMax(double geoMinMax[])
++{
++ if (!mb_GeoTransformSet)
++ return CE_Failure;
++
++ geoMinMax[0] = mdSrcGeoMinX;
++ geoMinMax[2] = mdSrcGeoMinY;
++ geoMinMax[1] = mdSrcGeoMaxX;
++ geoMinMax[3] = mdSrcGeoMaxY;
++
++ return CE_None;
++}
++
++/************************************************************************/
++/* GetGeoMinMax() */
++/************************************************************************/
++
++/**
++ * \brief Convert the GOES dataset from satellite CRS project to grid CRS.
++ *
++ * The method will convert the GOES dataset from satellite CRS project to
++ * grid CRS based on GDAL API GDALReprojectImage;
++ *
++ * @return CE_None on success or CE_Failure on failure.
++ */
++
++CPLErr NC_GOES_Dataset::RectifyGOESDataSet()
++{
++ char *pszDstWKT;
++ mo_NativeCRS.exportToWkt(&pszDstWKT);
++
++ GDALDriverH poDriver = GDALGetDriverByName("MEM");
++ GDALDataset* rectDataSet = (GDALDataset*) GDALCreate(poDriver, "", mi_RectifiedImageXSize,
++ mi_RectifiedImageYSize, maptr_DS->GetRasterCount(),
++ maptr_DS->GetRasterBand(1)->GetRasterDataType(), NULL);
++ if (NULL == rectDataSet)
++ {
++ GDALClose(poDriver);
++ OGRFree(pszDstWKT);
++ SetWCS_ErrorLocator("AbstractDataset::rectifyDataSet()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode,
++ "Failed to create \"MEM\" dataSet.");
++
++ return CE_Failure;
++ }
++
++ rectDataSet->SetProjection(pszDstWKT);
++ rectDataSet->SetGeoTransform(md_Geotransform);
++
++ if (CE_None != GDALReprojectImage(maptr_DS.get(), NULL, rectDataSet,
++ pszDstWKT, GRA_NearestNeighbour, 0, 0.125, NULL, NULL, NULL))
++ {
++ GDALClose(rectDataSet);
++ GDALClose(poDriver);
++ OGRFree(pszDstWKT);
++ SetWCS_ErrorLocator("AbstractDataset::RectifyDataSet()");
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode,
++ "Failed to re-project GOES data from satellite GCP CRS to geographical CRS.");
++
++ return CE_Failure;
++ }
++
++ OGRFree(pszDstWKT);
++ GDALClose(maptr_DS.release());
++
++ maptr_DS.reset(rectDataSet);
++
++ return CE_None;
++}
++
+Binarne pliki bes-3.12.0/functions.orig/swath2grid/.svn/wc.db i bes-3.12.0/functions/swath2grid/.svn/wc.db ró¿ni± siê
+diff -Nur bes-3.12.0/functions.orig/swath2grid/three_array_1.das bes-3.12.0/functions/swath2grid/three_array_1.das
+--- bes-3.12.0/functions.orig/swath2grid/three_array_1.das 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/three_array_1.das 2014-03-03 15:47:38.046899595 +0100
+@@ -0,0 +1,10 @@
++# three_array_1.das
++#
++# Created on: Dec 12, 2012
++# Author: jimg
++
++Attributes {
++ t{}
++ lon{}
++ lat{}
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/three_array_1.dds bes-3.12.0/functions/swath2grid/three_array_1.dds
+--- bes-3.12.0/functions.orig/swath2grid/three_array_1.dds 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/three_array_1.dds 2014-03-03 15:47:38.050232928 +0100
+@@ -0,0 +1,10 @@
++# three_array_1.dds
++#
++# Created on: Dec 12, 2012
++# Author: jimg
++
++Dataset {
++ Float64 t[10][10];
++ Float64 lon[10][10];
++ Float64 lat[10][10];
++} three_array_1;
+diff -Nur bes-3.12.0/functions.orig/swath2grid/wcs_error.cpp bes-3.12.0/functions/swath2grid/wcs_error.cpp
+--- bes-3.12.0/functions.orig/swath2grid/wcs_error.cpp 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/wcs_error.cpp 2014-03-03 15:47:38.046899595 +0100
+@@ -0,0 +1,116 @@
++/******************************************************************************
++ * $Id: wcs_error.cpp 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: WCS exception and error handler implementation, used to set
++ * the exception code and locator of WCS
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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 "wcs_error.h"
++
++static string WCS_ERROR_STRING="";
++static string ERROR_LOCATOR="";
++static string ExcptCodeText[] =
++{
++ "OperationNotSupported",
++ "MissingParameterValue",
++ "InvalidParameterValue",
++ "VersionNegotiationFailed",
++ "InvalidUpdateSequence",
++ "OptionNotSupported",
++ "NoApplicableCode",
++ "NoSuchCoverage",
++ "InvalidAxisLabel",
++ "InvalidSubsetting"
++};
++
++static int WCS_IsSoapMessage_Transform = 0;
++
++string CPL_STDCALL GetWCS_ErrorMsg()
++{
++ return WCS_ERROR_STRING;
++}
++
++void CPL_STDCALL SetWCS_ErrorLocator(const char* loc)
++{
++ ERROR_LOCATOR = loc;
++}
++
++void CPL_STDCALL WCS_ErrorHandler(CPLErr eErrClass,int err_no,const char *pszErrorMsg )
++{
++ WCS_ERROR_STRING.clear();
++ string ExcCode;
++
++ if(err_no >= 300 && err_no <= 309)
++ ExcCode = ExcptCodeText[err_no - 300];
++ else
++ ExcCode = ExcptCodeText[6];
++
++ if(WCS_IsSoapMessage_Transform)
++ {
++ WCS_ERROR_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
++ WCS_ERROR_STRING += "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n";
++ WCS_ERROR_STRING += "<soap:Body>\n";
++ WCS_ERROR_STRING += "<ExceptionReport xmlns=\"http://www.opengis.net/ows\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
++ WCS_ERROR_STRING += "xsi:schemaLocation=\"http://www.opengis.net/ows/owsCommon.xsd\" version=\"0.3.20\" language=\"en\">\n";
++ WCS_ERROR_STRING += " <Exception exceptionCode=\"";
++ WCS_ERROR_STRING += ExcCode;
++ WCS_ERROR_STRING += "\" locator=\"";
++ WCS_ERROR_STRING += ERROR_LOCATOR;
++ WCS_ERROR_STRING += "\">\n";
++ WCS_ERROR_STRING += " <ExceptionText>" + string(pszErrorMsg) + "</ExceptionText>\n";
++ WCS_ERROR_STRING += " </Exception>\n";
++ WCS_ERROR_STRING += "</ExceptionReport>\n";
++ WCS_ERROR_STRING += "/soap:Body>\n";
++ WCS_ERROR_STRING += "/<soap:Envelope>\n";
++ }
++ else
++ {
++ WCS_ERROR_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
++ WCS_ERROR_STRING += "<ExceptionReport xmlns=\"http://www.opengis.net/ows\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
++ WCS_ERROR_STRING += "xsi:schemaLocation=\"http://www.opengis.net/ows/owsCommon.xsd\" version=\"0.3.20\" language=\"en\">\n";
++ WCS_ERROR_STRING += " <Exception exceptionCode=\"";
++ WCS_ERROR_STRING += ExcCode;
++ WCS_ERROR_STRING += "\" locator=\"";
++ WCS_ERROR_STRING += ERROR_LOCATOR;
++ WCS_ERROR_STRING += "\">\n";
++ WCS_ERROR_STRING += " <ExceptionText>" + string(pszErrorMsg) + "</ExceptionText>\n";
++ WCS_ERROR_STRING += " </Exception>\n";
++ WCS_ERROR_STRING += "</ExceptionReport>\n";
++ }
++
++ return;
++}
++
++void WCST_SetSoapMsgTrns(int isSoap)
++{
++ WCS_IsSoapMessage_Transform = isSoap;
++}
++
++int WCST_GetSoapMsgTrns()
++{
++ return WCS_IsSoapMessage_Transform;
++}
+diff -Nur bes-3.12.0/functions.orig/swath2grid/wcs_error.h bes-3.12.0/functions/swath2grid/wcs_error.h
+--- bes-3.12.0/functions.orig/swath2grid/wcs_error.h 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/wcs_error.h 2014-03-03 15:47:38.046899595 +0100
+@@ -0,0 +1,81 @@
++/******************************************************************************
++ * $Id: wcs_error.h 2011-07-19 16:24:00Z $
++ *
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)
++ * for Earth Observation: Open Source Reference Implementation
++ * Purpose: WCS exception and error handler definition
++ * Author: Yuanzheng Shao, yshao3@gmu.edu
++ *
++ ******************************************************************************
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>
++ *
++ * 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.
++ ****************************************************************************/
++
++/************************************************************************
++ WCS Exception Code
++
++ See OGC Web Services Common Standard [OGC 06-121r9] for details
++ Table 27 — Standard exception codes and meanings
++ OperationNotSupported
++ MissingParameterValue
++ InvalidParameterValue
++ VersionNegotiationFailed
++ InvalidUpdateSequence
++ OptionNotSupported
++ NoApplicableCode
++
++ See OGC® WCS 2.0 Interface Standard - Core [09-110r3] for details
++ Table 18 - Exception codes for GetCoverage operation
++ NoSuchCoverage
++ InvalidAxisLabel
++ InvalidSubsetting
++
++*************************************************************************/
++
++#ifndef WCS_ERROR_H_
++#define WCS_ERROR_H_
++
++#include <cpl_error.h>
++#include <string>
++
++using namespace std;
++
++#define OGC_WCS_OperationNotSupported 300
++#define OGC_WCS_MissingParameterValue 301
++#define OGC_WCS_InvalidParameterValue 302
++#define OGC_WCS_VersionNegotiationFailed 303
++#define OGC_WCS_InvalidUpdateSequence 304
++#define OGC_WCS_OptionNotSupported 305
++#define OGC_WCS_NoApplicableCode 306
++
++#define OGC_WCS_NoSuchCoverage 307
++#define OGC_WCS_InvalidAxisLabel 308
++#define OGC_WCS_InvalidSubsetting 309
++
++void CPL_DLL CPL_STDCALL WCS_Error(CPLErr, int, const char*, ...);
++void CPL_DLL CPL_STDCALL SetWCS_ErrorLocator(const char* loc);
++void CPL_DLL CPL_STDCALL WCS_ErrorHandler(CPLErr, int, const char*);
++string CPL_DLL CPL_STDCALL GetWCS_ErrorMsg();
++
++int WCST_GetSoapMsgTrns();
++void WCST_SetSoapMsgTrns(int);
++
++#define WCS_Error CPLError
++#endif /* WCS_ERROR_H_ */
+diff -Nur bes-3.12.0/functions.orig/swath2grid/wcsUtil.cpp bes-3.12.0/functions/swath2grid/wcsUtil.cpp
+--- bes-3.12.0/functions.orig/swath2grid/wcsUtil.cpp 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/wcsUtil.cpp 2014-03-03 15:47:38.056899595 +0100
+@@ -0,0 +1,1278 @@
++/******************************************************************************\r
++ * $Id: wcsUtil.cpp 2011-07-19 16:24:00Z $\r
++ *\r
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)\r
++ * for Earth Observation: Open Source Reference Implementation\r
++ * Purpose: WCS Utility Function implementation\r
++ * Author: Yuanzheng Shao, yshao3@gmu.edu\r
++ *\r
++ ******************************************************************************\r
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>\r
++ *\r
++ * Permission is hereby granted, free of charge, to any person obtaining a\r
++ * copy of this software and associated documentation files (the "Software"),\r
++ * to deal in the Software without restriction, including without limitation\r
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
++ * and/or sell copies of the Software, and to permit persons to whom the\r
++ * Software is furnished to do so, subject to the following conditions:\r
++ *\r
++ * The above copyright notice and this permission notice shall be included\r
++ * in all copies or substantial portions of the Software.\r
++ *\r
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
++ * DEALINGS IN THE SOFTWARE.\r
++ ****************************************************************************/\r
++\r
++#include <unistd.h>\r
++#include <dirent.h>\r
++#include <sys/stat.h>\r
++#include <stdexcept>\r
++#include <uuid/uuid.h>\r
++#include "wcsUtil.h"\r
++//#include "mfhdf.h"\r
++\r
++/************************************************************************/\r
++/* GetUUID() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Used to get UUID string.\r
++ *\r
++ * This method will return a UUID, such as: cd32eb56-412c-11e0-9cce-67750f871b94\r
++ *\r
++ * @return A generated UUID string.\r
++ */\r
++\r
++string CPL_STDCALL GetUUID()\r
++{\r
++ uuid_t uuid;\r
++ uuid_generate(uuid);\r
++ char uuidstr[36];\r
++ uuid_unparse(uuid, uuidstr);\r
++ return uuidstr;\r
++}\r
++\r
++/************************************************************************/\r
++/* SPrintArray() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Print a string based on coverage realted parameters.\r
++ *\r
++ * This method will return a UUID, such as: cd32eb56-412c-11e0-9cce-67750f871b94\r
++ *\r
++ * @return A generated UUID string.\r
++ */\r
++\r
++string CPL_STDCALL SPrintArray(GDALDataType eDataType, const void *paDataArray, int nValues, const char *pszDelimiter)\r
++{\r
++ char *pszString, *pszField;\r
++ int i, iFieldSize, iStringSize;\r
++\r
++ iFieldSize = 32 + strlen(pszDelimiter);\r
++ pszField = (char *) CPLMalloc(iFieldSize + 1);\r
++ iStringSize = nValues * iFieldSize + 1;\r
++ pszString = (char *) CPLMalloc(iStringSize);\r
++ memset(pszString, 0, iStringSize);\r
++ for (i = 0; i < nValues; i++)\r
++ {\r
++ switch (eDataType)\r
++ {\r
++ case GDT_Byte:\r
++ sprintf(pszField, "%d%s", ((GByte *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_UInt16:\r
++ sprintf(pszField, "%u%s", ((GUInt16 *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_Int16:\r
++ default:\r
++ sprintf(pszField, "%d%s", ((GInt16 *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_UInt32:\r
++ sprintf(pszField, "%u%s", ((GUInt32 *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_Int32:\r
++ sprintf(pszField, "%d%s", ((GInt32 *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_Float32:\r
++ sprintf(pszField, "%.7g%s", ((float *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ case GDT_Float64:\r
++ sprintf(pszField, "%.15g%s", ((double *) paDataArray)[i], (i < nValues - 1) ? pszDelimiter : "");\r
++ break;\r
++ }\r
++ strcat(pszString, pszField);\r
++ }\r
++\r
++ CPLFree(pszField);\r
++\r
++ return string(pszString);\r
++}\r
++\r
++/************************************************************************/\r
++/* StrTrimHead() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Trim s string's head.\r
++ *\r
++ * This method will trim a string's head, remove the sapce and line break\r
++ * in the head of a string.\r
++ *\r
++ * @param str The string to be processed.\r
++ *\r
++ * @return A head-trimmed string.\r
++ */\r
++\r
++string CPL_STDCALL StrTrimHead(const string &str)\r
++{\r
++ string::size_type p = 0;\r
++ /* leading space? */\r
++ while ((p < str.size()) && (str[p] == ' ' || str[p] == '\t' || str[p] == 13 || str[p] == 10))\r
++ p++;\r
++ if (p >= str.size())\r
++ return "";\r
++ else\r
++ return str.substr(p);\r
++}\r
++\r
++/************************************************************************/\r
++/* StrTrimTail() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Trim s string's tail.\r
++ *\r
++ * This method will trim a string's tail, remove the sapce and line break\r
++ * in the tail of a string.\r
++ *\r
++ * @param str The string to be processed.\r
++ *\r
++ * @return A tail-trimmed string.\r
++ */\r
++\r
++string CPL_STDCALL StrTrimTail(const string &str)\r
++{\r
++ string::size_type p = str.size() - 1;\r
++ while (p >= 0 && (str[p] == ' ' || str[p] == '\t' || str[p] == 13 || str[p] == 10))\r
++ p--;\r
++ if (p < 0)\r
++ return "";\r
++ else\r
++ return str.substr(0, p + 1);\r
++}\r
++\r
++/************************************************************************/\r
++/* StrTrim() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Trim s string's head and tail.\r
++ *\r
++ * This method will trim a string's head and tail, remove the sapce and\r
++ * line break in both the head and end of a string.\r
++ *\r
++ * @param str The string to be processed.\r
++ *\r
++ * @return A trimmed string.\r
++ */\r
++\r
++string CPL_STDCALL StrTrim(const string &str)\r
++{\r
++ string s = StrTrimTail(str);\r
++ return StrTrimHead(s);\r
++}\r
++\r
++/************************************************************************/\r
++/* StrTrims() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Trim s string's head and tail based on delimiter string.\r
++ *\r
++ * This method will trim a string's head and tail based on delimiter\r
++ * string, and return the trimmed string.\r
++ *\r
++ * @param srcStr The string to be processed.\r
++ *\r
++ * @param tok The delimiter string used to trim the string.\r
++ *\r
++ * @return A trimmed string.\r
++ */\r
++\r
++string CPL_STDCALL StrTrims(const string& srcStr, const char* tok)\r
++{\r
++ if (srcStr.empty())\r
++ return srcStr;\r
++\r
++ string::size_type beginIdx, endIdx;\r
++ beginIdx = srcStr.find_first_not_of(tok);\r
++ endIdx = srcStr.find_last_not_of(tok);\r
++\r
++ if (beginIdx != string::npos && endIdx != string::npos)\r
++ return srcStr.substr(beginIdx, endIdx - beginIdx + 1);\r
++ else\r
++ return "";\r
++}\r
++\r
++/************************************************************************/\r
++/* Strslip() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Slice a string and split it into an array.\r
++ *\r
++ * This method will slice a string based on left and right delimiter, and then\r
++ * split the slipped part into an array.\r
++ *\r
++ * @param str The string to be processed, such as "longitude[15.5,23.5]"\r
++ *\r
++ * @param arrStr The two dimension array to place the sliced results.\r
++ *\r
++ * @param leftdlm The left delimiter used to slip the string, such as '['.\r
++ *\r
++ * @param rightdlm The right delimiter used to slip the string, such as ']'.\r
++ */\r
++\r
++void CPL_STDCALL Strslip(const char* str, const char* arrStr[], const char leftdlm, const char rightdlm)\r
++{\r
++ char* pdest1 = 0;\r
++ char* pdest2 = 0;\r
++\r
++ arrStr[0] = str;\r
++ pdest1 = (char*)strchr(str, leftdlm);\r
++ if (!pdest1)\r
++ {\r
++ arrStr[1] = str;\r
++ return;\r
++ }\r
++\r
++ pdest2 = (char*)strrchr(str, rightdlm);\r
++ if (!pdest2)\r
++ return;\r
++\r
++ arrStr[1] = pdest1 + 1;\r
++ *pdest1 = '\0';\r
++ *pdest2 = '\0';\r
++\r
++ return;\r
++}\r
++\r
++/************************************************************************/\r
++/* CsvburstComplexCpp() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Slice a string based on single or multiple delimiter(s), and\r
++ * then store the results to array.\r
++ *\r
++ * This method will slice a string based on specified delimiter(s), and then\r
++ * place the sliced string parts to a array.\r
++ *\r
++ * @param line The string to be processed.\r
++ *\r
++ * @param strSet The array to place the sliced results.\r
++ *\r
++ * @param tok The delimiter string used to slice the string.\r
++ *\r
++ * @return The size of the sliced parts.\r
++ */\r
++\r
++int CPL_STDCALL CsvburstComplexCpp(const string& line, vector<string> &strSet, const char *tok)\r
++{\r
++ if (line.empty() || line == "")\r
++ return 0;\r
++\r
++ strSet.clear();\r
++ string::size_type firstPos, idx;\r
++\r
++ firstPos = idx = 0;\r
++ idx = line.find_first_of(tok, firstPos);\r
++\r
++ while (idx != string::npos)\r
++ {\r
++ string tmpStr = StrTrim(line.substr(firstPos, (idx - firstPos)));\r
++ if (!tmpStr.empty() && tmpStr != "")\r
++ strSet.push_back(tmpStr);\r
++\r
++ firstPos = idx + 1;\r
++ if (firstPos == string::npos)\r
++ break;\r
++ idx = line.find_first_of(tok, firstPos);\r
++ }\r
++\r
++ if (firstPos != string::npos)\r
++ {\r
++ strSet.push_back(StrTrim(line.substr(firstPos)));\r
++ }\r
++\r
++ return strSet.size();\r
++}\r
++\r
++/************************************************************************/\r
++/* CsvburstCpp() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Slice a string based on single delimiter, and then store the results to array.\r
++ *\r
++ * This method will slice a string based on specified single delimiter, and then\r
++ * place the sliced string parts to a array.\r
++ *\r
++ * @param line The string to be processed, such as "12,34,56".\r
++ *\r
++ * @param strSet The array to place the sliced results.\r
++ *\r
++ * @param tok The delimiter character used to slice the string, such as ','.\r
++ *\r
++ * @return The size of the sliced parts.\r
++ */\r
++\r
++int CPL_STDCALL CsvburstCpp(const string& line, vector<string> &strSet, const char tok)\r
++{\r
++ if (line.empty() || line == "")\r
++ return 0;\r
++\r
++ strSet.clear();\r
++ string::size_type firstPos, idx;\r
++ string::size_type panfuPos;\r
++ panfuPos = 0;\r
++ firstPos = idx = 0;\r
++\r
++ idx = line.find_first_of(tok, firstPos);\r
++\r
++ while (idx != string::npos)\r
++ {\r
++ if(line[idx-2] == '\"' || line[idx-2] == '\'')//Add By Yuanzheng Shao\r
++ {\r
++ firstPos = idx + 1;\r
++ if (firstPos == string::npos)\r
++ break;\r
++ panfuPos = idx-2;\r
++ idx = line.find_first_of(tok, firstPos);\r
++\r
++ string tmpStr = StrTrim(line.substr(panfuPos, (idx - panfuPos)));\r
++ if (!tmpStr.empty() && tmpStr != "")\r
++ strSet.push_back(tmpStr);\r
++\r
++ firstPos = idx + 1;\r
++ idx = line.find_first_of(tok, firstPos);\r
++ }\r
++ else\r
++ {\r
++ string tmpStr = StrTrim(line.substr(firstPos, (idx - firstPos)));\r
++ if (!tmpStr.empty() && tmpStr != "")\r
++ strSet.push_back(tmpStr);\r
++\r
++ firstPos = idx + 1;\r
++ if (firstPos == string::npos)\r
++ break;\r
++ idx = line.find_first_of(tok, firstPos);\r
++ }\r
++ }\r
++\r
++ if (firstPos != string::npos)\r
++ {\r
++ strSet.push_back(StrTrim(line.substr(firstPos)));\r
++ }\r
++\r
++ return strSet.size();\r
++}\r
++\r
++/************************************************************************/\r
++/* Find_Compare_SubStr() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Find the substring in a string.\r
++ *\r
++ * This method will find a substring in a string.\r
++ *\r
++ * @param line The string to be processed.\r
++ *\r
++ * @param sub The substring to be compared.\r
++ *\r
++ * @return TRUE if find the substring, otherwise FALSE.\r
++ */\r
++\r
++int CPL_STDCALL Find_Compare_SubStr(string line, string sub)\r
++{\r
++ if (line.empty() || line == "" || sub.empty() || sub == "")\r
++ return 0;\r
++\r
++ for (unsigned int i = 0; i < line.size(); ++i)\r
++ {\r
++ line[i] = (char) toupper((char) line[i]);\r
++ }\r
++ for (unsigned int j = 0; j < sub.size(); ++j)\r
++ {\r
++ sub[j] = (char) toupper((char) sub[j]);\r
++ }\r
++\r
++ if (string::npos == line.find(sub))\r
++ return 0;\r
++ else\r
++ return 1;\r
++}\r
++\r
++/************************************************************************/\r
++/* GetFileNameList() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch the file name list under the specified directory.\r
++ *\r
++ * This method will fetch the file name list under the specified directory,\r
++ * and store the results to a array.\r
++ *\r
++ * @param dir The directory name.\r
++ *\r
++ * @param strList The array used to place the results.\r
++ *\r
++ * @return CE_None on success or CE_Failure on failure.\r
++ */\r
++\r
++CPLErr CPL_STDCALL GetFileNameList(char* dir, vector<string> &strList)\r
++{\r
++ char pwdBuf[256];\r
++ char *pwd=getcwd (pwdBuf, 256);\r
++ DIR *dp;\r
++ struct dirent *entry;\r
++ struct stat statbuf;\r
++ if ((dp = opendir(dir)) == NULL)\r
++ {\r
++ SetWCS_ErrorLocator("getFileNameList()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Open Director %s", dir);\r
++ return CE_Failure;\r
++ }\r
++\r
++ if (dir[strlen(dir) - 1] == '/')\r
++ dir[strlen(dir) - 1] = '\0';\r
++\r
++ chdir(dir);\r
++\r
++ while ((entry = readdir(dp)) != NULL)\r
++ {\r
++ lstat(entry->d_name, &statbuf);\r
++ if (S_ISDIR(statbuf.st_mode))\r
++ {\r
++ /* Found a directory, but ignore . and .. */\r
++ if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)\r
++ continue;\r
++ /* Recurse at a new indent level */\r
++ string subdir = dir;\r
++ subdir = subdir + "/" + entry->d_name;\r
++ GetFileNameList((char*)subdir.c_str(), strList);\r
++ }\r
++ else if (S_ISREG(statbuf.st_mode))\r
++ {\r
++ string fname = getcwd(NULL, 0);\r
++ fname = fname + "/" + entry->d_name;\r
++ strList.push_back(fname);\r
++ }\r
++ }\r
++ chdir(pwd);\r
++ closedir(dp);\r
++\r
++ return CE_None;\r
++}\r
++\r
++/************************************************************************/\r
++/* Julian2Date() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Convert the Julian days to date string.\r
++ *\r
++ * This method will convert the days of year to its date string (YYYY-MM-DD);\r
++ *\r
++ * @param year The year of days.\r
++ *\r
++ * @param days The Julian days.\r
++ *\r
++ * @return The date string.\r
++ */\r
++\r
++string Julian2Date(int year, int days)\r
++{\r
++ bool leapyear = ((year%4==0 && year%100!=0) || year%400==0) ? true : false;\r
++ int month, day;\r
++\r
++ int leapArr[24] = {1, 31, 32, 60, 61, 91, 92, 121, 122, 152, 153, 182, 183, 213, 214, 244,\r
++ 245, 274, 275, 305, 306, 335, 336, 366};\r
++ int unLeArr[24] = {1, 31, 32, 59, 60, 90, 91, 120, 121, 151, 152, 181, 182, 212, 213, 243,\r
++ 244, 273, 274, 304, 305, 334, 335, 365};\r
++\r
++ if(leapyear) {\r
++ for (int i = 0; i < 24; i += 2) {\r
++ if(days >= leapArr[i] && days <= leapArr[i+1]) {\r
++ month = int(i/2) + 1;\r
++ day = days - leapArr[i] + 1;\r
++ break;\r
++ }\r
++ }\r
++ } else {\r
++ for (int i=0; i < 24; i += 2) {\r
++ if(days >= unLeArr[i] && days <= unLeArr[i+1]) {\r
++ month = int(i/2) + 1;\r
++ day = days - unLeArr[i] + 1;\r
++ break;\r
++ }\r
++ }\r
++ }\r
++\r
++ string monthStr = month<10 ? "0" + convertToString(month) : convertToString(month);\r
++ string dayStr = day<10 ? "0" + convertToString(day) : convertToString(day);\r
++\r
++ return convertToString(year) + "-" + monthStr + "-" + dayStr;\r
++}\r
++\r
++/************************************************************************/\r
++/* GetTRMMBandList() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch the day's list for TRMM data based on the range of date/time.\r
++ *\r
++ * This method will find day's list for TRMM data based on specified date/time\r
++ * range, and store the results to a array.\r
++ *\r
++ * @param start The start date/time.\r
++ *\r
++ * @param end The end date/time.\r
++ *\r
++ * @param bandList The array used to place the results.\r
++ *\r
++ * @return CE_None on success or CE_Failure on failure.\r
++ */\r
++\r
++CPLErr CPL_STDCALL GetTRMMBandList(string start, string end, std::vector<int> &bandList)\r
++{\r
++ //calculate 2000-06-01's days, start's days, end's days\r
++ if(EQUAL(start.c_str(), "") && EQUAL(end.c_str(), ""))\r
++ return CE_None;\r
++\r
++ string june1str = start.substr(0, 4) + "-06-01";\r
++ long int june1sec = ConvertDateTimeToSeconds(june1str);\r
++ long int startsec = 0, endsec = 0;\r
++\r
++ if(!EQUAL(start.c_str(), ""))\r
++ startsec = ConvertDateTimeToSeconds(start);\r
++ if(!EQUAL(end.c_str(), ""))\r
++ endsec = ConvertDateTimeToSeconds(end);\r
++\r
++ int sdays = (int)(startsec - june1sec)/(24*3600) + 1;\r
++ int edays = (int)(endsec - june1sec)/(24*3600) + 1;\r
++\r
++ sdays = (sdays < 0) ? 0 : sdays;\r
++ edays = (edays < 0) ? sdays : edays;\r
++\r
++ for(int i = sdays; i <= edays; i++)\r
++ bandList.push_back(i);\r
++\r
++ return CE_None;\r
++}\r
++\r
++\r
++/************************************************************************/\r
++/* GetTimeString() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch the current system time to a string.\r
++ *\r
++ * This method will get the current system time, and convert it to a string.\r
++ * The return date/time has two formats:\r
++ * 1: YYYYMMDDHHMMSS\r
++ * 2: YYYY-MM-DDTHH:MM:SSZ\r
++ *\r
++ * @param code The return string's format.\r
++ *\r
++ * @return The string corresponding to current system time.\r
++ */\r
++\r
++string GetTimeString(int code)\r
++{\r
++ struct tm* ptime;\r
++ time_t now;\r
++ time(&now);\r
++ ptime = localtime(&now);\r
++ int year = ptime->tm_year + 1900;\r
++ int month = ptime->tm_mon + 1;\r
++ int day = ptime->tm_mday;\r
++ int hour = ptime->tm_hour;\r
++ int minute = ptime->tm_min;\r
++ int second = ptime->tm_sec;\r
++ string ye, mo, da, ho, mi, se;\r
++ ye = convertToString(year);\r
++ mo = (month < 10) ? "0" + convertToString(month) : convertToString(month);\r
++ da = (day < 10) ? "0" + convertToString(day) : convertToString(day);\r
++ ho = (hour < 10) ? "0" + convertToString(hour) : convertToString(hour);\r
++ mi = (minute < 10) ? "0" + convertToString(minute) : convertToString(minute);\r
++ se = (second < 10) ? "0" + convertToString(second) : convertToString(second);\r
++\r
++ string timestring;\r
++ if(code == 1)\r
++ {\r
++ string part1 = ye + mo + da;\r
++ string part2 = ho + mi + se;\r
++ timestring = part1.append(part2);\r
++ }\r
++ else if(code == 2)\r
++ {\r
++ string part1 = ye + "-" + mo + "-" + da + "T";\r
++ string part2 = ho + ":" + mi + ":" + se + "Z";\r
++ timestring = part1.append(part2);\r
++ }\r
++\r
++ return timestring;\r
++}\r
++\r
++/************************************************************************/\r
++/* MakeTempFile() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Generate a temporary file path.\r
++ *\r
++ * This method will generate a path for temporary file or output file,\r
++ * which is based on coverage identifier.\r
++ *\r
++ * @param dir The directory of the temporary file.\r
++ *\r
++ * @param covID The coverage identifier.\r
++ *\r
++ * @param suffix The suffix of the file format.\r
++ *\r
++ * @return The full path of the temporary file.\r
++ */\r
++\r
++string MakeTempFile(string dir, string covID, string suffix)\r
++{\r
++ string sOutFileName;\r
++\r
++ if (!dir.empty() && dir != "")\r
++ {\r
++ if (dir[dir.length() - 1] != '/')\r
++ {\r
++ dir += "/";\r
++ }\r
++ }\r
++ if (!suffix.empty() && suffix != "")\r
++ {\r
++ if (suffix[0] != '.')\r
++ suffix = "." + suffix;\r
++ }\r
++\r
++ if(covID == "")\r
++ {\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }\r
++ else if (EQUALN(covID.c_str(),"HDF4_EOS:EOS_SWATH:",19) ||\r
++ EQUALN(covID.c_str(),"HDF4_EOS:EOS_GRID:",18) ||\r
++ EQUALN(covID.c_str(),"HDF5:",5))\r
++ {\r
++ vector<string> strSet;\r
++ int n = CsvburstCpp(covID, strSet, ':');\r
++ if(n == 5){//Terra&Aqua\r
++ string srcFilePath = StrTrims(strSet[2], "\'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ string datasetname = StrTrims(strSet[4], "\'\"");\r
++ datasetname = StrReplace(datasetname, " ", "_");\r
++ sOutFileName = dir + srcFileName + "." + datasetname + "." + GetTimeString(1) + suffix;\r
++ }else if(n == 3) {//Aura\r
++ string srcFilePath = StrTrims(strSet[1], "\'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ string datasetname = StrTrims(strSet[2], "\'\"");\r
++ datasetname = StrReplace(datasetname, "//", "");\r
++ datasetname = StrReplace(datasetname, "/", "_");\r
++ datasetname = StrReplace(datasetname, " ", "");\r
++ sOutFileName = dir + srcFileName + "." + datasetname + "." + GetTimeString(1) + suffix;\r
++ }else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }else if(EQUALN( covID.c_str(), "GOES:NetCDF:",12))\r
++ {\r
++ vector<string> strSet;\r
++ int n = CsvburstCpp(covID, strSet, ':');\r
++ if(n == 4){\r
++ string srcFilePath = StrTrims(strSet[2], " \'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ sOutFileName = dir + srcFileName + "." + GetTimeString(1) + suffix;\r
++ }else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }\r
++ else if(EQUALN(covID.c_str(),"GEOTIFF:",8))\r
++ {\r
++ vector<string> strSet;\r
++ int n = CsvburstCpp(covID, strSet, ':');\r
++ if(n == 3){\r
++ string srcFilePath = StrTrims(strSet[1], " \'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ sOutFileName = dir + srcFileName + "." + GetTimeString(1) + suffix;\r
++ }else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }\r
++ else if(EQUALN(covID.c_str(),"TRMM:",5))\r
++ {\r
++ vector<string> strSet;\r
++ int n = CsvburstCpp(covID, strSet, ':');\r
++ if(n == 3){\r
++ string srcFilePath = StrTrims(strSet[1], " \'\"");\r
++ string srcFileName = string(CPLGetBasename(srcFilePath.c_str()));\r
++ sOutFileName = dir + srcFileName + "." + GetTimeString(1) + suffix;\r
++ }else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++ }\r
++ else\r
++ sOutFileName = dir + GetUUID() + suffix;\r
++\r
++ return sOutFileName;\r
++}\r
++\r
++/************************************************************************/\r
++/* StringList() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Constructor for StringList.\r
++ */\r
++\r
++StringList::StringList(const string& sstrings, const char delimiter)\r
++{\r
++ string str = sstrings + delimiter;\r
++ string::size_type np, op = 0;\r
++ while ((op < str.size())\r
++ && ((np = str.find(delimiter, op)) != string::npos))\r
++ {\r
++ add(str.substr(op, np - op));\r
++ op = ++np;\r
++ }\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list constructor\r
++// -----------------------------------------------------------------------\r
++StringList::StringList(const string& sstrings, const string& delimiters)\r
++{\r
++ string str = sstrings + delimiters;\r
++ string::size_type np, op = 0;\r
++ while ((op < str.size()) && ((np = str.find(delimiters, op))\r
++ != string::npos))\r
++ {\r
++ add(str.substr(op, np - op));\r
++ op = np + delimiters.length();\r
++ }\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list -- append\r
++// -----------------------------------------------------------------------\r
++void StringList::append(StringList & s)\r
++{\r
++ for (int i = 0; i < s.size(); i++)\r
++ add(s[i]);\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list -- append with delimiter\r
++// -----------------------------------------------------------------------\r
++void StringList::append(const string sstrings, const char delimiter)\r
++{\r
++ StringList n(sstrings, delimiter);\r
++ append(n);\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list -- append with delimiters\r
++// -----------------------------------------------------------------------\r
++void StringList::append(const string sstrings, const string& delimiters)\r
++{\r
++ StringList n(sstrings, delimiters);\r
++ append(n);\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// string list -- return the index for query string\r
++// -----------------------------------------------------------------------\r
++int StringList::indexof(string qstr)\r
++{\r
++ for (int i = 0; i < size(); i++)\r
++ {\r
++ if (strings[i] == qstr)\r
++ return i;\r
++ }\r
++ return -1;\r
++}\r
++\r
++/************************************************************************/\r
++/* KVP() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Constructor for KVP.\r
++ *\r
++ * @param namevaluepair The key-value pair.\r
++ */\r
++\r
++KVP::KVP(string namevaluepair)\r
++{\r
++ StringList ss(namevaluepair, '=');\r
++ if (ss.size() == 2)\r
++ {\r
++ name = StrTrim(ss[0]);\r
++ value = StrTrim(ss[1]);\r
++ }\r
++ else\r
++ {\r
++ name = namevaluepair;\r
++ value = "";\r
++ }\r
++}\r
++\r
++/************************************************************************/\r
++/* CFGReader() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Constructor for CFGReader.\r
++ *\r
++ * This method is used to load the configuration file for WCS. Each configuration\r
++ * item looks like a key-value pair, CFGReader() will read the file to memory and\r
++ * store the parameters to a KVP array.\r
++ *\r
++ * @param configfilename The full path of the configuration file.\r
++ */\r
++\r
++CFGReader::CFGReader(const string &configfilename)\r
++{\r
++ ifstream cfgfile(configfilename.c_str());\r
++ if (!cfgfile)\r
++ {\r
++ SetWCS_ErrorLocator("CFGReader");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to open configure file.");\r
++ throw runtime_error("");\r
++ }\r
++\r
++ char line[MAX_LINE_LEN];\r
++ while (!cfgfile.eof())\r
++ {\r
++ cfgfile.getline(line, MAX_LINE_LEN - 1, '\n');\r
++ if (!cfgfile.fail())\r
++ {\r
++ if (line[0] != '#')\r
++ {\r
++ KVP kvp(line);\r
++ kvps.push_back(kvp);\r
++ }\r
++ }\r
++ }\r
++\r
++ cfgfile.close();\r
++}\r
++\r
++/************************************************************************/\r
++/* getValue() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch a configured item's value.\r
++ *\r
++ * This method is used to fetch a items value from a configuration file.\r
++ *\r
++ * @param keyname The item's name.\r
++ *\r
++ * @return The result string.\r
++ */\r
++\r
++string CFGReader::getValue(const string &keyname)\r
++{\r
++ for (int i = 0; i < size(); i++)\r
++ {\r
++ if (EQUAL(kvps[i].name.c_str(), keyname.c_str()))\r
++ return kvps[i].value;\r
++ }\r
++\r
++ return "";\r
++}\r
++\r
++/************************************************************************/\r
++/* getValue() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Fetch a configured item's value, with default value.\r
++ *\r
++ * This method is used to fetch a items value from a configuration file,\r
++ * if not found, use the default value.\r
++ *\r
++ * @param keyname The item's name.\r
++ *\r
++ * @param defaultvalue The item's default value.\r
++ *\r
++ * @return The result string.\r
++ */\r
++\r
++string CFGReader::getValue(const string &keyname, const string &defaultvalue)\r
++{\r
++ string ret = getValue(keyname);\r
++ if (ret.empty() || ret == "")\r
++ return defaultvalue;\r
++ else\r
++ return ret;\r
++}\r
++\r
++/************************************************************************/\r
++/* Run() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief The entry point for CGI program.\r
++ *\r
++ * This method is used to fetch CGI parameters. Supports both HTTP GET\r
++ * and POST method. POST content could be KVPs and XML string, and GET\r
++ * content must be KVPs.\r
++ *\r
++ * @return CE_None on success or CE_Failure on failure.\r
++ */\r
++\r
++CPLErr WCSCGI::Run()\r
++{\r
++ /* get request parameters*/\r
++ char *gm = getenv("REQUEST_METHOD");\r
++ if (NULL == gm)\r
++ {\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Get \"REQUEST_METHOD\" Environment variable.");\r
++ return CE_Failure;\r
++ }\r
++\r
++ if (EQUAL(gm, "POST"))\r
++ me_CGIMethod = HTTP_XML_POST;\r
++ else if (EQUAL(gm, "GET"))\r
++ me_CGIMethod = HTTP_GET;\r
++ else\r
++ me_CGIMethod = UN_KNOWN;\r
++\r
++ switch (me_CGIMethod)\r
++ {\r
++ case HTTP_XML_POST:\r
++ {\r
++ char* aString = getenv("CONTENT_LENGTH");\r
++ if (NULL == aString || aString[0] == '\0')\r
++ {\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Get \"CONTENT_LENGTH\" Environment variable.");\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ return CE_Failure;\r
++ }\r
++\r
++ unsigned int cLength = atoi(aString);\r
++\r
++ string cString;\r
++ cString.resize(cLength + 1);\r
++\r
++ if (cLength != fread((char*) cString.c_str(), 1, cLength, stdin))\r
++ {\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Failed to Read POST Data Stream from Internet.");\r
++ return CE_Failure;\r
++ }\r
++\r
++ cString = StrReplace(cString, "&s;", "%26");\r
++ cString = StrReplace(cString, "&", "%26");\r
++\r
++ string tmpStr = CPLUnescapeString(cString.c_str(), NULL, CPLES_URL);\r
++ ms_CGIContent = CPLUnescapeString((char*) tmpStr.c_str(), NULL, CPLES_XML);\r
++\r
++ string::size_type beginIdx, endIdx;\r
++\r
++ beginIdx = ms_CGIContent.find("<?");\r
++ endIdx = ms_CGIContent.rfind(">");\r
++ //The post contents could be KVPs\r
++ if (beginIdx != string::npos && endIdx != string::npos)\r
++ ms_CGIContent = ms_CGIContent.substr(beginIdx, endIdx - beginIdx + 1);\r
++ }\r
++ break;\r
++ case HTTP_GET:\r
++ {\r
++ string tmpStr = getenv("QUERY_STRING");\r
++ tmpStr = StrReplace(tmpStr, "&s;", "%26");\r
++ tmpStr = StrReplace(tmpStr, "&", "%26");\r
++ if (tmpStr.empty() || tmpStr == "")\r
++ {\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "No \"QUERY_STRING\" Content.");\r
++ return CE_Failure;\r
++ }\r
++\r
++ ms_CGIContent = CPLUnescapeString((char*) tmpStr.c_str(), NULL, CPLES_URL);\r
++ }\r
++ break;\r
++ default:\r
++ {\r
++ SetWCS_ErrorLocator("WCSCGI::Run()");\r
++ WCS_Error(CE_Failure, OGC_WCS_NoApplicableCode, "Unkown \"REQUEST_METHOD\".");\r
++ return CE_Failure;\r
++ }\r
++ }\r
++\r
++ return CE_None;\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// KVPsReader constructor\r
++// -----------------------------------------------------------------------\r
++KVPsReader::KVPsReader(const string& urlStr, const char &tok)\r
++{\r
++ StringList strLit(urlStr, tok);\r
++\r
++ for (int i = 0; i < strLit.size(); ++i)\r
++ {\r
++ KVP kvp(StrTrim(strLit[i]));\r
++ m_kvps.push_back(kvp);\r
++ }\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// KVPsReader get value function\r
++// -----------------------------------------------------------------------\r
++string KVPsReader::getValue(const string &keyname)\r
++{\r
++ for (unsigned int i = 0; i < m_kvps.size(); i++)\r
++ {\r
++ if (EQUAL(m_kvps[i].name.c_str() , keyname.c_str()))\r
++ return m_kvps[i].value;\r
++ }\r
++ return "";\r
++}\r
++\r
++\r
++vector<string> KVPsReader::getValues(const string &keyname)\r
++{\r
++ vector<string> valuesList;\r
++ for (unsigned int i = 0; i < m_kvps.size(); i++)\r
++ {\r
++ if (EQUAL(m_kvps[i].name.c_str() , keyname.c_str()))\r
++ valuesList.push_back(m_kvps[i].value);\r
++ }\r
++ return valuesList;\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// KVPsReader get value function, with default value\r
++// -----------------------------------------------------------------------\r
++string KVPsReader::getValue(const string &keyname, const string &defaultvalue)\r
++{\r
++ string ret = getValue(keyname);\r
++ if (ret.empty() || ret == "")\r
++ return defaultvalue;\r
++ else\r
++ return ret;\r
++}\r
++\r
++/************************************************************************/\r
++/* StrReplace() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Replace a string.\r
++ *\r
++ * This method is used to replace a string with specified substring.\r
++ *\r
++ * @param str The string needs to be processed.\r
++ *\r
++ * @param oldSubStr The substring needs to be replaced.\r
++ *\r
++ * @param newStr The string will replace the oldSubStr.\r
++ *\r
++ * @return The processed string.\r
++ */\r
++\r
++string CPL_STDCALL StrReplace(string& str, const string oldSubStr, const string newStr)\r
++{\r
++ while(true)\r
++ {\r
++ string::size_type pos(0);\r
++ if( ( pos = str.find(oldSubStr) ) != string::npos )\r
++ {\r
++ str.replace( pos, oldSubStr.length(), newStr );\r
++ }else {\r
++ break;\r
++ }\r
++ }\r
++ return str;\r
++}\r
++\r
++/************************************************************************/\r
++/* GetSingleValue() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Get a single value from a special KVP part.\r
++ *\r
++ * This method is used to get value from a special KVP part.\r
++ *\r
++ * @param subsetstr The string needs to be processed, such as "subset=Long(11)".\r
++ *\r
++ * @return The processed string, such as "11".\r
++ */\r
++\r
++string CPL_STDCALL GetSingleValue(const string& subsetstr)\r
++{\r
++ string::size_type idx1 = subsetstr.find_last_of('(');\r
++ string::size_type idx2 = subsetstr.find_last_of(')');\r
++\r
++ return StrTrim(subsetstr.substr(idx1 + 1, idx2 - idx1 -1));\r
++}\r
++\r
++/************************************************************************/\r
++/* GetSubSetLatLon() */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \brief Get a subset spatial extent in WCS 2.0 request.\r
++ *\r
++ * This method is used to get values of spatial extent and place the values\r
++ * in an array, and return the CRS code for the coordinates of the extent.\r
++ *\r
++ * @param subsetstr The string needs to be processed,\r
++ * such as "subset=Lat,http://www.opengis.net/def/crs/EPSG/0/4326(32,47)".\r
++ *\r
++ * @param subsetvalue The array to place the spatial extent values.\r
++ *\r
++ * @return The processed string, such as "EPSG:4326".\r
++ */\r
++\r
++string CPL_STDCALL GetSubSetLatLon(const string& subsetstr, vector<double> &subsetvalue)\r
++{\r
++ string::size_type idx1 = subsetstr.find_last_of('(');\r
++ string::size_type idx2 = subsetstr.find_last_of(')');\r
++\r
++ string value = StrTrim(subsetstr.substr(idx1 + 1, idx2 - idx1 -1));\r
++ vector<string> tmpV;\r
++ CsvburstCpp(value, tmpV, ',');\r
++\r
++ for(unsigned int i = 0; i < tmpV.size(); i++)\r
++ {\r
++ double curD;\r
++ convertFromString(curD, tmpV.at(i));\r
++ subsetvalue.push_back(curD);\r
++ }\r
++\r
++ string subsetProj;\r
++ idx1 = subsetstr.find(',');\r
++ idx2 = subsetstr.find('(');\r
++ if(idx1 > idx2) \r
++ {\r
++ subsetProj = "EPSG:4326";\r
++ }\r
++ else\r
++ {\r
++ value = StrTrim(subsetstr.substr(idx1 + 1, idx2 - idx1 - 1));\r
++ if(value.find("http") != string::npos)\r
++ {\r
++ string::size_type idx3 = value.find_last_of('/');\r
++ subsetProj = "EPSG:" + value.substr(idx3 + 1);\r
++ }\r
++ else\r
++ {\r
++ subsetProj = value;\r
++ }\r
++\r
++ }\r
++\r
++ return subsetProj;\r
++}\r
++\r
++//subset=phenomenonTime("2006-08-01","2006-08-22T09:22:00Z")&\r
++//subset=phenomenonTime("2006-08-01")&\r
++void CPL_STDCALL GetSubSetTime(const string& subsetstr, vector<string> &subsetvalue)\r
++{\r
++ string::size_type idx1 = subsetstr.find_last_of('(');\r
++ string::size_type idx2 = subsetstr.find_last_of(')');\r
++ string value = StrTrim(subsetstr.substr(idx1 + 1, idx2 - idx1 - 1));\r
++ string valueN = StrReplace(value, "\"", "");\r
++ CsvburstCpp(valueN, subsetvalue, ',');\r
++}\r
++\r
++//time type 1: 2006-08-22T09:22:00Z\r
++//time type 1: 2006-08-01\r
++int CPL_STDCALL CompareDateTime_GreaterThan(string time1, string time2)\r
++{\r
++ time_t retval1 = 0;\r
++ time_t retval2 = 0;\r
++\r
++ struct tm storage1 = {0,0,0,0,0,0,0,0,0};\r
++ struct tm storage2 = {0,0,0,0,0,0,0,0,0};\r
++\r
++ char *p1 = NULL;\r
++ char *p2 = NULL;\r
++\r
++ if(time1.find("T") != string::npos && time1.find("Z") != string::npos)\r
++ p1 = (char *)strptime(time1.c_str(), "%Y-%m-%dT%H:%M:%SZ", &storage1);\r
++ else\r
++ p1 = (char *)strptime(time1.c_str(), "%Y-%m-%d", &storage1);\r
++\r
++ if(time2.find("T") != string::npos && time2.find("Z") != string::npos)\r
++ p2 = (char *)strptime(time2.c_str(), "%Y-%m-%dT%H:%M:%SZ", &storage2);\r
++ else\r
++ p2 = (char *)strptime(time2.c_str(), "%Y-%m-%d", &storage2);\r
++\r
++ retval1 = mktime(&storage1);\r
++ retval2 = mktime(&storage2);\r
++\r
++ if(retval1 == retval2)\r
++ return 0;\r
++ else if(retval1 > retval2)\r
++ return 1;\r
++ else\r
++ return -1;\r
++\r
++}\r
++\r
++int CPL_STDCALL ConvertDateTimeToSeconds(string datetime)\r
++{\r
++ time_t retval1 = 0;\r
++ struct tm storage1 = {0,0,0,0,0,0,0,0,0};\r
++ char *p1 = NULL;\r
++\r
++ if(datetime.find("T") != string::npos && datetime.find("Z") != string::npos)\r
++ p1 = (char *)strptime(datetime.c_str(), "%Y-%m-%dT%H:%M:%SZ", &storage1);\r
++ else\r
++ p1 = (char *)strptime(datetime.c_str(), "%Y-%m-%d", &storage1);\r
++\r
++ retval1 = mktime(&storage1);\r
++\r
++ return retval1;\r
++}\r
++\r
++// -----------------------------------------------------------------------\r
++// Find lower-left and upper-right corner point coordinate\r
++// -----------------------------------------------------------------------\r
++void CPL_STDCALL GetCornerPoints(const GDAL_GCP* &pGCPList, const int &nGCPs, My2DPoint& lowLeft, My2DPoint& upRight)\r
++{\r
++ double xLeft = (numeric_limits<double>::max)();\r
++ double xRight = -xLeft;\r
++ double yLower = (numeric_limits<double>::max)();\r
++ double yUpper = -yLower;\r
++\r
++ for (int j = 0; j < nGCPs; j++)\r
++ {\r
++ yUpper = MAX(yUpper,pGCPList[j].dfGCPY);\r
++ yLower = MIN(yLower,pGCPList[j].dfGCPY);\r
++ if(pGCPList[j].dfGCPX != -999)//test MOD021KM.A2000065.1900.005.2008235220315.hdf, error GCP X value (-999)\r
++ xLeft = MIN(xLeft,pGCPList[j].dfGCPX);\r
++ xRight = MAX(xRight,pGCPList[j].dfGCPX);\r
++ }\r
++\r
++ lowLeft.mi_X = xLeft;\r
++ lowLeft.mi_Y = yLower;\r
++ upRight.mi_X = xRight;\r
++ upRight.mi_Y = yUpper;\r
++\r
++ return;\r
++}\r
+diff -Nur bes-3.12.0/functions.orig/swath2grid/wcsUtil.h bes-3.12.0/functions/swath2grid/wcsUtil.h
+--- bes-3.12.0/functions.orig/swath2grid/wcsUtil.h 1970-01-01 01:00:00.000000000 +0100
++++ bes-3.12.0/functions/swath2grid/wcsUtil.h 2014-03-03 15:47:38.043566262 +0100
+@@ -0,0 +1,381 @@
++/******************************************************************************\r
++ * $Id: wcsUtil.h 2011-07-19 16:24:00Z $\r
++ *\r
++ * Project: The Open Geospatial Consortium (OGC) Web Coverage Service (WCS)\r
++ * for Earth Observation: Open Source Reference Implementation\r
++ * Purpose: WCS Utility Function definition\r
++ * Author: Yuanzheng Shao, yshao3@gmu.edu\r
++ *\r
++ ******************************************************************************\r
++ * Copyright (c) 2011, Liping Di <ldi@gmu.edu>, Yuanzheng Shao <yshao3@gmu.edu>\r
++ *\r
++ * Permission is hereby granted, free of charge, to any person obtaining a\r
++ * copy of this software and associated documentation files (the "Software"),\r
++ * to deal in the Software without restriction, including without limitation\r
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
++ * and/or sell copies of the Software, and to permit persons to whom the\r
++ * Software is furnished to do so, subject to the following conditions:\r
++ *\r
++ * The above copyright notice and this permission notice shall be included\r
++ * in all copies or substantial portions of the Software.\r
++ *\r
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
++ * DEALINGS IN THE SOFTWARE.\r
++ ****************************************************************************/\r
++\r
++#ifndef WCSUTIL_H_\r
++#define WCSUTIL_H_\r
++\r
++#include <iostream>\r
++#include <fstream>\r
++#include <sstream>\r
++#include <vector>\r
++#include <stdlib.h>\r
++#include <time.h>\r
++\r
++#include <cpl_string.h>\r
++#include "wcs_error.h"\r
++#include "BoundingBox.h"\r
++\r
++using namespace std;\r
++\r
++#ifndef EQUAL\r
++#if defined(WIN32) || defined(WIN32CE)\r
++# define EQUALN(a,b,n) (strnicmp(a,b,n)==0)\r
++# define EQUAL(a,b) (stricmp(a,b)==0)\r
++#else\r
++# define EQUALN(a,b,n) (strncasecmp(a,b,n)==0)\r
++# define EQUAL(a,b) (strcasecmp(a,b)==0)\r
++#endif\r
++#endif\r
++\r
++#ifndef TRUE\r
++#define TRUE 1\r
++#endif\r
++#ifndef FALSE\r
++#define FALSE 0\r
++#endif\r
++\r
++#ifndef NULL\r
++#define NULL 0\r
++#endif\r
++\r
++#ifdef WINDOWS\r
++#define DELIMITER "\\"\r
++#else\r
++#define DELIMITER "/"\r
++#endif\r
++\r
++const int SHORT_NAME_LEN = 128;\r
++const int MAX_NAME_LEN = 512;\r
++const int MAX_LIST_LEN = 1024;\r
++const int MAX_LINE_LEN = 65536;\r
++\r
++\r
++// -----------------------------------------------------------------------\r
++// CGI (Common Gateway Interface) related class and functions\r
++// -----------------------------------------------------------------------\r
++enum CGI_METHOD_FLAG\r
++{\r
++ UN_KNOWN, HTTP_GET, HTTP_XML_POST\r
++};\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* WCSCGI */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++\r
++/**\r
++ * \class WCSCGI "wcsUtil.h"\r
++ *\r
++ * WCSCGI class is used to acquire WCS request, both GET and POST method\r
++ * are supported.\r
++ */\r
++\r
++class WCSCGI\r
++{\r
++private:\r
++ string ms_CGIContent;\r
++ CGI_METHOD_FLAG me_CGIMethod;\r
++\r
++public:\r
++ WCSCGI()\r
++ {\r
++ me_CGIMethod = UN_KNOWN;\r
++ }\r
++\r
++ CPLErr Run();\r
++\r
++ string GetRqstContent()\r
++ {\r
++ return ms_CGIContent;\r
++ }\r
++\r
++ CGI_METHOD_FLAG GetCGImethod()\r
++ {\r
++ return me_CGIMethod;\r
++ }\r
++};\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* StringList */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++\r
++class StringList\r
++{\r
++private:\r
++ vector<string> strings;\r
++\r
++public:\r
++ StringList(const string& sstrings, const char delimiter);\r
++ StringList(const string& sstrings, const string& delimiters);\r
++ StringList(){ }\r
++\r
++ int indexof(string qstr);\r
++\r
++ void add(string newstr)\r
++ {\r
++ strings.push_back(newstr);\r
++ }\r
++\r
++ void clear()\r
++ {\r
++ strings.clear();\r
++ }\r
++\r
++ int size()\r
++ {\r
++ return strings.size();\r
++ }\r
++\r
++ string& operator [](int index)\r
++ {\r
++ return strings[index];\r
++ }\r
++\r
++ void append(StringList & s);\r
++ void append(const string sstrings, const char delimiter);\r
++ void append(const string sstrings, const string& delimiters);\r
++\r
++ string toString()\r
++ {\r
++ string s = "";\r
++ for (int i = 0; i < size(); i++)\r
++ s += strings[i];\r
++ return s;\r
++ }\r
++\r
++ string toString(const char delimiter)\r
++ {\r
++ string s = "";\r
++ for (int i = 0; i < size(); i++)\r
++ s += strings[i] + delimiter;\r
++ return s;\r
++ }\r
++\r
++ string toString(const string& delimiters)\r
++ {\r
++ string s = "";\r
++ for (int i = 0; i < size(); i++)\r
++ s += strings[i] + delimiters;\r
++ return s;\r
++ }\r
++};\r
++\r
++class S2C\r
++{\r
++\r
++private:\r
++ char buf[MAX_LINE_LEN];\r
++\r
++public:\r
++ S2C(string s)\r
++ {\r
++ s.copy(buf, string::npos);\r
++ buf[s.size()] = 0;\r
++ }\r
++\r
++ char * c_str()\r
++ {\r
++ return buf;\r
++ }\r
++\r
++};\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* KVP */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++\r
++class KVP\r
++{\r
++public:\r
++ string name, value;\r
++\r
++ KVP& operator =(const KVP &id)\r
++ {\r
++ name = id.name;\r
++ value = id.value;\r
++ return *this;\r
++ }\r
++\r
++ KVP& operator =(const KVP *pid)\r
++ {\r
++ name = pid->name;\r
++ value = pid->value;\r
++ return *this;\r
++ }\r
++\r
++ KVP(string n, string v) :\r
++ name(n), value(v)\r
++ {\r
++ }\r
++\r
++ KVP(string namevaluepair);\r
++};\r
++\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* KVPsReader */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++\r
++class KVPsReader\r
++{\r
++protected:\r
++ vector<KVP> m_kvps;\r
++\r
++public:\r
++ KVPsReader()\r
++ {\r
++ }\r
++\r
++ ~KVPsReader()\r
++ {\r
++ }\r
++\r
++ KVPsReader(const string& urlStr, const char &tok);\r
++\r
++ KVP& operator [](const int index)\r
++ {\r
++ return m_kvps[index];\r
++ }\r
++\r
++ int size()\r
++ {\r
++ return m_kvps.size();\r
++ }\r
++\r
++ string getValue(const string &keyname);\r
++ string getValue(const string &keyname, const string &defaultvalue);\r
++ vector<string> getValues(const string &keyname);\r
++};\r
++\r
++/************************************************************************/\r
++/* ==================================================================== */\r
++/* CFGReader */\r
++/* ==================================================================== */\r
++/************************************************************************/\r
++class CFGReader\r
++{\r
++protected:\r
++ vector<KVP> kvps;\r
++\r
++public:\r
++ CFGReader(const string &configfilename);\r
++\r
++ KVP& operator [](const int index)\r
++ {\r
++ return kvps[index];\r
++ }\r
++\r
++ int size()\r
++ {\r
++ return kvps.size();\r
++ }\r
++\r
++ string getValue(const string &keyname);\r
++ string getValue(const string &keyname, const string &defaultvalue);\r
++};\r
++\r
++\r
++// -----------------------------------------------------------------------\r
++// Extra Template Functions\r
++// Exchange() --- used to exchange values\r
++// convertToString() --- convert value to string\r
++// convertFromString --- convert string to values\r
++// -----------------------------------------------------------------------\r
++template<class T>\r
++static void Exchange(T & a, T & b)\r
++{\r
++ T t;\r
++ t = a;\r
++ a = b;\r
++ b = t;\r
++}\r
++\r
++template <class T>\r
++static string convertToString(T &value)\r
++{\r
++ stringstream ss;\r
++ ss<<value;\r
++ string rtnstr = ss.str();\r
++ return rtnstr;\r
++}\r
++\r
++template <class T>\r
++static void convertFromString(T &value, const string& s)\r
++{\r
++ stringstream ss(s);\r
++ ss>>value;\r
++}\r
++\r
++\r
++// -----------------------------------------------------------------------\r
++// Extra Utility Functions\r
++// -----------------------------------------------------------------------\r
++CPL_C_START\r
++\r
++// String Operation Related\r
++int CPL_DLL CPL_STDCALL CsvburstCpp(const std::string& line, std::vector<std::string> &strSet, const char tok);\r
++int CPL_DLL CPL_STDCALL CsvburstComplexCpp(const string& line, vector<string> &strSet, const char* tok);\r
++int CPL_DLL CPL_STDCALL Find_Compare_SubStr(string line, string sub);\r
++void CPL_DLL CPL_STDCALL Strslip(const char* str, const char* arrStr[], const char leftdlm, const char rightdlm);\r
++string CPL_DLL CPL_STDCALL StrReplace(string& str, const string oldSubStr, const string newStr);\r
++string CPL_DLL CPL_STDCALL SPrintArray(GDALDataType eDataType, const void *paDataArray, int nValues, const char *pszDelimiter);\r
++string CPL_DLL CPL_STDCALL StrTrimHead(const string &str);\r
++string CPL_DLL CPL_STDCALL StrTrimTail(const string &str);\r
++string CPL_DLL CPL_STDCALL StrTrims(const std::string&, const char*);\r
++string CPL_DLL CPL_STDCALL StrTrim(const string &str);\r
++\r
++// Date Time Operation Related\r
++int CPL_DLL CPL_STDCALL CompareDateTime_GreaterThan(string time1, string time2);\r
++int CPL_DLL CPL_STDCALL ConvertDateTimeToSeconds(string datetime);\r
++string CPL_DLL CPL_STDCALL GetTimeString(int code);\r
++\r
++// Directory Operation Related\r
++CPLErr CPL_DLL CPL_STDCALL GetFileNameList(char* dir, std::vector<string> &strList);\r
++string CPL_DLL CPL_STDCALL MakeTempFile(string dir, string covID, string suffix);\r
++string CPL_DLL CPL_STDCALL GetUUID();\r
++\r
++// Request Parser Operation\r
++void CPL_DLL CPL_STDCALL GetSubSetTime(const string& subsetstr, vector<string> &subsetvalue);\r
++string CPL_DLL CPL_STDCALL GetSubSetLatLon(const string& subsetstr, vector<double> &subsetvalue);\r
++string CPL_DLL CPL_STDCALL GetSingleValue(const string& subsetstr);\r
++\r
++CPLErr CPL_DLL CPL_STDCALL GetTRMMBandList(string start, string end, std::vector<int> &bandList);\r
++void CPL_DLL CPL_STDCALL GetCornerPoints(const GDAL_GCP* &pGCPList, const int &nGCPs, My2DPoint& lowLeft, My2DPoint& upRight);\r
++\r
++CPL_C_END\r
++\r
++#endif /*WCSUTIL_H_*/\r