Skip to content

Conversation

@tyrauber
Copy link
Contributor

Point already accepts a time property. Waypoint and Trackpoint, currently only supply lon, lat, and elevation. This PR adds point[3] as the time param. This enables this library to import geojson with points that contain lon,lat,elevation and time, and will now work with RGeo::Cartesian.factor has_m_coordinate: true.

Additional Background:

You can extend GPX to patch to_geom:

module GPX
  class GPXFile < Base

    def to_geom
      factory = RGeo::Cartesian.factory(srid: 4326, has_z_coordinate: true, has_m_coordinate: true)
      if !self.tracks.empty?
        factory.collection(self.tracks.map do |track|
         factory.multi_line_string(track.segments.map do |segment|
            factory.line_string(
              segment.points.map do |point|
                factory.point(point.lon, point.lat, point.elevation.to_f, point.time.to_i)
              end
            )
          end)
        end)
      elsif !self.routes.empty?
        factory.multi_line_string(self.routes.map do |route|
          factory.line_string(
            route.points.map do |point|
              factory.point(point.lon, point.lat, point.elevation.to_f, point.time.to_i)
            end)
        end)
      end
    end
 end

This change makes it so you can import geojson structured with elevation and time and import it into a GeometryZM column:

# Ruby initialize method
 @gpx = GPX::GeoJSON.convert_to_gpx(geojson_data: options[:geojson])
 self.geom = @gpx.to_geom

You might need to alter the geom column from GeometryZ to GeometryZM:

ALTER TABLE gpx_tracks ALTER COLUMN geom TYPE geometry(GeometryZM, 4326) USING ST_Force4D(geom);

You can now create a method to extract total duration:

   CREATE OR REPLACE FUNCTION ST_Geom_Duration(geom geometry)
     RETURNS DOUBLE PRECISION AS $$
     DECLARE
         linestrings geometry[];
         line geometry;
         min_m DOUBLE PRECISION;
         max_m DOUBLE PRECISION;
         total_duration DOUBLE PRECISION := 0;
         i INT;
     BEGIN
         -- Extract all linestrings from the geometry collection
         linestrings := array(
             SELECT ST_GeometryN(geom, generate_series(1, ST_NumGeometries(geom)))
         );
     
         -- Loop through each linestring
         FOR i IN 1 .. array_length(linestrings, 1) LOOP
             line := linestrings[i];
     
             -- Extract the minimum M value from the linestring
             SELECT MIN(ST_M((dp).geom))
             INTO min_m
             FROM (
                 SELECT ST_DumpPoints(line) AS dp
             ) AS points;
     
             -- Extract the maximum M value from the linestring
             SELECT MAX(ST_M((dp).geom))
             INTO max_m
             FROM (
                 SELECT ST_DumpPoints(line) AS dp
             ) AS points;
     
             -- Add the duration of the current linestring to the total duration
             total_duration := total_duration + (max_m - min_m);
         END LOOP;
     
         -- Convert the total duration from milliseconds to seconds and return
         RETURN total_duration / 1000;
     END;
     $$ LANGUAGE plpgsql;

I doubt anyone else needs to do this, but I did, so I thought I'd share.

Point already accepts a time property. Waypoint and Trackpoint, currently only supply lon, lat, and elevation. This PR adds point[3] as the time param. This should hopefully enable it to work with RGeo::Cartesian.factor has_m_coordinate: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant