Closed sudhamani1983 closed 6 years ago
The input units expected by geo.distance are the same units of the SRID in the database. By default this implementation of SensorThingsAPI uses 4326, which has as units degrees. Therefore, your call is requesting for locations that fall 50 degrees away from your POINT. Roughly 111 Kms in average for your case. I also can see that your database is using 4326 and 4269, be careful here because requests to the API do not include information about which SRID should be used. The SensorThingsAPI does not specify how to perform re-projections or transformations as part of a request. Therefore, mixing units should be avoided. I recommend you stick to the SRID and units that will fit the best for your case (meters). Some references here: Spatial refernces Or you could use a middle ware to do the conversion before passing the request to the API.
It's exactly as @manuGil explained.
You can change the srid of the database tables, and that will change the unit of the geo.distance and geo.length functions. I've not tested it though, and you might hit some bugs.
You might want to keep track of issue https://github.com/opengeospatial/sensorthings/issues/25 on the SenosorThingsAPI github, since that deals with this exact topic.
I have modified SRID to 3857 (measure in meters). I get below error while inserting location. as below
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.postgresql.util.PSQLException: ERROR: Geometry SRID (4326) does not match column SRID (3857) at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2455) at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2155) at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:288) at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:430) at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:356) at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:168) at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:135) at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:97) at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:97) at com.querydsl.sql.dml.SQLInsertClause.executeWithKeys(SQLInsertClause.java:368) ... 39 common frames omitted
SensorthingAPI Request:
Request : http://localhost:8080/SensorThingsService/v1.0/Locations
Request Body :
{
"name": "Sephora",
"encodingType": "application/vnd.geo+json",
"description": "Sephora",
"location": {
"type":"Point",
"coordinates": [103.832342,1.30373]
}
}
That is unfortunate. I had hoped PostgreSQL would automatically convert the object to the correct srid. A Quick hack is to change line 1394 and set the srid to 3857 there. https://github.com/FraunhoferIOSB/SensorThingsServer/blob/62e03068d84b56ed4890aa9fca0dde646afb75b4/SensorThingsServer.SQL/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/postgres/EntityInserter.java#L1393
Another option would be to add a trigger to the Location and feature of Interest tables, like mentioned in https://gis.stackexchange.com/questions/136137/auto-reprojecting-st-transform-srids-in-postgis/250384
I'll think about how to best solve this issue. Maybe I will make the srid configurable in the context xml file.
I tried changing SRID 3857 in de.fraunhofer.iosb.ilt.sta.persistence.postgres.EntityInserter line 1394
clause.set(geomPath, Expressions.template(Geometry.class, "ST_Force2D(ST_Transform(ST_GeomFromGeoJSON({0}), 3857))", geoJson));
POST Location working fine.
But get location using below request has issue in GET API.
http://localhost:8080/SensorThingsService/v1.0/Locations?$filter=geo.distance(Locations/location, geography'POINT (103.831709 1.304389)') gt 50
Caught PSQLException for select "e1"."ID", "e1"."ID", "e1"."NAME", "e1"."DESCRIPTION", "e1"."ENCODING_TYPE", "e1"."LOCATION", "e1"."GEOM" from "LOCATIONS" "e1" where ST_Distance("e1"."GEOM", ?) > ? order by "e1"."ID" asc limit ? at com.querydsl.sql.DefaultSQLExceptionTranslator.translate(DefaultSQLExceptionTranslator.java:50) at com.querydsl.sql.Configuration.translate(Configuration.java:459) at com.querydsl.sql.AbstractSQLQuery.fetch(AbstractSQLQuery.java:502) at de.fraunhofer.iosb.ilt.sta.persistence.postgres.EntityCreator.visit(EntityCreator.java:198) at de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement.visit(EntitySetPathElement.java:58) at de.fraunhofer.iosb.ilt.sta.persistence.postgres.PostgresPersistenceManager.get(PostgresPersistenceManager.java:439) at de.fraunhofer.iosb.ilt.sta.service.Service.executeGet(Service.java:145) at de.fraunhofer.iosb.ilt.sta.service.Service.execute(Service.java:75) at de.fraunhofer.iosb.ilt.sta.Servlet_1_0.executeService(Servlet_1_0.java:91) at de.fraunhofer.iosb.ilt.sta.Servlet_1_0.processGetRequest(Servlet_1_0.java:67) at de.fraunhofer.iosb.ilt.sta.Servlet_1_0.doGet(Servlet_1_0.java:135) at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) at de.fraunhofer.iosb.ilt.sta.Servlet_1_0.service(Servlet_1_0.java:173) at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.apache.catalina.filters.CorsFilter.handleNonCORS(CorsFilter.java:410) at org.apache.catalina.filters.CorsFilter.doFilter(CorsFilter.java:169) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:745) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) Caused by: org.postgresql.util.PSQLException: ERROR: Operation on mixed SRID geometries at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2455) at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2155) at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:288) at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:430) at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:356) at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:168) at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:116)
Can you try changing the line:
https://github.com/FraunhoferIOSB/SensorThingsServer/blob/62e03068d84b56ed4890aa9fca0dde646afb75b4/SensorThingsServer.SQL/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/postgres/expression/ConstantGeometryExpression.java#L38
to
return this.transform(3857).accept(v, context);
I have done change in "ConstantGeometryExpression" file as per your comments. Its working fine. I tried testing geo.distance using more places from googlemap and attached sample data as well.
Issue : But st_within(geography'POINT(103.832342 1.30375)', location) not return back correct result. Previously (Before changing SRID 3857 ) its working fine.
POINT(103.832342 1.30375) is within ION Orchard polygon, So I expect below request should return back Location - ION Orchard, but response is empty.
Request : POINT(103.832342 1.30375) is within ION Orchard polygon http://localhost:8080/SensorThingsService/v1.0/Locations?$filter=st_within(geography'POINT(103.832342 1.30375)', location)
Polygon location used for testing : { "name": "ION Orchard", "encodingType": "application/vnd.geo+json", "description": "ION Orchard", "location": { "coordinates": [ [ [103.831076,1.304072], [103.831943,1.304477], [103.832699,1.303807], [103.832020,1.303343], [103.831076,1.304072] ] ],"type":"Polygon"} }
Sample Test Data for geo.distance : geo.distance sample data.docx
Query :
select ST_Distance("e1"."GEOM", ST_Transform(ST_GeomFromText('SRID=4326;POINT(103.831709 1.304389)'), 3857)), "e1"."NAME" from "LOCATIONS" "e1"
Actually, PostGIS is correct here, your point is outside your polygon. See https://codepen.io/anon/pen/vexWag
The coordinate I tried is 103.832342 1.30375, its within ION orchard polygon.
Hmm, odd, the accept method is only used for the second argument, not the first. using st_contains instead of st_within (with the arguments also the other way around ofcourse) does work... I'll have to look into that in more detail.
Can you revert the change to ConstantGeometryExpression
And instead change the three occurrences of:
https://github.com/FraunhoferIOSB/SensorThingsServer/blob/62e03068d84b56ed4890aa9fca0dde646afb75b4/SensorThingsServer.SQL/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/postgres/PgExpressionHandler.java#L432
to
return new ConstantGeometryExpression(geom).transform(3857);
The other two are on line 438 and 444
Now st_within working as expected. Thanks for your support.
Hi, My understanding is Google Maps uses EPSG 3857 projected coordinate system. We used same SRID 3857. Can you please help me to explain why distance from POSTGIS - ST_Distance has slight difference from GoogleMap distance calculation?
Query : select ST_Distance("e1"."GEOM", ST_Transform(ST_GeomFromText('SRID=4326;POINT(103.831709 1.304389)'), 3857)), "e1"."NAME" from "LOCATIONS" "e1"
Distance Difference : DistanceDifferent.xlsx
That is a question best asked on the PostGIS mailing list, since they implemented the function. How do you get the google maps distance calculation?
Sorry Typo. I mean Google Map distance.
How did you get the exact coordinates of the points for the distance measurement in Google Maps? As far as I can see you can only more-or-less click somewhere, so those inaccuracies of up to 50 cm are to be expected.
Hi,
We are trying to get location within 50 meters from given ‘Point’. I have two points from Google Map and stored this two points in STA LOCATION table. Distance between 2 points is 101.23 meter.
Point 1 : Dolce&Gabbana - 103.831709,1.304389 (longitude, latitude)
Point 2 : Sephora - 103.832342,1.30373 (longitude, latitude)
STA LOCATION Table data
SRID projection:
Issue : I expect below API call return back location “Sephora” but its return empty JSON.
Request : http://localhost:8080/SensorThingsService/v1.0/Locations?$filter=geo.distance(location,geography'POINT(103.831709 1.304389)') gt 50
Response : { "@iot.count": 0, "value": [] }
What is the unit of geo.distance filter result? Is SensorThing API has any functions to get geo distance in meters?