wiki:SoCWMSDriver

Version 11 (modified by nowakpl, 17 years ago) ( diff )

--

NOTE: This page is work in progress.

OGC WMS Driver

The driver is composed of interface layer between GDAL and mini-drivers, and many small mini-drivers. Mini-driver only task is to provide image locations, actual downloads and returning data is handled by interface layer. Example:

  1. User requests (via RasterIO call) 400x400 image block starting at pixel (500, 700).
  2. Mini-driver is asked to provide list of images to download and returns:
    1. upper-left corner: (500, 500), lower-right corner: (1000, 1000)

url: http://example.com/?width=500&height=500&bbox=5,5,10,10

  1. upper-left corner: (500, 1000), lower-right corner: (1000, 1500)

url: http://example.com/?width=500&height=500&bbox=5,10,10,15

  1. The images are downloaded, resampled, mosaicked, cropped to fit the user request.

The interface layer implements:

	class GDALWMSDataset : public GDALPamDataset {
	    virtual CPLErr IRasterIO( ... );
	    virtual CPLErr AdviseRead( ... );
	    virtual const char *GetProjectionRef();
	    virtual CPLErr GetGeoTransform( ... );
	};

	class GDALWMSRasterBand : public GDALPamRasterBand {
	    virtual CPLErr IReadBlock( ... );
	    virtual CPLErr IRasterIO( ... );
	    virtual CPLErr AdviseRead( ... );
	    virtual int HasArbitraryOverviews();
	    virtual int GetOverviewCount();
	    virtual GDALRasterBand *GetOverview( ... );
	};

HasArbitraryOverviews always returns true. Overview count is set in configuration file, each overview layer has half the resolution of previous layer. GetProjectionRef returns projection as specified in configuration file. GetGeoTransform returns geo-transform constructed from data window. IRasterIO, AdviseRead and IReadBlock are translated into common request format:

	class ImageRequest {
	public:
	    double m_x0, m_y0; // geo-referenced upper-left corner
	    double m_x1, m_y1; // geo-referenced lower-right corner
	    int m_xsize, m_ysize; // width and height in pixels
	};

	class ImageBufferInfo { // see GDALDataset::RasterIO documentation
	public:
	    void *m_data;
	    int m_xsize, m_ysize;
	    GDALDataType m_data_type;
	    int m_band_count;
	    int *m_band_map;
	    int m_pixel_space;
	    int m_line_space;
	    int m_band_space;
	};

Dataset open

  1. open, verify and read XML configuration file into CPL MiniXML tree
  2. update XML tree with arguments specified in dataset name
  3. create instance of mini-driver and pass in the XML tree

Dataset image request

  1. validate the request
  2. check if request can be satisfied from block cache only and return the data to user if possible
  3. call into mini-driver getting back list of image locations
  4. download the images, if allowed try in cache first
  5. update block cache wherever possible (resolution match, complete coverage)
  6. return the data to user

Download cache

