Steve
Steve

Reputation: 546

GeoServer - DWITHIN not filtering points correctly

The solution I am looking for is either an accurate way to convert kilometers to degrees for the DWITHIN request or to get GeoServer to recognize the units specified in the request to be able to pass in kilometers directly.

I am making a WFS request to GeoServer to return points within a certain distance (eg within 3km of a point) and my results are not accurate. I am currently using OpenLayers version 3.11.2 and running GeoServer version 2.6.2 and have also tested with 2.7.1.

This is the CQL Filter I am using for the DWITHIN where the 3rd parameter is the degree value of the radius to return results within. I do a closing parenthesis using the "%29" because I was having issues with that getting dropped when making the request.

CQL_FILTER=dwithin(the_geom,point(46.1379%20-60.1957),0.05577532499489729,meters%29

The issue is that there is a bug in GeoServer which only supports degrees even though I state units as meters. More info about that here https://gis.stackexchange.com/questions/132251/dwithin-wfs-filter-is-not-working

I tried working through this issue before and reached a scale that was accurate enough at the time which can be read here Geoserver - filtering points using DWITHIN

These calculations are being done in JavaScript. Originally I was using the radius/111.325 to convert the km to degrees which was not returning some points that were within the search. eg Radius was set to 2.7km and results 2km away would not return sometimes.

I have now changed the calculation to adjust the distance between longitudes based off the latitude using info from this question https://gis.stackexchange.com/questions/142326/calculating-longitude-length-in-miles

//get value of a degree in radians at current Latitude
var latRadians = lat * Math.PI / 180;

//get the value in kilometers for the current latitude based off radian value 
var degreeKM = latRadians * 111.325

var converteddistance = radius / degreeKM;

I am then passing in the converted distance in the CQL Fitler as the radius to return results within. The issue with this is some results are now returning outside the radius. This circle was drawn with a radius of 5km and you can see the results returning 5.79km away.

Image Radius

I also put the latitude/longitude into the calculator at this url for the center of the circle and the points that are appearing outside of it. The calculator gave me the same distance and my measurement tools used in the image so I believe the circle and measurement tool is working correctly. http://www.movable-type.co.uk/scripts/latlong.html

Upvotes: 2

Views: 1320

Answers (2)

ADJenks
ADJenks

Reputation: 3434

DWITHIN is basically broken, as of my answering. It doesn't accept units properly and hasn't been drawing a correct circle for me either, it comes out oblong even on a small scale near the equator with the correct projection input.

My workaround / solution: Compute a circle as a polygon using a spatial library on the client, generate the well-known text (WKT) and use WITHIN instead of DWITHIN.

After reading several complaints about DWITHIN on GeoServer and seeing no attempt to fix it, I decided I shouldn't be using it for now. Perhaps you or I could donate some time to fix it :)

The client code will be more complex and I won't demonstrate it here, but the CQL code will be much simpler, without a radius or units, and would look something like this:

WITHIN(the_geom,POLYGON((<circle-path-here>)))

Upvotes: 0

JGH
JGH

Reputation: 17906

There are several issues in the way you compute the length of one degree.

First, the length of a degree of latitude is not the same as a degree of longitude. Doing so will produce an ellipse, not a circle. If you use the smallest length (longitude) you will omit points, if you use the longest one (latitude) you will have too much points.

To get the length of a degree of longitude at a given latitude, you must use the cosine and do the computation in degrees.

degreeKM = cos(latDegree) * 111.325

At 60 degrees, it would be roughly cos(60)*111.325 = 55.66 km, which corresponds to values found here, and which is almost half of the length you currently have.

That being said, this whole approach is rather cumbersome for such as basic task. Do you have access to DB like PostGIS where you could do the filtering?

Upvotes: 2

Related Questions