Get Distance in Meters instead of degrees in Spatialite - sql

I have the following query:
select distance(GeomFromText('POINT(8 49)',4326),GeomFromText('LINESTRING(8.329969 49.919323,8.330181 49.919468)',4326))
this gives me 0.97 degrees. But I need it in meters and do not know which SRID to transform to.
Can somebody give me an example how to get the result in meters for spatialite?
The positions are all in Europe.

Just multiply the value in degrees by 111195 - this value is (Earth mean radius)*PI/180 - that is 'mean length of one great circle degree in meters on Earth's surface'.
The result obtained using this method is within 1% of the geodesic distance for the WGS84 ellipsoid.
EDIT
OK, my answer above still stands for the question: "how to convert arcs in degrees into lengths in meters", however, it's not the question you asked (should have asked).
I haven't used Spatialite professionally, so I assumed that your sample query indeed returns the 'length in degrees'. That's not true.
Unfortunately, it appears that Spatialite fails to calculate the distance in 'geographic sense'. Despite your geometries are defined with SRID 4326, it treats them as if they were on a plane.
Here's a simple proof:
select Distance(GeomFromText('POINT(0 0)',4326),GeomFromText('POINT(3 4)',4326));
returns 5.0.
It's a shame ...
Lets have a look at your original query:
select Distance(
GeomFromText('POINT(8 49)',4326),
GeomFromText('LINESTRING(8.329969 49.919323,8.330181 49.919468)',4326)
)
An equivalent query in MS SQL Server:
SELECT (geography::STGeomFromText('POINT(8 49)', 4326)).STDistance(geography::STGeomFromText('LINESTRING(8.329969 49.919323,8.330181 49.919468)', 4326));
gets you the correct result immediately: 105006.59673084648, in meters, and without any extra brouhaha.
So what are your options with Spatialite?
Indeed, as you said in comments, one option is to project your geometries, and calculate on those. Using SRID 3035 for Europe makes sense, too (if your locations are mostly in Germany, I'd consider SRID 25832).
select Distance(
Transform(GeomFromText('POINT(8 49)',4326),25832),
Transform(GeomFromText('LINESTRING(8.329969 49.919323,8.330181 49.919468)',4326),25832)
)
returns 104969.401605453.
As to your other sample (in comments):
select distance(
Transform(GeomFromText('POINT(8.328957 49.920900)',4326),3035),
Transform(GeomFromText('POINT(8.339665 49.918000)',4326),3035)
)
There's a simpler way to do it (if you have two POINTs, not a POINT and a LINESTRING): create a LINESTRING with your POINTs and use GeodesicLength function, like this:
select GeodesicLength(GeomFromText('LINESTRING(8.328957 49.920900, 8.339665 49.918000)',4326))
It returns 833.910006698673, as expected.

In SpatiaLite's functions reference guide, you can see there are two version of the Distance() function. One takes only two arguments and return the distance in CRS units, the other takes 3 arguments and return the distance in meters.
To get the distance in meters, simply pass a third argument to Distance:
sqlite> select Distance(MakePoint(0, 0), MakePoint(3, 4));
5.0
sqlite> select Distance(MakePoint(0, 0), MakePoint(3, 4), 1);
554058.923752633

Related

Find records by given latitude and longitude which intersects and circle within 2 mile radius using PostGIS?

I have a Postgres table with some data created by using a shapefile. I need to find all records which intersect within 2 miles radius from a given latitude and longitude. I used some queries including the following one.
SELECT * FROM us_census_zcta WHERE ST_INTERSECTS(geom,
CIRCLE(POINT(40.730610, -73.935242), 2));
But none of them worked. What I am doing wrong here? How can I get the results I need?
The SRID is 4269 (NAD 83).
EDIT: After Mike Organek pointed me out that I have switched the lat-long in the above query. And then I tried a few things and the following query gave me 1 record.
SELECT * FROM us_census_zcta WHERE ST_INTERSECTS(geom::geometry,
ST_SETSRID(ST_POINT(-73.935242, 40.730610), 4269)::geometry);
But how can I use Circle and find records which intersect within 2 miles radius from that given lat-long?
What you're looking for is ST_DWithin, which will check if records intersect within a given buffer. In order to use it with miles you better cast the geometry column to geography, as it then computes distances in metres:
For geography: units are in meters and distance measurement defaults to use_spheroid=true. For faster evaluation use use_spheroid=false to measure on the sphere.
SELECT * FROM us_census_zcta
WHERE
ST_DWithin(
geom::geography,
ST_SetSRID(ST_MakePoint(-73.935242, 40.730610), 4269)::geography,
3218.688); -- ~2 miles
Keep in mind that this cast might affect query performance if the indexes aren't set properly.
See also: Getting all Buildings in range of 5 miles from specified coordinates

How to get longitude and latitude for a place within certain distance from a known longitude and latitude

I want to find a place (longitude and latitude) with distance less than 10 km from a known longitude and latitude using BigQuery SQL. Is there any possible query for this?
I read your request as saying that given a geospatial point, you wish to query for anything within less than a 10km radius of that point. Here's two ways to solve this:
Using ST_BUFFER
You could use the ST_BUFFER function which similarly takes an argument of the radius to use around a point, but instead uses a segmented circle with 8 segments by default.
SELECT *
FROM `table`
WHERE ST_CONTAINS(
ST_BUFFER(
ST_GEOPOINT(longitude, latitude),
10 * 1000), -- Radius argument is expressed in meters
YourGeoPointColumn)
Using ST_BUFFERWITHTOLERANCE
You might use ST_BUFFERWITHTOLERANCE that replaces the segmented circle with tolerance instead of circle segments.
SELECT *
FROM `table`
WHERE ST_CONTAINS(
ST_BUFFERWITHTOLERANCE(
ST_GEOPOINT(longitude, latitude),
10 * 1000, -- Radius argument is expressed in meters
1), -- Tolerance of 1% of the buffer radius, expressed in meters
YourGeoPointColumn)
ST_Distance function should work here, like this:
with data as (
select 1 id, st_geogpoint(-122, 47) as geo
union all
select 2 id, st_geogpoint(-121, 47) as geo
)
select * from data
where st_distance(geo, st_geogpoint(-122.1, 47)) < 10000
id geo
------------------
1 POINT(-122 47)
Another way to write the distance condition is
ST_DWithin(geo, st_geogpoint(-122.1, 47), 10000)
If something does not work, please provide sample data and what data you expect in the results but is missing.

How can I return all the rows in a PostgreSQL/PostGIS table within a radius of Xkm provided by a longitude and latitude value?

I'm trying to have a go at learning about PostgreSQL and in particular, it's PostGIS extension and the benefits with regards to geographic spatial features it provides. I've loaded a PostgreSQL DB with a table that contains 30,000 records of latitude, longitude and a price value (for houses) and I want to start querying the DB to return all the rows that would be in a radius of Xkm of a particular latitude and longitude.
I've hit a brick wall as to how I might run this type of query as I've found the documentation to be quite limited online and I've found no similar attempts at this method of querying online.
Some methods I've tried:
SELECT *
FROM house_prices
WHERE ST_DWithin( ST_MakePoint(53.3348279,-6.269547099999954)) <= radius_mi *
1609.34;
This prompts the following error:
ERROR: function st_dwithin(geometry) does not exist
Another attempt:
SELECT * FROM house_prices ST_DWithin( 53.3348279, -6.269547099999954, 5); <-- A latitude value, longitude value and 5 miles radius
This prompts the following error:
ERROR: syntax error at or near "53.3348279"
Could anyone point me in the right direction/ know of some documentation I could look at?
** Edit **
Structure and set up of database and table in pgAdmin4
The first query has an invalid number of parameters. The function ST_DWithin expects at least two geometries and the srid distance,
and optionally a Boolean parameter indicating the usage of a spheroid (see documentation).
The second query is missing a WHERE clause and has the same problem as the first query.
Example from documentation:
SELECT s.gid, s.school_name
FROM schools s
LEFT JOIN hospitals h ON ST_DWithin(s.the_geom, h.the_geom, 3000)
WHERE h.gid IS NULL;
Perhaps something like this would be what you want to achieve:
SELECT *
FROM house_prices h
WHERE ST_DWithin(ST_MakePoint(53.3348,-6.2695),h.geom,h.radius_mi * 1609.34)
Also pay attention to the order of the coordinates pair (x,y or y,x), otherwise you might easily land on the sea with these coordinates ;-)
EDIT: Taking into account that there is no geometry on the table, so the points are stored in two different columns, longitude and latitude:
SELECT *
FROM house_prices
WHERE ST_DWithin(ST_MakePoint(longitude,latitude),ST_MakePoint(53.3348,-6.2695),1609.34)

