Wednesday, August 11, 2010

Mysterious “BBOX” parameter in Web Feature Service (WFS)

“BBOX” is a standard parameter defined as part of the OGC Web Feature Service (WFS) keyword-value encoding which is used in GetFeature requests to request features within a specific extent. So “…&BBOX=-180.0,-90.0,180.0,90.0…” means getting all the features in the extent defined by lower corner coordinate (-180.0,-90.0) and upper corner coordinate (180.0,90.0). Not as straight forward as it seems to be to most people, I actually find it quite confusing when trying to answer this question below:

Is it possible to set BBOX to coordinate values in other projection?

The answer to this question depends on whether it’s WFS 1.0.0 (No) or WFS 1.1.0 (Yes), and the yes for WFS 1.1.0 even introduces some more complexity. So in the rest of this article I am going to clear things up based on the definition and statement in following OGC specifications:

BBOX in WFS 1.0.0

First of all, it is a little less confusing for WFS version 1.0.0 that  you CAN’T specify BBOX in coordinates of any other projections. This is based on two facts in specs:

(1) WFS 1.0.0 spec (02-058), section 13.3.3, where it says:

The SRS of the bounding box must be the same as the SRS of the feature type(s) in a request. The SRS of a feature type is advertised by a WFS in the capabilities document. If more than one feature type is specified in a request, the feature types must all be in the same SRS and the BBOX must be specified in the common SRS as well.

(2) In WFS 1.0.0 schema, a WFS’s capabilities response can have only one “SRS” allowed for each feature type.

But I did see people get confused and thus argue about one thing: Can I specify BBOX in EPSG:4326?

Based on the statement above, if a WFS serves out feature types in a non-EPSG4326 then it should be valid and compliant to just reject GetFeature request with BBOX in EPSG:4326. But another paragraph in WFS 1.0.0 spec (same section 13.3.3) seems to indicate a yes on it:

If a request contains a Bounding Box whose area does not overlap at all with the LatLongBoundingBox(s) advertised in the Capabilities XML for the requested geodata object, the server should return empty content (e.g. null feature set) for that element. Any elements that are partly or entirely contained in the Bounding Box should be returned in the appropriate format.

In this case we don’t really have to strictly follow the spec, and I won’t be surprised to see most WFS 1.0.0 implementations supports BBOX in EPSG:4326 no matter what SRS its feature types are in.

BBOX in WFS 1.1.0

Now for WFS 1.1.0, things get a little complicated because of the fact that there is an optional “crsurl” value you can append at the end of the BBOX coordinates to explicitly specify what coordinate reference system the BBOX is in. For example, ”…&BBOX=minX,minY,maxX,maxY,EPSG:900913” means that those min/max X/Y values are in EPSG:900913. Another complexity is that in WFS 1.1.0 capabilities response there can be multiple supported SRS for each feature type.  So based the section 14.3.3 of WFS spec 1.1.0:

The KVP encoding for a bounding box is defined in subclause 10.2.3 of normative reference [15]. The general form of the parameter is:
BBOX=lcc1,lcc2,…,lccN,ucc1,ucc2,…uccN[,crsuri]…


…If the crsuri is not specified then the 2-D coordinates shall be specified using decimal degrees and WGS84 as described in [15].

Note: The WFS spec is reference OWS 1.1.0 spec as [15] here

Here I can actually get two conclusions:

(1) You can specify BBOX in any coordinate reference system as long as you provide a “crsuri”.

Although not described in spec, I would believe you will get correct and useful response only if you request one of those supported coordinate reference system listed in a WFS’s capabilities.

(2) If “crsuri” is missing, then the coordinate values specified in BBOX should be considered as WGS84 as described in OWS 1.1.0 spec as below:

A WGS 84 bounding box shall be KVP encoded in a corresponding parameter value list, with the ordered listed values for the quantities:
LowerCorner longitude, in decimal degrees
LowerCorner latitude, in decimal degrees
UpperCorner longitude, in decimal degrees
UpperCorner latitude, in decimal degrees
crs URI = “urn:ogc:def:crs:OGC:1.3:CRS84” (optional)

In another word, if you set BBOX parameter in request without a “crsurl”, the BBOX value should always be in syntax “min_lon, min_lat, max_lon, max_lat”.

