pgRouting

Forum #18 - Topic #123 - Message List

Choosing the nearest firestation

Hi,

I have a list of points, representing firestations. I am making a query so as to choose which is the nearest firestation to a point selected by the user (presuming it is where there is an accident). If the accident is a bit far from the firestation it gives me the nearest, but if the accident is very close to the firestation, I am getting a one which is further far.

I am providing some data to help my claim :

SELECT gid, astext(the_geom) as wkt, the_geom , length(the_geom) AS length
              FROM shootingstar_sp
              ('streets', 
                (
                select gid from streets where
                source = ( select give_source((select near_accident ('POINT(634320.5 241427.5)','firestations') ),1000,200) )
                limit 1
                )
              ,
              
                (
                select gid from streets where 
                target = ( select give_target('POINT(634320.5 241427.5)',1000,200) )
                limit 1
      
                )
              ,
              5000,
              'length',
              true,
              true
              );

This is the main query I am using. This can be better seen here : http://yancho.pastebin.com/f671701dd

I am using three custom functions give_source and give_target (which are practically the same), and near_accident. I am going to paste near_accident and give_source further down.

near_accident function first checks which of the firestations / hospitals (I can pass any of the two) falls within a region of 1000 meters (1 KM) and gives me the 3 nearest ones.

CREATE OR REPLACE FUNCTION near_accident(text, text)
  RETURNS text AS
$BODY$

	DECLARE
		pojnt ALIAS FOR $1;
		tejbil ALIAS FOR $2;
		distances RECORD;
		hospital RECORD;
		nearest RECORD;
		silect TEXT;
		
		sorc INTEGER;
		targit INTEGER;

	BEGIN
	       
		select 'inf'::float8 as dist, null::text as gid INTO nearest;
	 
raise notice 'Point is %', pojnt;    
select give_target(pojnt,1000,200) INTO targit;
raise notice 'value of target : %',targit;

raise notice '-----------------------------------------------'; 
	-- raise notice 'Entering the FOR IN %', timeofday() ;

	silect := ' select astext(h.the_geom) as hospital_location from '|| tejbil ||' h where 
					 (
					 h.the_geom && expand (pointfromtext('|| quote_literal(pojnt) ||'),100000) and
					 distance ( h.the_geom , pointfromtext('|| quote_literal(pojnt) ||') ) < 150000
					 )
				    order by distance (h.the_geom , pointfromtext('|| quote_literal(pojnt) ||')) ASC
				    limit 3 ';
	

	       FOR distances IN 
					EXECUTE silect


		
		LOOP

raise notice '=====================================================';	
 raise notice 'point location of hospital : %',	distances.hospital_location;	



 -- raise notice 'before give source : %', timeofday();
select give_source(distances.hospital_location,1000,200) INTO sorc;
raise notice 'value of sorc : %', sorc;
 --  raise notice 'after give source : %', timeofday();
  -- raise notice 'before give target : %', timeofday();

 --  raise notice 'after give target : %', timeofday();
	 --  raise notice 'entering shooting star %', timeofday() ;	
	       
		select gid, the_geom, length(the_geom) AS dist INTO hospital from shootingstar_sp
			      ( 'streets',
				    
				    (
					select s.gid from streets s where
					source = (sorc)
					limit 1


				    )

				    ,

				    (
					select gid from streets where
					target = ( targit)
					limit 1

				    )
				    
				    ,
				   5000,
				   'rcost',
				   true,
				   true
			      );
	 
	  raise notice 'Hospital Distance %', hospital.dist ;             

		      IF hospital.dist < nearest.dist  THEN
			  nearest.dist := hospital.dist;
	 raise notice 'value of nearest.dist is %', nearest.dist;
	 raise notice 'value of hospital.gid is %', hospital.gid;
	raise notice 'value of nearest.gid is %', nearest.gid;
			  nearest.gid := distances.hospital_location;
	raise notice 'value of 2ND nearest.gid is %', nearest.gid;

		      END IF;
	  -- raise notice 'after if %', timeofday() ;
	  -- raise notice 'before end of loop %', timeofday() ;
		      
	       END LOOP;
 -- 	raise notice 'after end of loop before returning %', timeofday() ;      
	       RETURN nearest.gid;
	      
	END;
	$BODY$
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION near_accident(text, text) OWNER TO yancho;

Which can be seen better here : http://yancho.pastebin.com/f21443d2a

And this is give_source which basically gives the source of the segment where the point lies :

CREATE OR REPLACE FUNCTION give_source(text, integer, integer)
  RETURNS integer AS
$BODY$

DECLARE
	pojnt ALIAS FOR $1;
	box ALIAS FOR $2;
	dist ALIAS FOR $3;

        r_source INTEGER;

BEGIN
	SELECT source INTO r_source 
	FROM streets s
	WHERE
		(
		the_geom && expand (pointfromtext(pojnt),box) and
		distance (s.the_geom , pointfromtext(pojnt)) < dist
		)
	ORDER BY distance (s.the_geom , pointfromtext(pojnt)) ASC
	LIMIT 1;

        RETURN r_source;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION give_source(text, integer, integer) OWNER TO yancho;

This can be better seen on : http://yancho.pastebin.com/f1db6b9cb

This is the result of the query I tried further up without showing the_geom :

  gid  |      length
-------+------------------
 46381 | 119.487000043323
 18196 | 118.668466931316
 21381 | 79.3749649748783
 17475 | 253.725975566964
 27494 | 74.5860393897621
 27493 | 63.7091656025134
 43129 | 185.128448448782
  5869 | 516.719430428418
 15251 | 211.399367734986
 42199 | 116.250314289262
 14316 | 32.6834707532192
  1743 | 123.843233939053
  4795 | 445.086042844799
 26706 |  125.79054976706
 23447 | 250.247125321842
 39960 | 352.879997114279
 27650 | 130.104149031247
 18320 | 88.1763693815924
 30714 | 103.273731618617
 49295 | 103.241010673955
 49209 | 519.309405228989
(21 rows)

This is a screenshot of the flaw : http://thesis.solutions-lab.net/wrong_firestations.jpg and this is a CSV file with the result of the query : http://thesis.solutions-lab.net/near_fire.csv

The green path is the route from the accident to the nearest firestation (the red/yellow star). As one can see there is one which is much nearer on the right @ location 634799,241982.

The red is me highlighting the part of the road which is a BIdirectional road and is a state road.

Is there anyone with an idea what I can do about this bug please?

Thanks and regards

Matthew