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! ![:slight_smile: :slight_smile:](/images/emoji/twitter/slight_smile.png?v=12)
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