If enabled in XML configuration file and allowed by mini-driver, downloaded images will be written to disk for future use. This should reduce load on the WMS server or even allow off-line operation. HTTP download queue Download queue is implemented using libcurl (http://curl.haxx.se/libcurl/), running in dedicated background thread to allow data preloading (AdviseRead or guessed). Can be configured to use HTTP pipelining and multiple connections.

XML configuration file

	<GDALWMS>
	  <HTTP> ... </HTTP>
	  <DataSource> ... </DataSource>
	  <DataWindow> ... </DataWindow>
	  <Cache> ... </Cache>
	</GDALWMS>

<HTTP> configures the HTTP download queue.

	<HTTP>
	  <MaxPipeline> ... </MaxPipeline>    number of requests on single connection	  <MaxParallel> ... </MaxParallel>    number of parallel connections
	  <UserAgent> ... </UserAgent>        custom user agent header
	  <User> ... </User>                  http authentication, user
	  <Password> ... </Password>          http authentication, password
	  <Proxy> ... </Proxy>                proxy support, see curl for docs
	  <ProxyPort> ... </ProxyPort>        
	  <ProxyType> ... </ProxyType>        
	  <ProxyUser> ... </ProxyUser>        
	  <ProxyPassword> ... </ProxyPassword>
	</HTTP>

<DataSource> specifies name and configuration for mini-driver.

	<DataSource driver=”some mini-driver”>
	  ... mini-driver specific configuration ...
	</DataSource>

<DataWindow> specifies projection, extents and resolution of data as visible by GDAL. Image size is in pixels, upper-left and lower-right corners are in specified projection. Overview count is optional and can be set to 0, default is calculated so last overview is bigger than 512x512. Block size is optional and defaults to 512x512.

	<DataWindow>
	  <Projection> ... </Projection>
	  <UpperLeftX> ... </UpperLeftX>
	  <UpperLeftY> ... </UpperLeftY>
	  <LowerRightX> ... </LowerRightX>
	  <LowerRightY> ... </LowerRightY>
	  <SizeX> ... </SizeX>
	  <SizeY> ... </SizeY>
	  <OverviewCount> ... </OverviewCount>
	  <BlockSizeX> ... </BlockSizeX>
	  <BlockSizeY> ... </BlockSizeY>
	</DataWindow>

Example data window (red) in global WMS layer (blue), geographic projection.

	<DataWindow>
	  <Projection>EPSG:4326</Projection>
	  <UpperLeftX>-120.0</UpperLeftX>
	  <UpperLeftY>60.0</UpperLeftY>
	  <LowerRightX>40.0</LowerRightX>
	  <LowerRightY>-40.0</LowerRightY>
	  <SizeX>4000</SizeX>
	  <SizeY>2500</SizeY>
	  <BlockSizeX>500</BlockSizeX>
	  <BlockSizeY>500</BlockSizeY>
	</DataWindow>

<Cache> specifies location of disk cache. If location is not set cache is disabled.

	<Cache>
	  <Path>/some/directory</Path>
	</Cache>

Mini-driver

Image download request, filled in by mini-driver and returned to interface layer.

	class ImageDownloadRequest {
	public:
	    CPLString m_url;       // image url to download
	    double m_x0, m_y0;     // georeferenced upper-left
	    double m_x1, m_y1;     // georeferenced bottom-right
	    int m_xsize, m_ysize;  // width and height in pixels
	    bool m_use_cache;      // should the image be cached / read from cache
	};

	typedef std::vector<ImageDownloadRequest> ImageDownloadRequestList;

Mini-driver

	class MiniDriver {
	public:
	    MiniDriver(CPLXMLNode *config);
	    virtual ~MiniDriver();

	public:
	    // Process image request and add image download requests to the list
	    virtual void AppendImageDownloadRequestList(
	        ImageDownloadRequestList &out, const ImageRequest &in);
	};

Mini-driver factory, used to create instance of given mini-driver.

	class MiniDriverFactory {
	public:
	    MiniDriverFactory();
	    virtual ~MiniDriverFactory();

	public:
	    // create mini-driver instance, basically:
	    // return new ExampleMiniDriver(config);
	    virtual MiniDriver* New(CPLXMLNode *config);

	    // destroy mini-driver instance, basically:
	    // delete instance;
	    virtual void Delete(MiniDriver *instance);

	public:
	    const std::string &GetName() {
	        return m_name;
	    }

	protected:
	    // <DataSource name=”...”> in configuration file
	    std::string m_name;
	};

Planned mini-drivers

OGC WMS mini-driver

  • The driver will not issue GetCapabilities requests, all information has to be stored in XML configuration file.
  • Small utility program will be provided (probably a script) to handle GetCapabilities requests and write configuration file.
  • Arbitrary overviews handled by WMS server.
  • Custom arguments in server URL (for example WMS Time)
  • Many download patterns:
    1. one download (light green) per image request (dark green), partial block cache (gray), disk cache not allowed
    2. one download per image request, extended to block cache grid, disk cache not allowed
    3. many downloads per image request (tiled), full block cache, disk cache allowed

OGC WMS mini-driver configuration

	<DataSource driver=”WMS”>
	  <Version>1.3.0</Version>
	  <ServerUrl>http://127.0.0.1/mapserv.cgi</ServerUrl>
	  <CRS>CRS:83</CRS>
	  <ImageFormat>image/png</ImageFormat>
	  <Layers>layer1,layer2</Layers>
	  <Styles>style1,style2</Styles>
	  <CustomArgs>
	    <time>2000-01-01T</time>
	  </CustomArgs>
	</DataSource>

Example mini-driver implementation

Mini-driver for a WMS-like service with requests in format: http://server/file?width=...&height=...&bbox=...

	MyMiniDriver::MyMiniDriver(CPLXMLNode *config) {
	    m_server = CPLGetXMLValue(config, "ServerURL", "");
	}

	MyMiniDriver::~MyMiniDriver() {
	}

	void MyMiniDriver::AppendImageDownloadRequestList(
	        ImageDownloadRequestList &out, const ImageRequest &in) {
	    ImageDownloadRequest req;
	    req.m_use_cache = false;
	    req.m_x0 = in.m_x0;
	    req.m_y0 = in.m_y0;
	    req.m_x1 = in.m_x1;
	    req.m_y1 = in.m_y1;
	    req.m_xsize = in.m_xsize;
	    req.m_ysize = in.m_ysize;
	    req.m_url.Printf("%s?width=%d&height=%d&bbox=%g,%g,%g,%g",
	            m_server.c_str(), in.m_xsize, in.m_ysize,
	            in.m_x0, in.m_y0, in.m_x1, in.m_y1);
	    out.push_back(req);
	}

	MyMiniDriverFactory::MyMiniDriverFactory() {
	    m_name = "MyWMS";
        }

	MyMiniDriverFactory::~MiniDriverFactory() {
	}

	MiniDriver* MyMiniDriverFactory::New(CPLXMLNode *p) {
	    return new MyMiniDriver(p);
	}

	void MyMiniDriverFactory::Delete(MiniDriver *p) {
	    delete p;
	}

Example XML configuration file for MyWMS mini-driver:

	<GDALWMS>
	  <DataSource name=”MyWMS”>
	    <ServerURL>http://localhost/mywms</ServerURL>
	  </DataSource>
	  ...
	</GDALWMS>

People

Other comments and suggestions

  • What protocol versions will be supported. I think WMS 1.1.0 is the most important but 1.0.0, and 1.3.0 are also desirable (FrankW)
    • As far as GetMap requests are concerned all three are almost equal (Nowak)
Note: See TracWiki for help on using the wiki.