Use sql to find out if the radius of one point intersects the radius of another point

I've got locations stored in the database(SQL-server), their location is declared as geography and another column declaring it's radius.
Giving a geography(or longitude/latitude) as parameter I would like to get the locations with a radius intersecting the parameters radius (a constant value) in return.
Any information on how to solve this is appreciated.
First note that the radii intercept each other if and only if the sum of the radii is greater than the distance between the two points.
I'm not that familiar with the syntax but you want something like this - I'm making use of the STDistance function of the Transact SQL geography data type.
SELECT * FROM TABLE
WHERE TABLE.RADIUS + #radius >= #geog.STDistance(TABLE.GEOGRAPHY);

Incorrect Distances When Comparing geography values in SQL

I have a SQL database set up containing a number of fields one of which is a geography field called Coordinates. I have a need to search for all rows that are within a certain radius and to do that I am using the query
DECLARE #CurrentLocation geography;
SET #CurrentLocation = geography::Point(-84.505562, 39.137706, 4326)
SELECT * , Coordinates.STDistance(#CurrentLocation) AS Distance FROM tParkingLot
WHERE Coordinates.STDistance(#CurrentLocation )<= 200000
which gives me the following results
the first row is returning as expected as I used those coordinates as my center. However, when measuring the other two lots on google maps I find that the results should be closer to 1133.246 for row 2 and 74673.56 for row 3
I can see from other stackoverflow results that a common mistake is to insert data as lat/lon as opposed to lon/lat however I have already made and corrected that mistake and I cannot determine why I am getting distance results that are so far off from the actual measurements.
The cause of the problem is the order of latitude and longitude. Geography world traditionally uses (lat, lon) order, SQL world defined (x, y) order, which usually means (lon, lat) order.
Microsoft SQL Server Point constructor made confusing compromise: they use (x, y) order for Geometry, but (lat, lon) order for Geography:
Point ( Lat, Long, SRID ) [1]
Since your points are in Cincinnati rather than Antartica, swap argument order.
[1] https://learn.microsoft.com/en-us/sql/t-sql/spatial-geography/point-geography-data-type?view=sql-server-2017