[Gfoss] POSTGIS e i dislivelli

Alessandro Pasotti ale.pas a tiscali.it
Lun 5 Ott 2009 13:00:00 CEST


Il venerdì 02 ottobre 2009, Antonio Falciano ha scritto:
> Alessandro Pasotti ha scritto:
> > Il venerdì 02 ottobre 2009, Antonio Falciano ha scritto:
> >> Alessandro Pasotti ha scritto:
> >>> Il venerdì 02 ottobre 2009, Antonio Falciano ha scritto:
> >>>> Alessandro Pasotti ha scritto:
> >>>>> Ciao (scusate il cross-post errato in lista soci),
> >>>>>
> >>>>> devo calcolare i dislivelli in discesa e in salita di una polilinea
> >>>>> 3D, sapete se (e come) si può fare con postgis?
> >>>>
> >>>> SELECT ST_ZMAX(the_geom) as z_max, ST_ZMIN(the_geom) as z_min,
> >>>> (ST_ZMAX(the_geom) - ST_ZMIN(the_geom)) as delta_z FROM streets;
> >>>>
> >>>> se ti interessa il dislivello esistente in assoluto, mentre per quello
> >>>> relativo occorre usare anche ST_PointN.
> >>>>
> >>>> ciao
> >>>> Antonio
> >>>
> >>> Grazie!
> >>>
> >>> se ho capito bene le prime due funzioni restituiscono quote minime e
> >>> massime,
> >>
> >> ok
> >>
> >>> se voglio sapere i dislivelli relativi devo quindi scrivere una
> >>> funzione che iterando su tutti i punti della polilinea, sommi tutti i
> >>> dislivelli in un verso (convenzionalmente salita) e in quello opposto
> >>> (discesa) ?
> >>
> >> No, perche' per via dei segni perderesti per strada buona parte
> >> dell'informazione. Cosi' facendo calcolaresti il dislivello tra il punto
> >> iniziale e finale e, a tal fine, basterebbe semplicemente recuperare la
> >> z di questi due agendo con ST_PointN (v. 2° es. in
> >> http://postgis.refractions.net/docs/ST_PointN.html
> >> Purtroppo cosi' si perdono tutti i dislivelli intermedi.
> >
> > Ho dato per scontato che userei due variabili, una per accumulare i
> > dislivelli in discesa e l'altra per quelli in salita (pseudo codice):
> >
> > for punto in linea
> > 	if punto_tmp
> > 		if punto.z > punto_tmp.z
> > 			salita += punto.z - punto_tmp.z
> > 		else
> > 			discesa += punto_tmp.z - punto.z
> > 	punto_tmp = punto
> >
> >
> > sbaglio qualcosa?
>
> ok, cosi' va meglio... ma, in ogni caso, mi calcolerei la pendenza,
> poiche' uno stesso dislivello lo puoi avere lungo 1 km opp. dopo soli 5
> m di tracciato, ti pare?
> Un'altra strategia potrebbe essere quella di "esplodere" le polilinee in
> linee, calcolare agevolmente il dislivello e quindi la pendenza di ogni
> singola linea ed, infine, riaggregare il tutto mediando le pendenze.
>
> >> Inoltre, potresti considerare anche la tipologia di tracciato (sterrato,
> >> pavimentato, ecc.) in modo considerare il grado di difficolta' nella sua
> >> percorrenza.
> >
> > Ho anche le variabili del mezzo: a piedi, in bici ecc. ma non so se mi
> > spingerò così avanti.
>
> Altre variabili da tenere conto nella funzione di costo potrebbero
> essere la tortuosita' del tracciato e le condizioni psico-fisiche del
> soggetto che lo percorre, ad es. con o senza grappino! :)
>
> ciao

Grappino a parte, ecco la funzione, in caso serva a qualcuno.


CREATE OR REPLACE FUNCTION dislivelli(line geometry)
  RETURNS real[] AS
$BODY$
DECLARE
	discesa real;
	salita real;
	point_iter geometry;
	point_tmp geometry;
	line_tmp geometry;
	num_points integer;
	i integer;
BEGIN
	discesa := 0.0;
	salita := 0.0;
	IF (GEOMETRYTYPE(line) = 'MULTILINESTRING') THEN
		line_tmp := ST_Force_3D(linemerge(line));
	ELSIF (GEOMETRYTYPE(line) = 'LINESTRING') THEN
		line_tmp := ST_Force_3D(line);
	ELSE
		Raise Exception 'Not a linestring or multilenstring!';
	END IF;
	num_points := ST_NPoints(line_tmp);
	--Raise Notice 'Points: %',  i;
	point_tmp := NULL;
	FOR i IN 1..num_points LOOP
		point_iter := ST_PointN(line_tmp, i);
		--Raise Notice 'Point Iter % : %', i, ST_asEWKT(point_iter);
		--Raise Notice 'Point Tmp % : %', i, ST_asEWKT(point_tmp);
		IF (NOT point_tmp IS NULL) THEN
			IF ST_Z(point_tmp) > ST_Z(point_iter) THEN
				discesa := discesa + ST_Z(point_tmp) - ST_Z(point_iter); 
				--Raise Notice 'Discesa : %' , discesa; 
			ELSE
				salita := salita + ST_Z(point_iter) - ST_Z(point_tmp);
				--Raise Notice 'Salita : %' , salita; 
			END IF;
		END IF;
		point_tmp := point_iter;
	END LOOP;
	
	RETURN ARRAY[salita,discesa];
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE STRICT
  COST 100;
COMMENT ON FUNCTION dislivelli(geometry) IS 'Calcola i dislivelli in salita e 
in discesa di una polilinea

Test: select dislivelli(st_geomfromewkt(''LINESTRING(1 2 4.0, 2 3 5.8, 3 6 
8.09, 2 4 1.0008)''));';


Ciao

-- 
Alessandro Pasotti
itOpen - "Open Solutions for the Net Age"
w3:  www.itopen.it
Linux User# 167502


Maggiori informazioni sulla lista Gfoss