PostGIS обнаруживает пересечение с отметкой времени - PullRequest
1 голос
/ 23 октября 2019

Мне нужно сохранить в базе данных серию точек GPS с временными метками (следы различных транспортных средств).

Сначала я хотел написать что-то самостоятельно, но это потребовало бы немного большей вычислительной мощности, чемпросто в результате одного запроса.

Я немного изучил и наткнулся на PostGIS, но я не уверен, подходит ли это или возможно решить эту проблему.

Идея состоит в том, чтобы проверить, проезжали ли два транспортных средства одновременно.

У меня есть таблица с координатами, каждая координата находится в отдельной строке, и каждая строка имеет временную метку, связанную с ней.

Таблица имеет следующую схему (vehicle_id, широта, долгота, временная метка).

Поэтому, учитывая несколько координат транспортных средств, мне нужно проверить, не пересекался ли он с другими транспортными средствами одновременно. Я обнаружил, что могу использовать ST_MakeLine для создания строки линии из последовательности точек GPS, и увидел, что существуют разные функции пересечения, но для этого необходимо, чтобы координаты соответствовали идеально, и здесь смещение может быть, скажем, 30 метров, а отметка времени должна быть

Любой ответ поможет.

Спасибо

1 Ответ

1 голос
/ 23 октября 2019

Если я правильно понял ваш вариант использования, я считаю, что вам не нужно создавать LineStrings, чтобы проверить, пересекается ли ваша траектория или приближается в определенный момент времени.

Образец данных:

CREATE TABLE t (vehicle_id INT, longitude NUMERIC, latitude NUMERIC, ts TIMESTAMP);

INSERT INTO t VALUES (1,1,1.1111,'2019-05-01 15:30:00'),
                     (1,1,2.1112,'2019-05-01 15:40:00'),
                     (1,1,3.1111,'2019-05-01 15:50:00'),

                     (2,2,2.1111,'2019-05-01 15:30:00'),
                     (2,1,2.1111,'2019-05-01 15:40:00'),
                     (2,1,4.1111,'2019-05-01 15:05:00');

Как видно из приведенных выше примеров данных, vehicle_id 1 и 2 расположены близко (менее 30 м) друг к другу на 2019-05-01 15:40:00, что можно найти с помощью запроса, подобного следующему:

SELECT 
  t1.vehicle_id,t2.vehicle_id,t1.ts, 
  ST_AsText(ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY) AS p1,
  ST_AsText(ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) AS p2,
  ST_Distance(
    ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY,
    ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) AS distance
FROM t t1, t t2
WHERE 
  t1.vehicle_id <> t2.vehicle_id AND
  t1.ts = t2.ts AND
  ST_Distance(
    ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY,
    ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) <= 30


 vehicle_id | vehicle_id |         ts          |       p1        |       p2        |  distance   
------------+------------+---------------------+-----------------+-----------------+-------------
          1 |          2 | 2019-05-01 15:40:00 | POINT(1 2.1112) | POINT(1 2.1111) | 11.05757826
          2 |          1 | 2019-05-01 15:40:00 | POINT(1 2.1111) | POINT(1 2.1112) | 11.05757826
(2 rows)

Как видите, результат в некотором роде дублируется, поскольку 1 близко к 2, а 2 близко к 1 одновременно. Вы можете исправить это, используя DISTINCT ON(), но, поскольку я не знаком с вашими данными, думаю, вам лучше настроить это самостоятельно.

Обратите внимание, что тип данных GEOGRAPHY, а не GEOMETRY. Это потому, что расстояния с ST_Distance по геометриям рассчитываются в градусах, а с использованием географии - в метрах.

РЕДАКТИРОВАТЬ: Чтобы ответить на вопрос, упомянутый в комментариях.

Чтобы избежать ненужных затрат при создании записей географии во время выполнения, вы можете захотеть уже сохранить координатыкак география. В этом случае таблица будет выглядеть следующим образом ..

CREATE TABLE t (vehicle_id INT, geom GEOGRAPHY, ts TIMESTAMP);

И вы можете заполнить ее следующим образом.

INSERT INTO t (vehicle_id, geom, ts) 
VALUES (1,ST_MakePoint(1,1.1111),'2019-05-01 15:30:00');

В случае, если вы хотите избежать повторного заполнения таблицы,Вы можете просто переместить данные в другой столбец и избавиться (если хотите) от широты и долготы:

ALTER TABLE t ADD COLUMN geom GEOGRAPHY;
UPDATE t SET geom = ST_MakePoint(longitude,latitude);
ALTER TABLE t DROP COLUMN longitude, DROP COLUMN latitude;
CREATE INDEX idx_point ON t USING GIST(geom);
SELECT vehicle_id,ts,ST_AsText(geom) FROM t;

 vehicle_id |         ts          |    st_astext    
------------+---------------------+-----------------
          1 | 2019-05-01 15:30:00 | POINT(1 1.1111)
          1 | 2019-05-01 15:40:00 | POINT(1 2.1112)
          1 | 2019-05-01 15:50:00 | POINT(1 3.1111)
          2 | 2019-05-01 15:30:00 | POINT(2 2.1111)
          2 | 2019-05-01 15:40:00 | POINT(1 2.1111)
          2 | 2019-05-01 15:05:00 | POINT(1 4.1111)
(6 rows)
...