PostGIS - Berechnet den progressiven Abstand zwischen Punkten auf einem GPX-Pfad

8

Ich versuche, ein Höhenprofil nur mit PostGIS-PostgreSQL zu erstellen. Ich habe GPX-Daten in meine PostGis-Datenbank importiert, daher habe ich jetzt eine Tabelle mit den GPS-Koordinaten der Spur und dem Zeitstempel jedes einzelnen GPS-Punkts der Spur. Jetzt möchte ich eine zweite Tabelle erstellen, die in einer einzigen Zeile Folgendes enthält:

  1. die Track-ID
  2. Ein Array von Floats, die den inkrementellen Abstand vom Startpunkt darstellen
  3. Ein Array von Floats, die die inkrementelle Zeit vom Startpunkt aus darstellen

Ist es möglich, dies in einer einzelnen gespeicherten SQL-Prozedur zu tun?

Vielen Dank,

Andrea

Andrea Cremaschi
quelle

Antworten:

8

Hier ist ein Anfang (nicht wirklich getestet ...) Erste zwei Annahmen:

  • Ich denke, Ihre Track-Tabelle ist eine räumliche PostGIS-Tabelle mit einer Geom-Spalte. (Wenn nicht, müssen Sie SELECT AddGeometryColumn (...) ausführen, um es mit den Lon / Lat-Werten einzurichten.)
  • Wenn Sie "inkrementelle Entfernung" sagen, gehe ich davon aus, dass Sie die akkumulierte Entfernung meinen?

Ich habe zwei Testtabellen erstellt: Spuren für die Punkte und Akkumulation für die akkumulierten Entfernungen und Zeiten

geodata=# \d ms.tracks
                                        Table "ms.tracks"
    Column    |            Type             |                      Modifiers                      
--------------+-----------------------------+-----------------------------------------------------
 pk           | integer                     | not null default nextval('tracks_pk_seq'::regclass)
 trk_id       | integer                     | 
 lon          | double precision            | 
 lat          | double precision            | 
 geom         | geometry                    | 
 gps_timestmp | timestamp without time zone | 
Indexes:
    "tracks_pkey" PRIMARY KEY, btree (pk)
Check constraints:
    "enforce_dims_geom" CHECK (st_ndims(geom) = 2)
    "enforce_geotype_geom" CHECK (geometrytype(geom) = 'POINT'::text OR geom IS NULL)
    "enforce_srid_geom" CHECK (st_srid(geom) = 4326)

und

geodata=# \d accum
              Table "ms.accum"
   Column   |        Type        | Modifiers 
------------+--------------------+-----------
 trk_id     | integer            | 
 accum_dist | double precision[] | 
 accum_time | double precision[] | 

Hier ist ein grober Entwurf einer Funktion, die Entfernungen und Zeiten akkumuliert und die Werte in Arrays in der Akkumulationstabelle platziert. Diese Funktion wird mit der Parameter trk_id aufgerufen.

CREATE OR REPLACE FUNCTION public.calculate_accumulated_track(IN t_id integer) RETURNS void AS
$BODY$
DECLARE
i integer;
-- first date/time in the track
dt1 timestamp;
-- the date/time of following track points
dt2 timestamp;
num_rows integer;
-- first_row will be the primary key of the 
-- first track point for the track id passed into the function
first_row integer := 1;
-- Accumulated distance and time, to be inserted into accum table
segment float :=0;
accum_t float;
accum_d float;

BEGIN
    -- Initialize a row in the accum table
    INSERT INTO accum VALUES (t_id, NULL, NULL);
    -- Get the primary key of the first row for this track id.
    SELECT pk INTO first_row FROM tracks WHERE trk_id=t_id ORDER BY pk LIMIT 1;
    SELECT count(*) INTO num_rows FROM tracks WHERE trk_id=t_id;
    SELECT gps_timestmp INTO dt1 FROM tracks WHERE trk_id=t_id ORDER BY gps_timestmp LIMIT 1;

    FOR i in 1..num_rows LOOP
        SELECT gps_timestmp INTO dt2 FROM tracks WHERE pk=i+first_row;
        accum_t := dt2 - dt1;
        IF pk==1 THEN
accum_d:=0;
ELSE
SELECT ST_Distance(t1.geom, t2.geom) INTO segment 
                FROM tracks t1, tracks t2
                WHERE t1.pk=i+first_row-1 AND t2.pk=i+first_row;
END IF;
accum_t := accum_d+segment;     


    -- Now UPDATE the accum table
     UPDATE accum SET accum_time[i]=accum_t WHERE trk_id=t_id;
     UPDATE accum SET accum_dist[i]=accum_d WHERE trk_id=t_id;
    END LOOP;

END;$BODY$
LANGUAGE plpgsql VOLATILE;
ALTER FUNCTION public.calculate_accumulated_track(IN integer) OWNER TO geodba;

Vielleicht hilft Ihnen das beim Einstieg.

Prost, Micha

Micha
quelle
Das ist es! Vielen Dank für die Antwort, genau das habe ich versucht zu erreichen.
Andrea Cremaschi
1
Wenn ich die Funktion ein zweites Mal betrachte, sehe ich, dass accum_d oben die kartesische Entfernung zwischen einem Punkt auf der Spur und dem ersten Punkt ist. Das wollten Sie nicht. Vielmehr benötigen Sie die Entfernung entlang der Strecke . Also habe ich eine Variable "Segment" hinzugefügt und die Berechnung von accum_d geändert, um die akkumulierte Entfernung unter Verwendung jedes Spursegments widerzuspiegeln. Guck mal.
Micha
Ja, tatsächlich war das mit "progressiver" Distanz gemeint. Nochmals vielen Dank!
Andrea Cremaschi