Calculate distance between two points in QGIS field calculator - qgis

I'm more or less a beginner with QGIS, I've used version QGIS 3.10.
I would like to calculate distances (in meters or kilometers) of a number of points to one certain reference point. Is it possible to do this with the QGIS field calculator? The points are geometry points with latitude and longitude in WGS84.
The attribute table looks like:
Point_ID Latitude Longitude Distance_m
1 46.27789 9.87763
2 46.27366 9.87701
3 46.27565 9.88045
4 46.27600 9.87822
Point with ID #1 should be the reference point. The linear distance between point #1 to all the other points is my wished result.
I tried several versions like:
distance(geom_to_wkt($geometry ), geom_to_wkt(POINT('POINT_ID'='1')))
or
distance(geom_to_wkt($geometry ), geom_to_wkt(geometry(get_feature_by_id('Point_ID', '1'))))
while the first geometry includes all points listed in the attribute table and the second geometry is the reference point from which distances should be calculated.
but the result is always "NULL".
The distance matrix is not the aim as I get any distance of any point with it. The aim is a sub matrix of the distance matrix...

You are getting null because it can not find the reference point. You need to search by the layer name not the field name.
First you should project your points, otherwise you will get results in degrees not meters. Then you can calculate the distance:
distance(($geometry),geometry(get_feature_by_id('Layer Name', 1)))
Where "Layer Name" is the name of the layer in the Layers panel (a.k.a. table of contents).
In your question you are using WKT from longitude and latitude, this can be done from projected x and y values (e.g. UTM) like so:
distance( geom_from_wkt( 'POINT(' || "x_utm" || ' ' || "y_utm" || ')'), geom_from_wkt( 'POINT(' || attribute(get_feature_by_id('Layer Name', 1),'x_utm') || ' '|| attribute(get_feature_by_id('Layer Name', 1),'y_utm') || ')' ) )
If you need to you can do the transformations like this:
x(transform(( geom_from_wkt( 'POINT('||"lon"|| ' '|| "lat" || ')' ) ),'epsg:4326','epsg:code for your UTM zone'))
y(transform(( geom_from_wkt( 'POINT('||"lon"|| ' '|| "lat" || ')' ) ),'epsg:4326','epsg:code for your UTM zone'))
I have not found a way to get great circle distance in field calculator.

Related

Why is the distance between a point and a polygon 0 here?

I am using PostGIS, here is the SQL that I am using -
SELECT ST_Distance(
'SRID=4326;POINT(0 55)'::geography,
'SRID=4326;POLYGON((-180 45,-10 45,-10 -45,-180 -45,-180 45))'::geography
);
Visualizing these objects on a map suggests to me that the distance should be non-zero.

What is the area of geom field?