EPSG:4326 versus. CRS84

Now one finally thing people get confused very often is the order of longitude and latitude they should put in BBOX parameter for EPSG:4326 and CRS:84. Originally and as always, official EPSG:4326 defines coordinates in order of “latitude” followed by “longitude”, but unfortunately almost everyone speaks and uses the reverse order as “longitude” followed by “latitude”, which is why old spec like WMS 1.1.1 and WFS 1.0.0 also uses this order for EPSG:4326. But in most recent specifications OGC is trying to fix this common mistaken usage of EPSG:4326 by creating a brand new CRS:84, which based on my understanding is identical to EPSG:4326 except that it defines coordinates in order of “longitude” followed by “latitude”. So as far as WFS goes, always follow the rules below:

For WFS 1.0.0, uses EPSG:4326 and always set BBOX coordinate values as “longitude” followed by “latitude”. For WFS 1.1.0, specify coordinates in BBOX as longitude followed by latitude if you’re setting CRS:84 as the coordinate reference system for BBOX (e.g. “…&BBOX=–180.0,-90.0,180.0,90.0,urn:ogc:def:crs:OGC:1.3:CRS84…”), or set it the other way if you’re setting EPSG:4326 for BBOX (e.g. “…&BBOX=-90.0,-180.0,90.0,180.0,urn:x-ogc:def:crs:EPSG:6.9:4326…), but again if you’re omittng “crsuri” at the end please always stick to the order where longitude is ahead of latitude.

Summary

“BBOX” parameter looks easy and straight forward to use, but it also gets complicated when different versions of WFS implementations and EPSG:4326/WGS84 are involved. Hopefully this article clear things up a little.

6 comments:

  1. Hi Tang,
    This is really a good article.
    Can you help to clarify one thing:
    I have a viewing area:
    The latitude is from 35 to 40
    and the longitude is from 170 to 190.
    Yes, it's across the +-180 longitude line.
    Using CRS84, what's the right format/value in BBOX?
    It looks BBOX is not supporting 360 degree longitude.
    How can I get the right BBOX using +-180 based system?
    Thanks.

    ReplyDelete
  2. Hi, my understanding is that BBOX doesn't support crossing the +/-180.0 line, similar situation for WMS too. Usually when you need map or features in an area across +/-180.0 line you probably need to send two separate request.

    ReplyDelete
  3. Thanks! I couldn't figure out what WFS 1.1 was expecting for my BBOX or how to specify something other than EPSG:4326.

    ReplyDelete
  4. Thank you so much sir! This helped me so much! I did not now you could specify the EPSG in the BBOX and this helped to get the final missing piece of my puzzle

    ReplyDelete
  5. This was EXTREMELY helpful! Thank you thank you!

    I do have a followup question about bounding boxes in filters if you are able to answer.
    Is there a way to set the BBOX EPSG:4326 and the SRSNAME EPSG:3857 in a filter?

    So far I've been using filters in two different ways (which have the same effect).

    <Filter>
    <BBOX>
    <PropertyName>geometry_4326</PropertyName>
    <Envelope srsName='EPSG:4326'>
    <lowerCorner>{llat} {llon}</lowerCorner>
    <upperCorner>{ulat} {ulon}</upperCorner>
    </Envelope>
    </BBOX>
    </Filter>

    Or

    <Filter>
    <BBOX>
    <PropertyName>geometry_4326</PropertyName>
    <Box srsName='EPSG:4326'>
    <coordinates>{llon},{llat} {ulon},{ulat}</coordinates>
    </Box>
    </BBOX>
    </Filter>

    After reading your article, it dawned on me that we are able to set make the bounding box in one projection, while getting the data back in another using the &BBOX= parameter. This is extremely useful! Now if I can only do that while using a filter. (if that's even possible)

    ReplyDelete
  6. After playing around more with this, I figured out what I was missing.

    In the filter I needed to specify the srsName=EPSG: but then I ALSO needed to speficy the &SRSNAME=EPSG: for the data. I was thinking I needed to do both in the filter, which was incorrect.

    Again, you just filled in a huge gap in my knowledge. Thank you!

    ReplyDelete