| 1 | CREATE TYPE link_point AS (id integer, name varchar); |
|---|
| 2 | |
|---|
| 3 | ------------------------------------------------------------------- |
|---|
| 4 | -- This function finds nearest link to a given node |
|---|
| 5 | -- point - text representation of point |
|---|
| 6 | -- distance - function will search for a link within this distance |
|---|
| 7 | -- tbl - table name |
|---|
| 8 | ------------------------------------------------------------------- |
|---|
| 9 | CREATE OR REPLACE FUNCTION find_nearest_link_within_distance(point varchar, |
|---|
| 10 | distance double precision, tbl varchar) |
|---|
| 11 | RETURNS INT AS |
|---|
| 12 | $$ |
|---|
| 13 | DECLARE |
|---|
| 14 | row record; |
|---|
| 15 | x float8; |
|---|
| 16 | y float8; |
|---|
| 17 | |
|---|
| 18 | srid integer; |
|---|
| 19 | |
|---|
| 20 | BEGIN |
|---|
| 21 | |
|---|
| 22 | FOR row IN EXECUTE 'select getsrid(the_geom) as srid from '||tbl||' where gid = (select min(gid) from '||tbl||')' LOOP |
|---|
| 23 | END LOOP; |
|---|
| 24 | srid:= row.srid; |
|---|
| 25 | |
|---|
| 26 | -- Getting x and y of the point |
|---|
| 27 | |
|---|
| 28 | FOR row in EXECUTE 'select x(GeometryFromText('''||point||''', '||srid||')) as x' LOOP |
|---|
| 29 | END LOOP; |
|---|
| 30 | x:=row.x; |
|---|
| 31 | |
|---|
| 32 | FOR row in EXECUTE 'select y(GeometryFromText('''||point||''', '||srid||')) as y' LOOP |
|---|
| 33 | END LOOP; |
|---|
| 34 | y:=row.y; |
|---|
| 35 | |
|---|
| 36 | -- Searching for a link within the distance |
|---|
| 37 | |
|---|
| 38 | FOR row in EXECUTE 'select gid, distance(the_geom, GeometryFromText('''||point||''', '||srid||')) as dist from '||tbl|| |
|---|
| 39 | ' where setsrid(''BOX3D('||x-distance||' '||y-distance||', '||x+distance||' '||y+distance||')''::BOX3D, '||srid||')&&the_geom order by dist asc limit 1' |
|---|
| 40 | LOOP |
|---|
| 41 | END LOOP; |
|---|
| 42 | |
|---|
| 43 | IF row.gid IS NULL THEN |
|---|
| 44 | --RAISE EXCEPTION 'Data cannot be matched'; |
|---|
| 45 | RETURN NULL; |
|---|
| 46 | END IF; |
|---|
| 47 | |
|---|
| 48 | RETURN row.gid; |
|---|
| 49 | |
|---|
| 50 | END; |
|---|
| 51 | $$ |
|---|
| 52 | LANGUAGE 'plpgsql' VOLATILE STRICT; |
|---|
| 53 | |
|---|
| 54 | ------------------------------------------------------------------- |
|---|
| 55 | -- This function finds nearest node to a given node |
|---|
| 56 | -- point - text representation of point |
|---|
| 57 | -- distance - function will search for a link within this distance |
|---|
| 58 | -- tbl - table name |
|---|
| 59 | ------------------------------------------------------------------- |
|---|
| 60 | |
|---|
| 61 | CREATE OR REPLACE FUNCTION find_nearest_node_within_distance(point varchar, |
|---|
| 62 | distance double precision, tbl varchar) |
|---|
| 63 | RETURNS INT AS |
|---|
| 64 | $$ |
|---|
| 65 | DECLARE |
|---|
| 66 | row record; |
|---|
| 67 | x float8; |
|---|
| 68 | y float8; |
|---|
| 69 | d1 double precision; |
|---|
| 70 | d2 double precision; |
|---|
| 71 | d double precision; |
|---|
| 72 | field varchar; |
|---|
| 73 | |
|---|
| 74 | node integer; |
|---|
| 75 | source integer; |
|---|
| 76 | target integer; |
|---|
| 77 | |
|---|
| 78 | srid integer; |
|---|
| 79 | |
|---|
| 80 | BEGIN |
|---|
| 81 | |
|---|
| 82 | FOR row IN EXECUTE 'select getsrid(the_geom) as srid from '||tbl||' where gid = (select min(gid) from '||tbl||')' LOOP |
|---|
| 83 | END LOOP; |
|---|
| 84 | srid:= row.srid; |
|---|
| 85 | |
|---|
| 86 | -- Getting x and y of the point |
|---|
| 87 | |
|---|
| 88 | FOR row in EXECUTE 'select x(GeometryFromText('''||point||''', '||srid||')) as x' LOOP |
|---|
| 89 | END LOOP; |
|---|
| 90 | x:=row.x; |
|---|
| 91 | |
|---|
| 92 | FOR row in EXECUTE 'select y(GeometryFromText('''||point||''', '||srid||')) as y' LOOP |
|---|
| 93 | END LOOP; |
|---|
| 94 | y:=row.y; |
|---|
| 95 | |
|---|
| 96 | -- Getting nearest source |
|---|
| 97 | |
|---|
| 98 | FOR row in EXECUTE 'select source, distance(StartPoint(the_geom), GeometryFromText('''||point||''', '||srid||')) as dist from '||tbl|| |
|---|
| 99 | ' where setsrid(''BOX3D('||x-distance||' '||y-distance||', '||x+distance||' '||y+distance||')''::BOX3D, '||srid||')&&the_geom order by dist asc limit 1' |
|---|
| 100 | LOOP |
|---|
| 101 | END LOOP; |
|---|
| 102 | |
|---|
| 103 | d1:=row.dist; |
|---|
| 104 | source:=row.source; |
|---|
| 105 | |
|---|
| 106 | -- Getting nearest target |
|---|
| 107 | |
|---|
| 108 | FOR row in EXECUTE 'select target, distance(EndPoint(the_geom), GeometryFromText('''||point||''', '||srid||')) as dist from '||tbl|| |
|---|
| 109 | ' where setsrid(''BOX3D('||x-distance||' '||y-distance||', '||x+distance||' '||y+distance||')''::BOX3D, '||srid||')&&the_geom order by dist asc limit 1' |
|---|
| 110 | LOOP |
|---|
| 111 | END LOOP; |
|---|
| 112 | |
|---|
| 113 | -- Checking what is nearer - source or target |
|---|
| 114 | |
|---|
| 115 | d2:=row.dist; |
|---|
| 116 | target:=row.target; |
|---|
| 117 | IF d1<d2 THEN |
|---|
| 118 | node:=source; |
|---|
| 119 | d:=d1; |
|---|
| 120 | ELSE |
|---|
| 121 | node:=target; |
|---|
| 122 | d:=d2; |
|---|
| 123 | END IF; |
|---|
| 124 | |
|---|
| 125 | IF d=NULL OR d>distance THEN |
|---|
| 126 | node:=NULL; |
|---|
| 127 | END IF; |
|---|
| 128 | |
|---|
| 129 | RETURN node; |
|---|
| 130 | |
|---|
| 131 | END; |
|---|
| 132 | $$ |
|---|
| 133 | LANGUAGE 'plpgsql' VOLATILE STRICT; |
|---|
| 134 | |
|---|
| 135 | ------------------------------------------------------------------- |
|---|
| 136 | -- This function finds nearest node as a source or target of the |
|---|
| 137 | -- nearest link |
|---|
| 138 | -- point - text representation of point |
|---|
| 139 | -- distance - function will search for a link within this distance |
|---|
| 140 | -- tbl - table name |
|---|
| 141 | ------------------------------------------------------------------- |
|---|
| 142 | |
|---|
| 143 | CREATE OR REPLACE FUNCTION find_node_by_nearest_link_within_distance(point varchar, |
|---|
| 144 | distance double precision, tbl varchar) |
|---|
| 145 | RETURNS link_point AS |
|---|
| 146 | $$ |
|---|
| 147 | DECLARE |
|---|
| 148 | row record; |
|---|
| 149 | link integer; |
|---|
| 150 | d1 double precision; |
|---|
| 151 | d2 double precision; |
|---|
| 152 | field varchar; |
|---|
| 153 | res link_point; |
|---|
| 154 | |
|---|
| 155 | srid integer; |
|---|
| 156 | BEGIN |
|---|
| 157 | |
|---|
| 158 | FOR row IN EXECUTE 'select getsrid(the_geom) as srid from '||tbl||' where gid = (select min(gid) from '||tbl||')' LOOP |
|---|
| 159 | END LOOP; |
|---|
| 160 | srid:= row.srid; |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | -- Searching for a nearest link |
|---|
| 164 | |
|---|
| 165 | FOR row in EXECUTE 'select id from find_nearest_link_within_distance('''||point||''', '||distance||', '''||tbl||''') as id' |
|---|
| 166 | LOOP |
|---|
| 167 | END LOOP; |
|---|
| 168 | IF row.id is null THEN |
|---|
| 169 | res.id = -1; |
|---|
| 170 | RETURN res; |
|---|
| 171 | END IF; |
|---|
| 172 | link:=row.id; |
|---|
| 173 | |
|---|
| 174 | -- Check what is nearer - source or target |
|---|
| 175 | |
|---|
| 176 | FOR row in EXECUTE 'select distance((select StartPoint(the_geom) from '||tbl||' where gid='||link||'), GeometryFromText('''||point||''', '||srid||')) as dist' |
|---|
| 177 | LOOP |
|---|
| 178 | END LOOP; |
|---|
| 179 | d1:=row.dist; |
|---|
| 180 | |
|---|
| 181 | FOR row in EXECUTE 'select distance((select EndPoint(the_geom) from '||tbl||' where gid='||link||'), GeometryFromText('''||point||''', '||srid||')) as dist' |
|---|
| 182 | LOOP |
|---|
| 183 | END LOOP; |
|---|
| 184 | d2:=row.dist; |
|---|
| 185 | |
|---|
| 186 | IF d1<d2 THEN |
|---|
| 187 | field:='source'; |
|---|
| 188 | ELSE |
|---|
| 189 | field:='target'; |
|---|
| 190 | END IF; |
|---|
| 191 | |
|---|
| 192 | FOR row in EXECUTE 'select '||field||' as id, '''||field||''' as f from '||tbl||' where gid='||link |
|---|
| 193 | LOOP |
|---|
| 194 | END LOOP; |
|---|
| 195 | |
|---|
| 196 | res.id:=row.id; |
|---|
| 197 | res.name:=row.f; |
|---|
| 198 | |
|---|
| 199 | RETURN res; |
|---|
| 200 | |
|---|
| 201 | |
|---|
| 202 | END; |
|---|
| 203 | $$ |
|---|
| 204 | LANGUAGE 'plpgsql' VOLATILE STRICT; |
|---|
| 205 | |
|---|
| 206 | ------------------------------------------------------------------- |
|---|
| 207 | -- This function matches given line to the existing network. |
|---|
| 208 | -- Returns set of edges as geometry. |
|---|
| 209 | -- tbl - table name |
|---|
| 210 | -- line - line to match |
|---|
| 211 | -- distance - distance for nearest node search |
|---|
| 212 | -- distance2 - distance for shortest path search |
|---|
| 213 | -- dir - true if your network graph is directed |
|---|
| 214 | -- rc - true if you have a reverse_cost column |
|---|
| 215 | ------------------------------------------------------------------- |
|---|
| 216 | |
|---|
| 217 | CREATE OR REPLACE FUNCTION match_line_as_geometry(tbl varchar, line geometry, distance double precision, |
|---|
| 218 | distance2 double precision, dir boolean, rc boolean) |
|---|
| 219 | RETURNS SETOF GEOMS AS |
|---|
| 220 | $$ |
|---|
| 221 | DECLARE |
|---|
| 222 | row record; |
|---|
| 223 | num integer; |
|---|
| 224 | i integer; |
|---|
| 225 | geom geoms; |
|---|
| 226 | points integer[]; |
|---|
| 227 | |
|---|
| 228 | srid integer; |
|---|
| 229 | |
|---|
| 230 | query text; |
|---|
| 231 | |
|---|
| 232 | BEGIN |
|---|
| 233 | |
|---|
| 234 | FOR row IN EXECUTE 'select getsrid(the_geom) as srid from '||tbl||' where gid = (select min(gid) from '||tbl||')' LOOP |
|---|
| 235 | END LOOP; |
|---|
| 236 | srid:= row.srid; |
|---|
| 237 | |
|---|
| 238 | |
|---|
| 239 | FOR row IN EXECUTE 'select geometryType(GeometryFromText('''||astext(line)||''', '||srid||')) as type' LOOP |
|---|
| 240 | END LOOP; |
|---|
| 241 | |
|---|
| 242 | IF row.type <> 'LINESTRING' THEN |
|---|
| 243 | RAISE EXCEPTION 'Geometry should be a linestring.'; |
|---|
| 244 | END IF; |
|---|
| 245 | |
|---|
| 246 | -- Searching through all points in given line |
|---|
| 247 | |
|---|
| 248 | num:=NumPoints(line); |
|---|
| 249 | i:= 0; |
|---|
| 250 | |
|---|
| 251 | LOOP |
|---|
| 252 | i:=i+1; |
|---|
| 253 | |
|---|
| 254 | -- Getting nearest node to the current point |
|---|
| 255 | |
|---|
| 256 | FOR row in EXECUTE 'select * from find_nearest_node_within_distance(''POINT(' |
|---|
| 257 | ||x(PointN(line, i))||' '||y(PointN(line, i))||')'','||distance||', '''||tbl||''') as id' |
|---|
| 258 | LOOP |
|---|
| 259 | END LOOP; |
|---|
| 260 | |
|---|
| 261 | IF row.id IS NOT NULL THEN |
|---|
| 262 | points[i-1]:=row.id; |
|---|
| 263 | |
|---|
| 264 | ELSE |
|---|
| 265 | |
|---|
| 266 | -- If there is no nearest node within given distance, let's try another algorithm |
|---|
| 267 | |
|---|
| 268 | FOR row in EXECUTE 'select * from find_node_by_nearest_link_within_distance(''POINT(' |
|---|
| 269 | ||x(PointN(line, i))||' '||y(PointN(line, i))||')'','||distance2||', '''||tbl||''') as id' |
|---|
| 270 | LOOP |
|---|
| 271 | END LOOP; |
|---|
| 272 | |
|---|
| 273 | points[i-1]:=row.id; |
|---|
| 274 | |
|---|
| 275 | END IF; |
|---|
| 276 | |
|---|
| 277 | IF i>1 AND points[i-2] <> points[i-1] THEN |
|---|
| 278 | |
|---|
| 279 | -- We could find existing edge, so let's construct the main query now |
|---|
| 280 | |
|---|
| 281 | query := 'select gid, the_geom FROM shortest_path( ''select gid as id, source::integer,'|| |
|---|
| 282 | ' target::integer, length::double precision as cost,x1,x2,y1,y2'; |
|---|
| 283 | |
|---|
| 284 | IF rc THEN query := query || ', reverse_cost'; |
|---|
| 285 | END IF; |
|---|
| 286 | |
|---|
| 287 | query := query || ' from '||quote_ident(tbl)||' where setsrid(''''BOX3D('||x(PointN(line, i-1))-distance2*2||' ' |
|---|
| 288 | ||y(PointN(line, i-1))-distance2*2||', '||x(PointN(line, i))+distance2*2||' ' |
|---|
| 289 | ||y(PointN(line, i))+distance2*2||')''''::BOX3D, '||srid||')&&the_geom'', ' |
|---|
| 290 | || points[i-1] ||', '|| points[i-2] ||', '''||dir||''', '''||rc||'''), ' |
|---|
| 291 | ||quote_ident(tbl)||' where edge_id=gid'; |
|---|
| 292 | FOR row IN EXECUTE query |
|---|
| 293 | LOOP |
|---|
| 294 | |
|---|
| 295 | geom.gid := row.gid; |
|---|
| 296 | geom.the_geom := row.the_geom; |
|---|
| 297 | |
|---|
| 298 | RETURN NEXT geom; |
|---|
| 299 | |
|---|
| 300 | END LOOP; |
|---|
| 301 | |
|---|
| 302 | END IF; |
|---|
| 303 | |
|---|
| 304 | |
|---|
| 305 | EXIT WHEN i=num; |
|---|
| 306 | |
|---|
| 307 | |
|---|
| 308 | END LOOP; |
|---|
| 309 | |
|---|
| 310 | RETURN; |
|---|
| 311 | |
|---|
| 312 | END; |
|---|
| 313 | $$ |
|---|
| 314 | |
|---|
| 315 | LANGUAGE 'plpgsql' VOLATILE STRICT; |
|---|
| 316 | |
|---|
| 317 | ------------------------------------------------------------------- |
|---|
| 318 | -- This function matches given line to the existing network. |
|---|
| 319 | -- Returns set of edges. |
|---|
| 320 | -- tbl - table name |
|---|
| 321 | -- line - line to match |
|---|
| 322 | -- distance - distance for nearest node search |
|---|
| 323 | -- distance2 - distance for shortest path search |
|---|
| 324 | -- dir - true if your network graph is directed |
|---|
| 325 | -- rc - true if you have a reverse_cost column |
|---|
| 326 | ------------------------------------------------------------------- |
|---|
| 327 | |
|---|
| 328 | CREATE OR REPLACE FUNCTION match_line(tbl varchar, line geometry, distance double precision, |
|---|
| 329 | distance2 double precision, dir boolean, rc boolean) |
|---|
| 330 | RETURNS SETOF PATH_RESULT AS |
|---|
| 331 | $$ |
|---|
| 332 | DECLARE |
|---|
| 333 | row record; |
|---|
| 334 | num integer; |
|---|
| 335 | |
|---|
| 336 | i integer; |
|---|
| 337 | z integer; |
|---|
| 338 | t integer; |
|---|
| 339 | |
|---|
| 340 | prev integer; |
|---|
| 341 | |
|---|
| 342 | query text; |
|---|
| 343 | |
|---|
| 344 | path path_result; |
|---|
| 345 | |
|---|
| 346 | edges integer[]; |
|---|
| 347 | vertices integer[]; |
|---|
| 348 | costs double precision[]; |
|---|
| 349 | |
|---|
| 350 | srid integer; |
|---|
| 351 | |
|---|
| 352 | points integer[]; |
|---|
| 353 | |
|---|
| 354 | BEGIN |
|---|
| 355 | |
|---|
| 356 | FOR row IN EXECUTE 'select getsrid(the_geom) as srid from '||tbl||' where gid = (select min(gid) from '||tbl||')' LOOP |
|---|
| 357 | END LOOP; |
|---|
| 358 | srid:= row.srid; |
|---|
| 359 | |
|---|
| 360 | FOR row IN EXECUTE 'select geometryType(GeometryFromText('''||astext(line)||''', '||srid||')) as type' LOOP |
|---|
| 361 | END LOOP; |
|---|
| 362 | |
|---|
| 363 | IF row.type <> 'LINESTRING' THEN |
|---|
| 364 | RAISE EXCEPTION 'Geometry should be a linestring.'; |
|---|
| 365 | END IF; |
|---|
| 366 | |
|---|
| 367 | num:=NumPoints(line); |
|---|
| 368 | i:= 0; |
|---|
| 369 | z:= 0; |
|---|
| 370 | prev := -1; |
|---|
| 371 | |
|---|
| 372 | -- Searching through all points in given line |
|---|
| 373 | |
|---|
| 374 | LOOP |
|---|
| 375 | i:=i+1; |
|---|
| 376 | |
|---|
| 377 | -- Getting nearest node to the current point |
|---|
| 378 | |
|---|
| 379 | FOR row in EXECUTE 'select * from find_nearest_node_within_distance(''POINT(' |
|---|
| 380 | ||x(PointN(line, i))||' '||y(PointN(line, i))||')'','||distance||', '''||tbl||''') as id' |
|---|
| 381 | LOOP |
|---|
| 382 | END LOOP; |
|---|
| 383 | |
|---|
| 384 | |
|---|
| 385 | IF row.id IS NOT NULL THEN |
|---|
| 386 | points[i-1]:=row.id; |
|---|
| 387 | |
|---|
| 388 | ELSE |
|---|
| 389 | |
|---|
| 390 | -- If there is no nearest node within given distance, let's try another algorithm |
|---|
| 391 | |
|---|
| 392 | FOR row in EXECUTE 'select * from find_node_by_nearest_link_within_distance(''POINT(' |
|---|
| 393 | ||x(PointN(line, i))||' '||y(PointN(line, i))||')'','||distance2||', '''||tbl||''') as id' |
|---|
| 394 | LOOP |
|---|
| 395 | END LOOP; |
|---|
| 396 | |
|---|
| 397 | points[i-1]:=row.id; |
|---|
| 398 | IF row.id = -1 THEN |
|---|
| 399 | return; |
|---|
| 400 | END IF; |
|---|
| 401 | |
|---|
| 402 | END IF; |
|---|
| 403 | |
|---|
| 404 | IF i>1 AND points[i-2] <> points[i-1] THEN |
|---|
| 405 | |
|---|
| 406 | -- We could find existing edge, so let's construct the main query now |
|---|
| 407 | |
|---|
| 408 | query := 'select edge_id, vertex_id, cost FROM shortest_path( ''select gid as id, source::integer,'|| |
|---|
| 409 | ' target::integer, length::double precision as cost,x1,x2,y1,y2 '; |
|---|
| 410 | |
|---|
| 411 | IF rc THEN query := query || ', reverse_cost'; |
|---|
| 412 | END IF; |
|---|
| 413 | |
|---|
| 414 | query := query || ' from '||quote_ident(tbl)||' where setsrid(''''BOX3D('||x(PointN(line, i-1))-distance2*2||' ' |
|---|
| 415 | ||y(PointN(line, i-1))-distance2*2||', '||x(PointN(line, i))+distance2*2||' ' |
|---|
| 416 | ||y(PointN(line, i))+distance2*2||')''''::BOX3D, '||srid||')&&the_geom'', ' |
|---|
| 417 | || points[i-1] ||', '|| points[i-2] ||', '''||dir||''', '''||rc||''')'; |
|---|
| 418 | |
|---|
| 419 | |
|---|
| 420 | BEGIN |
|---|
| 421 | |
|---|
| 422 | FOR row IN EXECUTE query |
|---|
| 423 | LOOP |
|---|
| 424 | |
|---|
| 425 | |
|---|
| 426 | IF row IS NULL THEN |
|---|
| 427 | RAISE NOTICE 'Cannot find a path between % and %', points[i-1], points[i-2]; |
|---|
| 428 | RETURN; |
|---|
| 429 | END IF; |
|---|
| 430 | |
|---|
| 431 | edges[z] := row.edge_id; |
|---|
| 432 | vertices[z] := row.vertex_id; |
|---|
| 433 | costs[z] := row.cost; |
|---|
| 434 | |
|---|
| 435 | IF edges[z] = -1 THEN |
|---|
| 436 | |
|---|
| 437 | t := 0; |
|---|
| 438 | |
|---|
| 439 | -- Ordering edges |
|---|
| 440 | |
|---|
| 441 | FOR t IN (prev+1)..z-1 LOOP |
|---|
| 442 | |
|---|
| 443 | path.edge_id := edges[t]; |
|---|
| 444 | path.vertex_id := vertices[t]; |
|---|
| 445 | path.cost = costs[t]; |
|---|
| 446 | |
|---|
| 447 | edges[t] := edges[z-t+prev+1]; |
|---|
| 448 | vertices[t] := vertices[z-t+prev+1]; |
|---|
| 449 | costs[t] := costs[z-t+prev+1]; |
|---|
| 450 | |
|---|
| 451 | edges[z-t+prev+1] := path.edge_id; |
|---|
| 452 | vertices[z-t+prev+1] := path.vertex_id; |
|---|
| 453 | costs[z-t+prev+1] := path.cost; |
|---|
| 454 | |
|---|
| 455 | |
|---|
| 456 | END LOOP; |
|---|
| 457 | |
|---|
| 458 | prev := z; |
|---|
| 459 | |
|---|
| 460 | END IF; |
|---|
| 461 | |
|---|
| 462 | z := z+1; |
|---|
| 463 | |
|---|
| 464 | END LOOP; |
|---|
| 465 | |
|---|
| 466 | EXCEPTION |
|---|
| 467 | WHEN containing_sql_not_permitted THEN RETURN; |
|---|
| 468 | |
|---|
| 469 | END; |
|---|
| 470 | |
|---|
| 471 | END IF; |
|---|
| 472 | |
|---|
| 473 | EXIT WHEN i=num; |
|---|
| 474 | |
|---|
| 475 | END LOOP; |
|---|
| 476 | |
|---|
| 477 | FOR t IN 0..array_upper(edges, 1) LOOP |
|---|
| 478 | |
|---|
| 479 | IF edges[array_upper(edges, 1)-t] > 0 OR (edges[array_upper(edges, 1)-t] < 0 AND t = array_upper(edges, 1)) THEN |
|---|
| 480 | path.edge_id := edges[array_upper(edges, 1)-t]; |
|---|
| 481 | path.vertex_id := vertices[array_upper(edges, 1)-t]; |
|---|
| 482 | path.cost = costs[array_upper(edges, 1)-t]; |
|---|
| 483 | RETURN NEXT path; |
|---|
| 484 | END IF; |
|---|
| 485 | END LOOP; |
|---|
| 486 | |
|---|
| 487 | RETURN; |
|---|
| 488 | |
|---|
| 489 | END; |
|---|
| 490 | $$ |
|---|
| 491 | |
|---|
| 492 | LANGUAGE 'plpgsql' VOLATILE STRICT; |
|---|
| 493 | |
|---|
| 494 | ------------------------------------------------------------------- |
|---|
| 495 | -- This function matches given line to the existing network. |
|---|
| 496 | -- Returns single (multi)linestring. |
|---|
| 497 | -- tbl - table name |
|---|
| 498 | -- line - line to match |
|---|
| 499 | -- distance - distance for nearest node search |
|---|
| 500 | -- distance2 - distance for shortest path search |
|---|
| 501 | -- dir - true if your network graph is directed |
|---|
| 502 | -- rc - true if you have a reverse_cost column |
|---|
| 503 | ------------------------------------------------------------------- |
|---|
| 504 | |
|---|
| 505 | CREATE OR REPLACE FUNCTION match_line_as_linestring(tbl varchar, line geometry, distance double precision, |
|---|
| 506 | distance2 double precision, dir boolean, rc boolean) |
|---|
| 507 | RETURNS GEOMETRY AS |
|---|
| 508 | $$ |
|---|
| 509 | DECLARE |
|---|
| 510 | row record; |
|---|
| 511 | |
|---|
| 512 | i integer; |
|---|
| 513 | |
|---|
| 514 | edges integer[]; |
|---|
| 515 | |
|---|
| 516 | srid integer; |
|---|
| 517 | |
|---|
| 518 | BEGIN |
|---|
| 519 | |
|---|
| 520 | FOR row IN EXECUTE 'select getsrid(the_geom) as srid from '||tbl||' where gid = (select min(gid) from '||tbl||')' LOOP |
|---|
| 521 | END LOOP; |
|---|
| 522 | srid:= row.srid; |
|---|
| 523 | |
|---|
| 524 | FOR row IN EXECUTE 'select geometryType(GeometryFromText('''||astext(line)||''', '||srid||')) as type' LOOP |
|---|
| 525 | END LOOP; |
|---|
| 526 | |
|---|
| 527 | IF row.type <> 'LINESTRING' THEN |
|---|
| 528 | RAISE EXCEPTION 'Geometry should be a linestring.'; |
|---|
| 529 | END IF; |
|---|
| 530 | |
|---|
| 531 | i := 0; |
|---|
| 532 | |
|---|
| 533 | FOR row IN EXECUTE 'select * from match_line('''||quote_ident(tbl)||''', GeometryFromText('''||astext(line)||''', '||srid||'), ' |
|---|
| 534 | ||distance||', '||distance2||', '''||dir||''', '''||rc||''')' LOOP |
|---|
| 535 | edges[i] := row.edge_id; |
|---|
| 536 | i := i + 1; |
|---|
| 537 | END LOOP; |
|---|
| 538 | IF i = 0 THEN |
|---|
| 539 | return NULL; |
|---|
| 540 | END IF; |
|---|
| 541 | |
|---|
| 542 | -- Attempt to create a single linestring. It may return multilinestring as well. |
|---|
| 543 | |
|---|
| 544 | FOR row IN EXECUTE 'select linemerge(geomunion(multi(the_geom))) as the_geom from '||tbl||' where gid in ('||array_to_string(edges, ', ')||') and gid > 0' LOOP |
|---|
| 545 | END LOOP; |
|---|
| 546 | |
|---|
| 547 | IF isvalid(row.the_geom) THEN |
|---|
| 548 | RETURN row.the_geom; |
|---|
| 549 | ELSE |
|---|
| 550 | RAISE EXCEPTION 'The result is not a valid geometry.'; |
|---|
| 551 | END IF; |
|---|
| 552 | |
|---|
| 553 | END; |
|---|
| 554 | $$ |
|---|
| 555 | |
|---|
| 556 | LANGUAGE 'plpgsql' VOLATILE STRICT; |
|---|