I want to check the area of geometry values.
The geometry values are POLYGON or POINT or MULTI POLYGON.
The field has the type of geometry
I check the srid of the geom field:
select st_srid(geometry)
from my_table
And I got srid=32636.
I checked here:
https://epsg.io/32636 and it seems that the units are in meters.
Now I want to get the area (in meters) of each value:
select st_area(geometry)
from my_table
And I'm getting very small values (0.0002, or 0.000097 or 0.33, ....).
I want to be sure:
Does those values means square meter (m^2) ?
So the values are less than 1 square meter ?
Since your SRS unit is metre, ST_Area will return the area in square metres. The following example calculates the area of a polygon using SRS's that have different units:
WITH j (geom) AS (
VALUES ('SRID=32636;
POLYGON((-1883435.029648588 6673769.700215263,-1883415.1158478875 6673776.142528819,-1883411.8478185558 6673765.073005969,-1883431.7724919873 6673758.967942359,-1883435.029648588 6673769.700215263))'::GEOMETRY))
SELECT
ST_Area(geom) AS sqm,
ST_Area(
ST_Transform(geom,2249)) AS sqft
FROM j;
sqm | sqft
-------------------+-------------------
237.6060612927441 | 2341.135411173445
EPSG 32636: Units are metres (Ellipsoid WGS84)
EPSG 2249: Units are feet (Ellipsoid GRS1980)
To your questions:
Does those values means square meter (m^2) ?
Yes.
So the values are less than 1 square meter ?
Yes. I'm curious about what are your geometries about. Perhaps you mixed up different SRS?
Unrelated note: Spatial operations with SRS's that have the same unit might still deliver different results, as they might also use different ellipsoids. The example below will calculate the area of the same geometry using SRS's that have metre as unit but a different ellipsoid. Note the difference in the result:
WITH j (geom) AS (
VALUES ('SRID=32636;
POLYGON((-1883435.029648588 6673769.700215263,-1883415.1158478875 6673776.142528819,-1883411.8478185558 6673765.073005969,-1883431.7724919873 6673758.967942359,-1883435.029648588 6673769.700215263))'::GEOMETRY))
SELECT
ST_Area(geom) AS sqm_32636,
ST_Area(
ST_Transform(geom,26986)) AS sqm_26986
FROM j;
sqm_32636 | sqm_26986
-------------------+--------------------
237.6060612927441 | 217.49946674261872
EPSG 32636: Units are metres (Ellipsoid WGS84)
EPSG 26986: Units are metres (Ellipsoid GRS1980)
.. but if you stick to the same ellipsoid and unit, the math makes more sense:
WITH j (geom) AS (
VALUES ('SRID=32636;
POLYGON((-1883435.029648588 6673769.700215263,-1883415.1158478875 6673776.142528819,-1883411.8478185558 6673765.073005969,-1883431.7724919873 6673758.967942359,-1883435.029648588 6673769.700215263))'::GEOMETRY))
SELECT
ST_Area(
ST_Transform(geom,2249)) AS sqft_2249,
ST_Area(
ST_Transform(geom,2249)) * 0.3048 ^ 2 AS sqm_2249, -- manually converted from sqm to sqft
ST_Area(
ST_Transform(geom,26986)) AS sqm_26986
FROM j;
sqft_2249 | sqm_2249 | sqm_26986
-------------------+--------------------+--------------------
2341.135411173445 | 217.49859674966302 | 217.49946674261872
Demo: db<>fiddle

ST_MinimumBoundingCircle ellpse instead of circle

I use postgis and I want to calculate minimum bounding circle for my geometry.
My points are:
I use ST_MinimumBoundingCircle function, but it shows the ellipse instead of a circle (see ).
The following sample is to reproduce:
select ST_Centroid(collection), ST_MinimumBoundingCircle(collection) from (
select ST_COLLECT(point) as collection from (
select ST_SetSRID(ST_MakePoint(20.513371, 54.720205),4326) as point
UNION ALL
select ST_SetSRID(ST_MakePoint(20.493725, 54.717761),4326) as point
UNION ALL
select ST_SetSRID(ST_MakePoint(20.495189, 54.726808),4326) as point
UNION ALL
select ST_SetSRID(ST_MakePoint(20.501414, 54.716445),4326) as point
UNION ALL
select ST_SetSRID(ST_MakePoint(20.509221, 54.719836),4326) as point
) a
)b
I could not understand what I did wrong.
You're not doing anything wrong. You might see the buffer as an ellipse because the points you used to create it are pretty far from the equator (Kaliningrad). Keep in mind that you're projecting an ellipsoid into a 2D flat structure, therefore such distortions are just normal.
WITH j (geom) AS (
VALUES
('SRID=4326;POINT(20.513371 54.720205)'),
('SRID=4326;POINT(20.493725 54.717761)'),
('SRID=4326;POINT(20.495189 54.726808)'),
('SRID=4326;POINT(20.501414 54.716445)'),
('SRID=4326;POINT(20.509221 54.719836)')
)
SELECT ST_MinimumBoundingCircle(ST_Collect(geom::geometry))
FROM j;
But if you draw a similar buffer closer to the equator the distortion won't be so visible. See example bellow (north of Brazil):
WITH j (geom) AS (
VALUES
('SRID=4326;POINT(-56.30 1.55)'),
('SRID=4326;POINT(-56.63 1.14)'),
('SRID=4326;POINT(-55.95 0.70)'),
('SRID=4326;POINT(-55.57 1.38)')
)
SELECT ST_MinimumBoundingCircle(ST_Collect(geom::geometry))
FROM j;
Further reading: Buffers (Circle) in PostGIS
In order to avoid the distortion, transform to a coordinate system that represents lenghts more correctly before creating the buffer.

How to check if polygon in one table intersect with point and radius from second table?

How can I check if polygon in one table intersect with point and radius from second table ?
first table we have field (name: area) ,type geometry which contains polygon.
second table we have 2 fields:
field (name: pt) ,type: geometry which contains point
field (name: radius) ,type: int
The geometry values in WKB format
I want to check if the polygon intersect with the circle (point + radius).
How can I do it ?
You can use the ST_Distance function to find the distance between the polygon and the point. If the distance between them is less than the radius, then the polygon would intersect with a circle around the point with that radius.
Example query:
SELECT *
FROM polygon_table, circle_table
WHERE ST_Distance(polygon_table.area, circle_table.pt) <= circle_table.radius;
Use ST_Contains to check if the point is inside of the polygon and then calculate the buffer around your point and see if they intersect, with ST_Buffer and ST_Intersects respectively. Something like:
SELECT *
FROM polygon_table t1, circle_table t2
WHERE
ST_Contains(t1.area, t2.pt) AND
ST_Intersects(ST_Buffer(t2.pt,t2.radius),t1.area)
Note: the buffer will be created using the unit of your SRS. For instance, if you're using WGS84 it will be in degrees. If you want it in metres instead, use geography instead of geometry or simply cast it in real time, e.g. t1.area::geography.

Two closest points on boundary of Postgis geometry

I have a table geofences which stores geometry of polygon.
I also have a point A which is inside the geometry. What I have to do is find the two closest points from point A that lie on the surface of the polygon geometry.
Function in PostGIS:
CREATE OR REPLACE FUNCTION accuracyCheck(Polygon geometry
,decimal lat
,decimal lon)
RETURNS VARCHAR AS
$BODY$
DECLARE height DECIMAL;
DECLARE accuracy VARCHAR(250);
BEGIN
CREATE TEMPORARY TABLE closePointStorage AS
SELECT ST_AsText(ST_ClosestPoint(geometry
,ST_GeomFromText('POINT(lat lon)',0)
)
) AS closestPoint
FROM (
SELECT ST_GeomFromText(geometry) as geometry
FROM gfe_geofences
WHERE is_active=true
) As tempName;
CREATE TEMPORARY TABLE areaStorage ON COMMIT DROP AS
SELECT ST_Area(ST_GeomFromText('Polygon((23.0808622876029 96.1304006624291
,28.0808622876029 99.1304006624291
,100 200
,23.0808622876029 96.1304006624291
))'
,0)
) AS area;
CREATE TEMPORARY TABLE distanceStorage ON COMMIT DROP AS
SELECT ST_Distance(
ST_GeomFromText('POINT(23.0808622876029 96.1304006624291)',-1)
,ST_GeomFromText('POINT(28.0808622876029 99.1304006624291)',-1)
) AS distance;
height = (SELECT area FROM areaStorage)
/(0.5*(SELECT distance FROM distanceStorage));
IF height < (SELECT radius_meters
FROM gfe_geofences Where is_active=true) THEN
accuracy = "FullConfirm";
RETURN accuracy;
ELSE
accuracy = "PartiallyConfirm";
RETURN accuracy;
END IF;
END;
$BODY$ LANGUAGE plpgsql;
I just want to find two points on boundary of polygon geometry. Just like I have found one from the query:
CREATE TEMPORARY TABLE closePointStorage AS
SELECT ST_AsText(ST_ClosestPoint(geometry
,ST_GeomFromText('POINT(lat lon)',0)
)
) AS closestPoint
FROM (
SELECT ST_GeomFromText(geometry) as geometry
FROM gfe_geofences
WHERE is_active=true
)
AS tempName;
Other then this point I have to find one more with distance greater then the point find above but smaller then the rest of points.
Use ST_DumpPoints() to dump the points of the polygon, then select from that order by ST_Distance to A limit 2. ?
So it is something like
SELECT * from ST_DumpPoints(poly) order by ST_Distance(A,geom) asc limit 2;
(assumes that this is an inner select where poly is the polygon, A is the point to compare to and geom is the geom column of one of the points in the poly being compared)
There generally is no second closest point on the boundary polygon, if you include the lines. Just like there is no real number second closest to zero.
Either you only wish to consider the points at the corners, like Markus suggests.
Or you have only one closest point.
1) Kind of a left-field idea, but to find the second-closest point to your destination, why not find the closest point to the point you already found?
2) Or, more germaine to your specific question,
find the set of points within some reasonable range of the point,
find the intersection of that set with the set of points lying on the polygon border (which I am guessing may be another PostGIS function; haven't used postG in a while so I'm not sure)
3) Farther into left field, dump some of your dataset into Mongo and use the $near function... http://docs.mongodb.org/manual/reference/operator/near/
I am assuming you want to find the edge of the polygon that passes the closest to the point in question
To obtain the distance 'd' of point 'C' from line [A,B]
First translate all points so A is at 0,0
B -= A //vector subtraction
C -= A
Then normalize B so it is of length 1.0
len = sqrt( B . B) //dotproduct of two vectors is the length squared
B /= len //scalar divide by length
Find length from A that is at right angles to C
dotp = B . C //dot product again
closestPointOnLine = B * dotp //scalar multiply
Now get the distance
diff = (C - ClosestPointOnLine)
d = sqrt(diff . diff)
Not sure how to do that in SQL. You will need to do the above for each edge on your polygon, and then find the smallest value 'd'
By the way the sign of the cross-product of B and C will now tell you whether the point is on the inside of the polygon or not