Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have GPS data I've taken of bus routes, and now I'd like to snap it to my road network. Both layers are line layers in a PostGIS DB. I'd like to use either QGIS or PostGIS, but if I have to go with GRASS or ArcMap, that's OK, too. Thanks!

To clarify, I'm trying to snap lines to lines, not points to lines.

share|improve this question

I used to have this function I used. Be careful it changes the geometry in the existing point table. I didn't use it for a long time but it seem like it should do the job. As far as I remember it works well if you have spatial indexes on both table. In order to call it

SELECT snap_point_to_line('points_table', 'line_table', 500). It will snap with a tolerance of 500, 500 being the unit of your projection system. I used to work with Lambert.

    CREATE OR REPLACE FUNCTION snap_point_to_line(points_table character varying, line_table character varying, tolerance double precision)
      RETURNS boolean AS
            srid integer;
            i integer;

            row record;
            row_1 record;
            closest_distance double precision;

            query varchar;
            snapped_point geometry;

      --Get the srid of the points table
        FOR row IN EXECUTE 'select getsrid(the_geom) as srid from '||points_table||' where gid = (select min(gid) from '||points_table||')' LOOP
        END LOOP;
        srid := row.srid;

     -- Add a column in which it will store the closest nodes from the line
     FOR row IN EXECUTE 'SELECT the_geom FROM '||points_table LOOP

        query := 'SELECT ST_Transform(the_geom,'||srid||') as the_geom, ST_Distance(GeometryFromText('''||ST_AsText(row.the_geom)||''','||srid||'), ST_Transform(the_geom,'||srid||')) as distance FROM ' ||line_table||' ORDER BY ST_Distance(GeometryFromText('''||ST_AsText(row.the_geom)||''','||srid||'), ST_Transform(the_geom,'||srid||'))  LIMIT 1';
        RAISE NOTICE '%',query; 
        FOR row_1 IN EXECUTE query LOOP
            closest_distance := row_1.distance;

            --If below the distance threeshold, then snap the point
            IF closest_distance < tolerance THEN
                snapped_point := ST_line_interpolate_point(ST_LineMerge(row_1.the_geom),ST_line_locate_point(ST_LineMerge(row_1.the_geom), row.the_geom));

                --UPDATE the_geometry
                EXECUTE 'UPDATE '||points_table||' SET the_geom = GeometryFromText('''||ST_AsText(snapped_point)||''','||srid||') WHERE ST_AsText(the_geom) = '''||ST_AsText(row.the_geom)||'''';

            END IF;
    RETURN true;
    COST 100;
    ALTER FUNCTION snap_point_to_line(character varying, character varying, double precision) OWNER TO yourowner;
share|improve this answer
Thanks; is there a way to make this snap lines to lines? I don't think the linear referencing functions will work. (I've added a clarification to the original question). – mattwigway Jul 30 '11 at 0:15

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.