store array of 3d points in postgresql - postgresql

I have to store logical 3d coordiantes of object in postgres database. Each object typicaly has from 50-1000 points and probably never exceed 10000.
My intension is to use column of type real [][] in postgres.
I looked also postGis extension and wonder if it is suitable solution, but could not answer myself of several questions:
Which spatial reference should i use - only need logical coordinates x,y,z could i specify left or right coordinate system - this is the part that mostly confuses me?
2.How should orgnaize data - line geometry seems natural way to me?
Would be posible to find distance between two points in the array (line geometry)?

It would be natural to use the PostGIS geometry(pointz)[] as data type, an array of three-dimensional points.
Here is an example that shows a constant of that type and calculates the distance between the points:
WITH x(p) AS (
SELECT '{POINT Z (1 2 3):POINT Z (3 0 2)}'::geometry(pointz)[]
)
SELECT st_3ddistance(p[1], p[2]) FROM x;
st_3ddistance
---------------
3
(1 row)

Related

Postgres: How to calculate distance for a set of geography points?

I'm using Postgres v13.
I couldn't find a clear example of how to achieve this basic calculation. I'm totally confused about how to handle geometry and geography points.
I have a table that stores points in the format geography(Point, 4326) alongside their timestamp.
I need to obtain the total distance in meters between timestamps A and B, and I need it to be super specific using spherical calculations. To be clear, there may be N points.
So far I've been using this query, but the distance is way off for long distances and I don't understand if there is any difference in creating a line using geometry points or geography points:
SELECT ST_Length(ST_MakeLine(lh.position::geometry order by report_time), TRUE)
FROM location_history AS lh
WHERE lh.device_id = 1
AND lh.report_time BETWEEN '2022-10-10T13:25:00.000Z' AND '2022-10-11T13:25:00.000Z'
GROUP BY lh.device_id;
Does this query make sense? ST_MakeLine only accepts geometry points and confuses me. Is there another way of creating a line with geography points?
ST_Distance is used in every example I could find, but it just compares 2 points!
Thanks!

Geo Spatial Analysis in Pyspark ( Point in a Polygon)

I have a use case where Im given 4 geo spatial Point sets that represents 4 rectangles . I have a table which has a point( which is just a latitude and longitude ) . My task is to check if the point in the table lies within any of the four rectangles.
This should be done in Pyspark . I tried this using udf's but its taking a long time as the main table contains lot of rows. Could anyone help me on how to efficiently solve this problem in Pyspark.
Right now I have used Shapely to help me with Point and Polygon creations
We can think of the rectangle as space bounded by (min_latitude, max_latitude) and (min_longitude, max_longitude). Let's assume your point-of-interest is x = (lat, lon). Now, for each rectangle you need to check whether min_latitude <=x <= max_latitude and min_longitude <= y <= max_longitude. These can be done using native spark functions, no udf is required. Also, before performing these operations, you can select only required columns (dataframe.select(cols...)) from your original dataframe to discard redundant information.

How to configure PostgreSQL with Postgis to calculate distances

I know that it might be dumb question, but I'm searching for some time and can't find proper answer.
I have PostgreSQL database with PostGIS installed. In one table I have entries with lon lat (let's assume that columns are place, lon, lat).
What should I add to this table or/and what procedure I can use, to be able to count distance between those places in meters.
I've read that it is necessary to know SRID of a place to be able to count distance. Is it possible to not know/use it and still be able to count distance in meters basing only on lon lat?
Short answer:
Just convert your x,y values on the fly using ST_MakePoint (mind the overhead!) and calculate the distance from a given point, the default SRS will be WGS84:
SELECT ST_Distance(ST_MakePoint(lon,lat)::GEOGRAPHY,
ST_MakePoint(23.73,37.99)::GEOGRAPHY) FROM places;
Using GEOGRAPHY you will get the result in meters, while using GEOMETRY will give it in degrees. Of course, knowing the SRS of coordinate pairs is imperative for calculating distances, but if you have control of the data quality and the coordinates are consistent (in this case, omitting the SRS), there is not much to worry about. It will start getting tricky if you're planing to perform operations using external data, from which you're also unaware of the SRS and it might differ from yours.
Long answer:
Well, if you're using PostGIS you shouldn't be using x,y in separated columns in the first place. You can easily add a geometry / geography column doing something like this.
This is your table ...
CREATE TABLE places (place TEXT, lon NUMERIC, lat NUMERIC);
Containing the following data ..
INSERT INTO places VALUES ('Budva',18.84,42.92),
('Ohrid',20.80,41.14);
Here is how you add a geography type column:
ALTER TABLE places ADD COLUMN geo GEOGRAPHY;
Once your column is added, this is how you convert your coordinates to geography / geometry and update your table:
UPDATE places SET geo = ST_MakePoint(lon,lat);
To compute the distance you just need to use the function ST_Distance, as follows (distance in meters):
SELECT ST_Distance(geo,ST_MakePoint(23.73,37.99)) FROM places;
st_distance
-----------------
686560.16822422
430876.07368955
(2 Zeilen)
If you have your location parameter in WKT, you can also use:
SELECT ST_Distance(geo,'POINT(23.73 37.99)') FROM places;
st_distance
-----------------
686560.16822422
430876.07368955
(2 Zeilen)

Simple PostGIS XYZ set up?

I am new to PostGIS. I am looking to have a simple bounded (-200 < x, y, z < 200) data set of 1,000,000 points on a plain XYZ graph. The only query I need is a fast K nearest neighbors and all neighbors such that the distance is less than < N. It seems that PostGIS has a LOT of extra features that I do not need.
What do SRID do I need? One that does not concern with feet or meters.
Am I right that I need to use the function
ST_3DDistance to query for the K nearest neighbors with LIMIT K? or with a maximum distance of N.
To add a column, I need to use SELECT AddGeometryColumn ('my_schema','my_spatial_table','geom_c',4326,'POINT',3, false);. Is that correct?
What is the difference between a 3D point and a PointZ?
Will AddGeometryColumn ensure that my distance query is fast?
Is PostGIS the right choice for my use case? The rest of my DB is already integrated with PostgreSQL
Thanks!
What do SRID do I need? One that does not concern with feet or meters.
You don't "need" a srid. If your data is a in a coordinate system, find the right srid, otherwise, use 0.
Am I right that I need to use the function ST_3DDistance to query for the K nearest neighbors with LIMIT K? or with a maximum distance of N.
Yes, you're right.
To add a column, I need to use SELECT AddGeometryColumn ('my_schema','my_spatial_table','geom_c',4326,'POINT',3, false);. Is that correct?
Yes, but I'd use 0 for srid, instead of 4326 (that is for degrees).
What is the difference between a 3D point and a PointZ?
PointZ is a 3d Point.
Will AddGeometryColumn ensure that my distance query is fast?
AddGeometryColumn will just add some constraints to the table, ensuring that the geometries you insert are coherent with the column definition.
I don't think you need it, but you could try adding an index to your geometry column using CREATE INDEX index_name ON schema.table USING gist (geom_col);
Is PostGIS the right choice for my use case? The rest of my DB is already integrated with PostgreSQL
I think it is the easiest way, not necessarly the "right" one.
You could also implement a distance function without postgis, storing the three coordinates in three numeric fields.

postgis: point returned in ST_LineLocatePoint not able to detect in ST_Contains

I am using postgis's ST_LineLocatePoint to find out the closest point on a LineString to the given Point, and using ST_LineInterpolatePoint to extract a Point from the returned float number.
ST_LineLocatePoint Query:
SELECT ST_AsText(ST_LineInterpolatePoint(foo.the_line,
ST_LineLocatePoint(foo.the_line,
ST_GeomFromText('POINT(12.962315 77.584841)')))) AS g
FROM (
SELECT ST_GeomFromText('LINESTRING(12.96145 77.58408,12.96219 77.58447,12.96302 77.58489,
12.96316 77.58496,12.96348 77.58511)') AS the_line
) AS foo;
Output:
g
------------------------------------------
POINT(12.9624389808159 77.5845959902924)
Which exactly lies on the linestring I have passed. Demonstration is displayed here.
But when I check whether this point lies in the linestring using ST_Contains it always return false, even though the point lies within.
ST_Contains Query:
SELECT ST_Contains(ST_GeomFromText('LINESTRING(12.96145 77.58408,12.96219 77.58447,
12.96302 77.58489, 12.96316 77.58496, 12.96348 77.58511)'),
ST_GeomFromText('POINT(12.9624389808159 77.5845959902924)'));
Output
st_contains
-------------
f
I am not getting where I am doing wrong. Can anyone help me in this.
Postgresql : 9.4
postgis : 2.1
reference: ST_LineLocatePoint, ST_Contains
I am not getting where I am doing wrong.
I think you're doing good... I had the same issue some time ago... I used ST_ClosestPoint to locate point on linestring and then cut a linestring with this point, but I can't.
Following the documentation:
ST_ClosestPoint — Returns the 2-dimensional point on g1 that is
closest to g2. This is the first point of the shortest line.
So I get situation where one function says - this point is on a line, and other functions says - ok, but I can't cut cause your point is not on a line... I was confused like you're now...
In my case resolution was to draw another line which will intersect first line 'exactly' in given point and after that first line was cutted...
After some research I found issue was about rounding of coordinates counted and writen. I explain it to myself that, according to the definitions line is infinitely thin and point is infinitely small (they do not have the area), so they can easily miss each other - but it's my reasoning and I'm not sure whether it is good. I advice you to use st_intersects, but with very low st_buffer or ST_DWithin function also with very low distance.
To be sure that your point lies on a line it have to be a part of this line (e.g. LINESTRING(0 0, 5 5) points (0 0) and (5 5). Example with point(3 3) works because it's coordinates are counted without any roundings.
This is actually a really common question (most likely a duplicate, but I'm too lazy to find it.)
The issue is related to numerical precision, where the Point is not exactly on the LineString, but is within a very small distance of it. Sort of like how SELECT sin(pi()) is not exactly zero.
Rather than using DE-9IM spatial predicates (like Contains, or Covers, etc.) which normally expect exact noding, it is more robust to use distance-based techniques like ST_DWithin with a small distance threshold. For example:
SELECT ST_Distance(the_point, the_line),
ST_Covers(the_point, the_line),
ST_DWithin(the_point, the_line, 1e-10)
FROM (
SELECT 'POINT(12.9624389808159 77.5845959902924)'::geometry AS the_point,
'LINESTRING(12.96145 77.58408,12.96219 77.58447,12.96302 77.58489,12.96316 77.58496,12.96348 77.58511)'::geometry AS the_line
) AS foo;
-[ RECORD 1 ]----------------------
st_distance | 1.58882185807825e-014
st_covers | f
st_dwithin | t
Here you can see that ST_DWithin indicates that the point is within a very small distance of the line, so it effectively contains the point.
ST_Contains() only returns true if the geometry to test lies within the supplied geometry. In your case the point has to lie within the linestring and this is always false since a linestring does not have an interior.
You should use the ST_Covers() function instead: true if no point of the geometry to test (your point) lies outside the supplied geometry (your linestring).