You are on page 1of 44

Baze prostornih podataka - Upute za vježbe

Mario Miler, Dražen Odobašić


11. studenog 2014.

1
Sadržaj
1 Što je i zašto Python? 4
1.1 Karakteristike Pythona . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Osnove programiranja 5

3 Instalacija i konfiguracija Python okoline 7

4 Osnove Pythona 8
4.1 Introspekcija i pomoć . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.2 Uvjetno izvršavanje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.3 Petlja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.4 Lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.5 Rječnik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.6 Funkcije . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4.7 Pretvorba tipova podataka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

5 Uvod u Shapely i Matplotlib 14


5.1 Stvaranje prostornih objekata u Shapelyu . . . . . . . . . . . . . . . . . . . . 14
5.2 Atributi i funkcije Shapely prostornih objekata . . . . . . . . . . . . . . . . . 15
5.3 Iscrtavanje Shapely prostornih objekata pomoću matplotlib biblioteke . . . . . 17
5.4 Zadatak 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

6 Prostorni odnosi, upiti i analize 21


6.1 Prostorni odnosi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6.2 Prostorne analize i funkcije za procesiranje prostornih objekata . . . . . . . . 22
6.3 Zadatak 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

7 Obrada SHP datoteka 31


7.1 Čitanje SHP datoteke koristeći OGR modula . . . . . . . . . . . . . . . . . . . 31
7.2 Resetiranje petlje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
7.3 Zadatak 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

8 Atributi i filteri nad SHP datotekama 37


8.1 Čitanje atributnih podataka SHP datoteka . . . . . . . . . . . . . . . . . . . . 37
8.2 Filtriranje atributnih podataka . . . . . . . . . . . . . . . . . . . . . . . . . . 37

9 Linearno referenciranje 38

10 Uvod u modul Fiona 42


10.1 Čitanje SHP datoteke koristeći Fiona modul . . . . . . . . . . . . . . . . . . . 42
10.2 Stvaranje nove SHP datoteke . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

2
Sažetak

• što je i zašto Python?


• osnovna terminologija u programiranju
• osnovni elementi programa
• instalacija Python okoline
• strukture podataka
• rad s listama
1 Što je i zašto Python?
Python (http://python.org) je programski jezik visoke razine (http://en.wikipedia.
org/wiki/High-level_programming_language), koji se često naziva skriptnim programskim
jezikom. Razvoj 2001. godine započinje Guido van Rossum1 , a naziv dobiva Monty Pyt-
hon serijalu. Python je slobodan softver dostupan pod licencom koja bilo kome omogućava
korištenje u bilo koju svrhu.
Python je interpreterski programski jezik što znači da se izvorni kod prevodi u izvršni u
trenutku izvršavanja programa. Primjerice Java, PHP, Ruby, ... su interpreterski programski
jezici. Interpreterski jezici su multiplatformalni, jer da bi se kod izvršio potrebno je “samo”
napisati interpreter za neku platformu i operativni sustav. Primjerice postoje implementacije
Python jezika koje se mogu izvršavati u Java Virtual Mashine (JVM) (http://jython.org)
ili .NET okolini (http://www.codeplex.com/wikipage?ProjectName=IronPython).

1.1 Karakteristike Pythona


Osnovna karakteristika Pythona je njegova jednostavnost koju opisuje mali broj osnovnih
naredbi koje je potrebno znati kako bi se kod efektivno pisao.
Druga karakteristika je dinamičnost jezika. Za razliku od C/C++ ili Jave, nije potrebno
deklarirati tip varijable prije izvršavanja, nego je tip varijable dinamičan, odnosno može se
lako promijeniti. Također svaki objekt je dinamičan, što omogućava definiranje novih objekata
u trenutku izvršavanja.
Python koristi “prazan prostor”2 za definiranje blokova kôda. Primjerice C/C++ ili Java
koriste vitičaste zagrade { } za definiciju početka i kraja bloka (tablica 1).

Python Java

def zbroji(a,b): public int zbroji (int a, int b) {


if a>b: if (a>b){return a+b;}
return a+b else {return b+a;}
else: }
return b+a

Tablica 1: Primjer koda Python/Java

Osim toga Python za terminator naredbe programa koristi oznaku za novi red, dok je kod
Jave terminator točka-zarez ;. Ovakav pristup je dvosjekli mač. Jer iako je Python kod lakše
čitati, zbog jasno prepoznatljivih blokova koda, jedna greška u formatiranju rezultira greškom
u programu. Napomena: za formatiranje koda koristiti ili razmak ili tabulator,
nikako oboje!
Za Python se često kaže da dolazi s uključenim baterijama, odnosno s velikim brojem
biblioteka i modula. Osim toga, postoji još veći broj biblioteka i modula kojima je moguće
1
http://en.wikipedia.org/wiki/Guido_van_Rossum
2
eng. whitespace

4
proširiti funkcionalnost. Zbog toga Python se koristi za izgradnju web aplikacija, obradu
podataka, interakciju s bazama podataka, razvoj korisničkih sučelja, skriptiranje procesa,
vizualizacije, …
Proširivost i jednostavnost omogućile su Pythonu široki raspon iskoristivosti, pa ga tako
koriste Youtube, Google, ILM, …, a moguće ga je koristiti za skriptiranje ArcGIS programskog
paketa, ili AutoCada kroz IronPython. Može se reći da ne donosi neke nove revolucionarne
značajke u programiranju, već na optimalan način ujedinjuje sve najbolje ideje i načela rada
drugih programskih jezika.

2 Osnove programiranja
Vjerojatno ste obradili osnove programiranja kroz neki kolegij na fakultetu, no ponoviti
ćemo neke osnovne pojmove:
program je niz instrukcija koje definiraju kako napraviti izračun, a svaki program ima sljedeće
dijelove:
ulazne kontrole ulaz podataka iz datoteka, tipkovnice, miša, …
kontrole izlaza prikaz podataka na zaslonu, spremanje u datoteku, slanje mrežom, …
matematika izvršavanje osnovnih matematičkih operacija, zbrajanje, množenje, …
uvjetno izvršavanje ovisno o uvjetima dijelovi koda će se izvršiti ili ne
ponavljanje ponovno izvršavanje koda
programiranje je proces u kojem razbijamo kompleksne zadatke na mnogo manjih koji se
mogu opisati jednostavnim operacijama, u tom procesu javljaju se greške, a proces uk-
lanjanja greški (bugova) naziva se debugging:
sintaksne krivo napisane instrukcije, npr. fi umjesto if ; najbrže se uklanjaju
izvršne greške koje se događaju tijekom izvršavanja programa, npr. ne postoji datoteka
na disku, ili nije moguće pristupiti mrežnom resursu; relativno se brzo uklanjaju
semantičke iako će se program uspješno izvršiti neće vratiti rezultat koji želimo, od-
nosno program će napraviti upravo ono što smo mu rekli da napravi; najteže se
uklanjaju
programski jezik je formalni jezik3 ; osnovni elementi jezika su simboli (riječi, brojevi, zna-
kovi, …) i struktura (određuje odnos u kojem se nalaze simboli)
Program koristi i upravlja vrijednostima, primjerice 3, Python je super!, 3.14 su
vrijednosti. Svakoj vrijednosti se može odrediti tip podatka, odnosno vrijednost je nekog tipa.
Uglavnom se razlikuju jednostavni i složeni tipovi podataka:
jednostavni tipovi kao cijeli broj int, realni broj float, datum date, niz znakova string, …
složeni tipovi su strukture koje mogu sadržavati jednostavne i složene tipove podataka, npr.
n-torka (eng. tuple) – (1,2,3,4,’Python’), lista (eng. list) – [1,2,3,4,’Python’], rječnik
(eng. dictonary) – {’broj’:123, ’naziv’:’Geodetski fakultet’}
3
formalni jezici su dizajnirani za specifičnu primjenu, tj. definirana su striktna pravila

5
Operatori su posebni simboli koji predstavljaju operacije na vrijednostima, poput zbra-
janja (+) i množenja (*). Python, kao i većina programskih jezika, ima sljedeći redoslijed
izvršavanja operatora:

1. zagrade ()

2. potenciranje **

3. množenje *, dijeljenje /

4. zbrajanje +, oduzimanje -

Ukoliko operatori imaju isti prioritet redoslijed izvršavanja je s lijeva na desno. Primjerice
izraz 2 + 3 − 5 ∗ 2, prvo će se izvršiti množenje, dakle 5 ∗ 2, nakon toga se izvršava zbrajanje
2 + 3, i tek nakon toga oduzimanje 5 − 10.
Varijabla je naziv koji povezujemo s vrijednosti, npr. broj_studenata=57 ili niz znakova
poruka=''Danas pada kiša!''. Varijable koristimo jer je lakše pamtiti i upravljati varijabla-
ma nego vrijednostima. Vrijednost se dodjeljuje varijabli upotrebom operatora dodjeljivanja
=.
Kao i svaki jezik Python definira pravila kako nazivati varijable, također treba uzeti u
obzir da razlikuje velika i mala slova:

• naziv može biti proizvoljne dužine

• mora započinjati sa slovom

• smije se koristiti _ podcrta

• nazivi ne mogu biti ključne riječi4

Na kraju treba spomenuti naredbe (eng. statement) koje su izgrađene od izjava (eng.
expressions) i temeljni su građevni elementi programa. Izjava je kombinacija vrijednosti,
varijabli i operatora. Primjer naredbi:

print 1+1
moja_placa = min(sve_place)
moja_placa = moja_placa * 9.81
print ';)'

Znači, naredbe su izgrađene od izjava, grupirane naredbe nazivamo blokovima, blokovi


postaju funkcije, funkcije i atributi izgrađuju objekte, objekti izgrađuju module, a više modula
nazivamo biblioteka.
4
izrazi rezervirani od strane Python programskog jezika, ukupno 31

6
3 Instalacija i konfiguracija Python okoline
Za ove vježbe preporuča se upotreba verzije Python 2.7.x, koja se može preuzeti sa https:
//www.python.org/downloads/. Iako postoji i novija 3.x verzija Pythona, za ove vježbe
se zbog kompatibilnosti sa dodatnim modulima, preporuča stabilna 2.7.x verzija. Ukoliko
koristite Linux operativni sustav, Python se može pronaći u službenim repozitorijima vaše
distibucije, ukoliko već nije instaliran.
Instalacija na Windows operativnom sustavu se svodi na preuzimanje odgovarajuće dato-
teke, koja ovisi o arhitekturi (32/64 bita), i pokretanje instalacije.
Nakon instalacije u Start izborniku (Slika 1) se nalazi Python 2.6. Kroz vježbe ćemo koris-
titi IDLE (Python GUI) koji omogućava interakciju s Python interpreterom. IDLE (Slika 3)
također omogućava uređivanje datoteka, tzv. Python skripti, koje mogu jednostavno pokretati
direktno iz sučelja.

Slika 1: Windows Start izbornik Slika 2: IDLE integrirana Python okolina

Pokretanjem IDLEa automatski se pokreće Python interpreter, koji se može prepoznati


po tri znaka >>>. Primjerice kada bi napisali i poslali sljedeći izraz, Python interpreteru,
pritiskom na tipku enter. Interpreter će ga izvršiti i prikazati rezultat:

>>> print 'Prostorne baze podataka'


Prostorne baze podataka
>>>

ili

>>> 1+1
2
>>> a=10
>>> b=5.5
>>> a*b

7
55
>>>

Postoji mnogo uređivača teksta i razvojnih okruženja koja omogućavaju uređivanje Python
koda. Za ovaj kolegij dovoljan će biti ugrađeni IDLE uređivač, koji se pokreće otvaranjem
postojeće Python datoteke ili odabirom File → New window. Na slici 3, prikazan je IDLE
uređivač koji sadrži samo jednu liniju print ``Dobar dan'', te nakon spremanja skripte u
datoteku test.py, pritiskom na tipku F5, interpreter će izvršiti našu skriptu.

Slika 3: IDLE uređivač skripti

4 Osnove Pythona
U ovom dijelu obraditi će se uvjetno izvršavanje, petlje i manipulacija listama, koje će se
intenzivno koristiti kroz kolegij.

4.1 Introspekcija i pomoć


Python omogućava uvid u popis metoda i atributa nekog objekta upotrebom funkcije dir.
Primjerice kada bi željeli saznati koje sve metode i atribute implementira biblioteka os, Python
interpreteru bi poslali sljedeću naredbu:
>>> import os
>>> dir(os)
['chown', 'chroot', 'close', 'closerange', 'confstr', ...]
Vrlo jednostavno pristupamo dokumentaciji objekta ili metoda, korištenjem ugrađene me-
tode help. Na primjer, pomoć za metodu chdir objekta os saznati ćemo izvršavanjem naredbe:
help(os.chdir).

4.2 Uvjetno izvršavanje


Uvjetno izvršavanje omogućava izvršavanje koda ovisno o zadovoljavanju uvjeta. Temelji
se na Booleovoj algebri5 , odnosno istinitim i ne istinitim vrijednostima. Booleova algebra
implementira operacije konjunkcije(AND), disjunkcije(OR) i negacije(NOT), čiji je rezultat
istinita ili ne istinita vrijednost.
5
http://en.wikipedia.org/wiki/Introduction_to_Boolean_algebra

8
Python omogućava korištenje tzv, operatora uspoređivanja čiji je rezultat istinita ili ne
istinita vrijednost. Raspoznaju se sljedeći operatori uspoređivanja: ==, !=, >, <, >= i <=.
Osnovna forma uvjetnog izvršavanja je sljedeća:

if a > 100:
a = a + 10
elif a > 10:
a = a + 1
else:
a = 0

Nakon ključne riječi if definira se uvjet. Uvjeti se povezuju Booleovim operacijama, npr.
(a > 10 and a < 20) or a >= 50. Nakon definicije uvjeta početak novog bloka označava
se znakom :, poslije kojeg se u novom redu blok uvlači praznim prostorom. Ukoliko postoji
potreba zadovoljavanja dodatnih uvjeta koristi se ključna riječ elif, a svi ostali ne zadovoljeni
slučajevi izvršavaju se u bloku definiranom ključnom riječi else.

4.3 Petlja
Petlja omogućava ponovno izvršavanje bloka koda, koje nazivamo iteracija. Petlja se iz-
vršava dok je zadovoljen uvjet, odnosno dok je uvjet istinit. Sljedeći blok koda prikazuje
osnovnu petlju koja odbrojava od 10 do 1:

n = 10
while n > 0:
print n
n = n - 1

U programiranju se često koriste tzv. “beskonačne petlje” za koje se uvjet nikad ne zado-
volji nego se program završava na neki drugi način, npr. kombinacijom tipki CTRL+C.

4.4 Lista
Lista je poredan i indeksiran niz elemenata, što znači da se svakom elementu može pristupiti
preko indeksa. Prvi element liste ima indeks 0, tzv. “zero-based”, drugi element liste ima
indeks 1 itd. Lista može sadržavati različite tipove podataka, npr. ["hello", 2.0, 5, [10,
20]]. Lista se definira uglatim zagradama [ ], a elemente liste odvajaju zarezi.
Pristup nekom članu liste moguć je preko indeksa, primjerice trećem elementu liste pris-
tupiti ćemo na sljedeći način:

lista = ['danas','je','petak',13,2010]
print lista[2]
print len(lista)
print 'danas' in lista
print 'sutra' in lista
del lista[1]

9
Funkcija len vraća koliko lista ima elementa, tzv. dužinu liste, a operator in pripadnost nekog
elementa listi. Funkcija del briše element liste.
Liste omogućavaju odabir podskupa liste, operatorom :, primjerice kada bi željeli podskup
od drugog do trećeg elementa to bi napravili na sljedeći način nova_lista=lista[1:3]. Mo-
guće izostaviti jedan od indeksa, npr. nova_lista=lista[:3] čime bi napravili podskup od
prva tri elementa liste.
Iterator omogućava hodanje po listi, element po element. Sljedeći primjer ispisuje samo
parne brojeve koji se nalaze u nekoj listi:

lista=[1,4,6,2,5,67,24,52,21,31]
for element in lista:
if element % 2 == 0:
print element, ' je paran broj!'

4.5 Rječnik
Jedna od vrlo korisnih struktura podataka u Pythonu je rječnik (eng. dictonary). Za
razliku od lista koje su indeksirane prema rednom broju elementa unutar liste, rječnik je
indeksiran prema ključu. Svaki element rječnika sadrži ključ prema kojem se pretražuje i
vrijednost za taj ključ. Upravo zbog ovoga, ova struktura se još naziva i ključ-vrijednost
struktura. Ključevi su uglavnom brojevi ili string tip podatka dok vrijednost može bili bilo
koji drugi objekt (tip podatka). Rječnici nisu poredani kao što je to slučaj s listama tako
da lokacija elementa unutar rječnika je promjenjiva, za razliku od lista. Vrijednosti ključa
su unikatne unutar jednog rječnika dok vrijednosti ne moraju biti. Ovdje su neki primjeri
rječnika:

rjecnik1 = {'hrvoje' : 1234, 'marko' : 4251, 'ana': 2415}


rjecnik2 = {1:2, 3:4, 'auto1':'ZG-5231-AD', 'OIB':[123123123421, 4839204958384]}
rjecnik3 = {} ## prazni rjecnik
print rjecnik1['ana']
## ispisati će 2415

Element rječnika se upisuje na način da se prvi definira ključ (‘hrvoje’, ‘marko’, ‘ana’), a
nakon toga vrijednosti za pojedine ključeve, u ovo slučaju to su brojevi 1234, 4251 i 2415.
Kod lista smo svakom elementu liste pristupali pomoću rednoga broja unutar same liste,
kod rječnika pristupamo pomoću ključa. U gornjem primjeru tražimo vrijednost rječnika za
ključ ‘ana’. Ukoliko želim dodati neki novi član unutar rječnika, dodajemo ga na način da
jednostavno kreiramo novi ključ sa nekom vrijednosti. Ukoliko taj ključ već postoji unutar
tog rječnika, stara vrijednost će biti izbrisana novom. Ovo također znači da ukoliko kreiramo
rječnik koji sadrži elemente s istim ključem, samo zadnji ključ će biti spremljen.

rjecnik1['ivan'] = 9521 ## dodajemo novi član rječnika


print rjecnik1
## {'ana': 2415, 'hrvoje': 1234, 'ivan': 9521, 'marko': 4251}
del rjecnik1['hrvoje'] ## brijšemo element iz rječnika koji ima ključ `hrvoje'
print rjecnik1
## {'ana': 2415, 'ivan': 9521, 'marko': 4251}

10
Ukoliko želimo saznati koji se sve ključevi nalaze unutar nekog rječnika, to činimo sa
funkcijom keys().

print rjecnik1.keys()
## ['ivan', 'marko', 'ana']
'hrvoje' in rjecnik1.keys()
## False

Ponekad je potrebno iterirati preko svih elemenata nekog rječnika. Najjednostavniji način
je pomoću iterimes() funkcije.

for kljuc, vrijednost in rjecnik1.iteritems():


print kljuc, vrijednost

## ivan 9521
## marko 4251
## ana 2415

4.6 Funkcije
Funkcija je niz naredbi koja izvršava željenu radnju. Funkcija ima zaglavlje i tijelo. Zaglav-
lje funkcije počinje ključnom riječi def nakon koje sijedi naziv funkcije, pa lista parametara
poslije koje slijedi : . Tijelo funkcije je uvučeno kao i svaki drugi blok koda. Bitno je naglasiti
da su parametri i varijable unutar funkcije dostupni samo unutar funkcije. Funkcije koje ne
vračaju vrijednost nazivaju se procedurama. Npr. str() funkcija pretvara integer/decimal u
string.

def ispisi(broj):
print "Broj: " + str(broj)

ispisi(3)

def kvadriraj(broj):
kvadrat=broj*broj
return kvadrat

kvadrati=[kvadriraj(2),kvadriraj(3),kvadriraj(9)]

4.7 Pretvorba tipova podataka


U Pythonu su podržane četiri vrste brojčanih vrijednosti:

• integer ili cjelobrojne vrijednosti (int)

• decimalne vrijednosti (float)

• duge decimalne vrijednosti (long)

11
• kompleksne vrijednosti (complex)

U prethodnom poglavlju smo već vidjeli na koji način možemo pretvoriti decimal/integer
tip podatka u string tip. Ova pretvorba je prilično jednostavna jer se brojevi sami po sebi
mogu napisati kao skup alfanumeričkih znakova tj. string. S druge strane, obrnuti proces, iz
decimal/integer u string ili iz decimal u integer tip podatka je malo složeniji proces. Uzmimo
sljedeće primjere,

>>> x= '2'
>>> y='2.3'
>>> float(x)
2.0
>>> float(y)
2.2999999999999998
>>> int(x)
2
>>> int(y)
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '2.3'
>>> z = 8.62
>>> int(z)
8
>>> float(z)
8.6199999999999992
>>>

Ovdje vidimo da kod pretvaranje brojčane string vrijednosti u decimal/integer nije svejedno
koju vrijednost pretvaramo. Razlog greške je zbog toga što nije moguće jednoznačno odrediti
integer vrijednost od stringa ’2.3’. Također, možemo vidjeti da pretvorba decimal string vri-
jednosti u decimal tip podatka također nije jednostavna. Pretvorba stringa ’2.3’ u decimal kao
rezultat daje 2.2999999999999998. Iako približna vrijednost je 2.3, to nije vrijednost koja je
očekivana. Razlog ovakvog rezultata je izvan domene ovog kolegija te ukoliko vas više zanima
o tome možete pogledati u literaturi ili na internetu pojmove poput Floating Point Arithmetic
ili Floating Point Precision.

12
Sažetak

• uvod u Shapely i Matplotlib biblioteku


• stvaranje prostornih objekata u Shapelyu
• vizualizacija prostornih objekata
5 Uvod u Shapely i Matplotlib
Shapley http://toblerity.org/shapely/manual.html je Python biblioteka za stvara-
nje, upravljanje i analizu ravninskih geometrijskih objekata.
Shapley integrira GEOS biblioteku http://geos.refractions.net/ koja je temelj pros-
torne analize PostGIS prostornog proširenja za PostgreSQL bazu o čemu će biti više riječ u
narednim vježbama. Drugim riječima, pomoću Shapely biblioteke moguće je izvršavati iste
prostorne operacije kao i pomoću PostgreSQL/PostGIS-om, samo bez baze podataka.
S obzirom da je rezultate prostornih najlakše vizulaizirati pomoću nekog grafičkog prikaza,
tokom vježbi koristiti ćemo Matplotlib http://matplotlib.org/ biblioteku. Matplotlib je
Python biblioteka koja omogućava iscrtavanje grafike na računalu ili spremanje u jedan od
grafičkih formata zapisa. U samo nekoliko linija koda moguće je stvoriti grafiku u obliku
grafova i crteža.
Kroz vježbe Matplotlib biblioteku koristiti ćemo samo za osnovnu vizualizaciju te naglasak
vježbi nije na Matplotlib već na Shapely biblioteci.

Slika 4: Shapely i Matplotlib vizualizacija

5.1 Stvaranje prostornih objekata u Shapelyu


Ukoliko ste instalirali sve potrebne biblioteke možete pokrenuti IDLE te početi pisati kod.
U drugoj vježbi prikazati će se kako stvoriti osnovne prostorne objekte te pristupiti njihovim
atributima. Nakon toga te iste objekte ćemo vizualizirati.
# -*- coding: utf-8 -*-
#dodavanje modula koji sadrzi klase geometrija
from shapely.geometry import Polygon, LineString, Point, MultiPoint, \
MultiLineString, MultiPolygon
#dodavnje modula za iscrtavnja
from matplotlib import pyplot

U prvoj liniji koda definirana je kodna stranica koja se koristi, to nije nužno, ali omogu-
ćava lakšu prenosivost koda. Nakon toga se u trenutnu izvršnu okolinu učitavaju moduli i

14
objekti. Specifično učitavamo objekte Polygon, LineString, Point, MultiPoint, … iz biblioteke
shapely.geometry. Da bi neki objekt mogli koristiti, moramo ga (tj. njegovu definiciju) učitati
u trenutnu okolinu izvršavanja programa. U ovom slučaju je to IDLE okolina. Također učitava
se pyplot iz matplotlib biblioteke koji ćemo kasnije koristiti.

#kreiranje dvije tocke pomocu klase Point() iz shapely.geometry modula


tocka1 = Point(4,4)
tocka2 = Point(1,2)

Ovdje smo definirali dvije točke s koordinatama 4, 4 i 1, 2 nekog prostornog sustava. Objekt
Point se inicijalizira s dva parametra x i y koordinatom. Ove vrijednosti smo pridružili
varijablama tocka1 i tocka2.
Na sličan način stvoriti ćemo linijski objekt LineString linija1. LineString objekt kao
parametar uzima listu s koordinatnim n-torkama, u ovom slučaju s dva elementa. Gotovo
identično stvaramo poligon1. Razlika između LineString i Polygon objekta je što su prva i
zadnja koordinata iste u Polygon objektu. U bilo kojem trenutku možemo saznati više o
objektu korištenjem introspekcije ili pomoći, što je opisano u prvoj vježbi.
Objekt MultiPoint je kolekcija više točaka, kao i MultiLineString te MultiPolygon. Postoji
i tzv. GeometryCollection kao skup različitih geometrija, ali se ne koristiti često u praksi jer
neke funkcije se ne mogu izvršavati nad ovim objektom te je vrlo upitna iskoristivost podataka
spremljenih u ovom obliku. GeometryCollection objekte neće stvarati, ali se mogu pojaviti
kao rezultati nekih funkcija.

#slicno kao i s tockama, kreiranje linije i poligona


linija1 = LineString([(1,7),(3,3),(9,4)])
poligon1 = Polygon([(0,4),(1,9),(6,5),(5,2),(0,4)])

#kreiranje kolekcije tocaka (Multipoint)


kolekcijaTocaka = MultiPoint([(1,2),(2,3),(4,5)])

#kreiranje kolekcije linija (MultiLineString)


kolekcijaLinija = MultiLineString([((0, 0),(1,1)),((-1,0),(1,0))])

#kreiranje kolekcije poligona (MultiPolygon)


poligon2 = Polygon([(4,6),(5,3),(10,5),(7,7),(4,6)])
kolekcijaPoligona = MultiPolygon([poligon1, poligon2])

#GeometryCollection postoji kao klasa, ali se ne moze kreirati objekt

5.2 Atributi i funkcije Shapely prostornih objekata


Objekti posjeduju atribute, primjerice linija ima dužinu, poligon površinu, itd. Želimo li
saznati dužinu linije, koristit će se atribut length. Zanimljivo, dužina točke iznosi 0. Također je
moguće mjeriti udaljenost između dva objekta. U tu svrhu koristi se funkcija distance na način
da se kao parametar funkcije distance postavi objekt do kojeg želimo ”mjeriti” udaljenost.
Poligoni imaju površinu, koju saznajemo upotrebom atributa area.

15
#racuananje duzine objekta linija1. Tocka nema duzinu pa ce
#tocka1.lenght vratiti vrijednost 0.0
duzinaLinije1 = linija1.length

#racunanje udaljenosti od tocka1 do tocka2. Takoder je moguce


#mjeriti udaljenost od i do bilo koje drugog geometrijskog objekta.
udaljenost = tocka1.distance(tocka2)

#racuanje povrsine poligona. Tocka i linija nemaju provrsinu


#te ce funkcija vratiti vrijednost 0.0 za objekta linije i tocke
povrsina = poligon1.area

#racunanje graničnog okvira poligona.


#Funkcija će vratiti listu u obliku (minx, miny, maxx, maxy)
granicni_okvir = poligon2.bounds

Slika 5: Granični okvir poligona je prikazan crvenom bojom

Informacija o tome da li je neki objekt “prazan” korisna je kada nakon neke operacije
želimo saznati postoje li rezultati te operacije. Znači, ako tražimo sjecište dvije linije, ukoliko
se te dvije linije sjeku, rezultat će biti točka, u suprotnom biti će “prazna” geometrija točke.
Ispitivanje da li je objekt “prazan” se testira pomoću atributa is_empty.
Pomoću atributa x i y, dolazimo do za točku jedinstvene vrijednosti koordinata X i Y. No
ako pristupimo istim atributima linije ili poligona dobiti ćemo liste x i y koordinata.

#kreiranje "praznog" objekta tocke. Prazni objekt moze biti i


#linija i poligon. Prazni objekt ne sadrzi nikakve vrijednosti
#(koordinate, duzinu, povrsinu ...).
praznaTocka = Point()
praznaTocka.is_empty

16
#ispisuje kojeg je tipa poligon2 objekt.
#Funkcija vraća vrijednost Point, LineString, Polygon, MultiPolygon ...
poligon2.geom_type

#objekt tocke sadrzi atribute x i y


tocka1.x
tocka1.y

Jednakost dva objekta može se utvrditi funkcijom equals, u ovom slučaju napraviti ćemo
kopiju objekta linija1. Linije su identične, pa će i funkcija equals vratiti istinitu vrijednost
(True). Moguće je uspoređivati različite tipove geografskih objekata, ali ako nisu identični,
equals funkcija će vratiti ne istinitu vrijednost (False).

#objekt linije i poligona

#kreiramo kopiju linija1 objekta u svrhu demonstracije


#equals() funkcije
linija1Kopija = LineString(linija1)
#usporedujemo linija1Kopija i linija1 objekt. Funkcija ce vratiti
#True jer to su koordinatno isti objekti.
linija1Kopija.equals(linija1)
#usporedujemo tocka1 i linija1 objekt. Funkcija ce vratiti False
tocka1.equals(linija1)

5.3 Iscrtavanje Shapely prostornih objekata pomoću matplotlib bi-


blioteke
U narednom dijelu koda prikazati će se kako iscrtati netom stvorene objekte uz pomoć
matplotlib biblioteke. Prvo moramo stvoriti “platno” na kojem će se objekti iscrtavati. Defi-
nirati ćemo “platno” veličine 3, 3 inča (standardna dužinska jedinica u matplotlib biblioteci)
razlučivosti 90 točkica po inču (standardni računalni prikaz). Nakon toga potrebno je dodati
novi graf (crtež) na platno, što činimo metodom add_subplot s parametrom 111. Zašto se
koristi ova metoda sa ovim parametrom je izvan domene ovog kolegija. Ukoliko želite, vi-
še o ovoj metodi i kombinacijama parametara kao i drugim metodama, možete pročitati u
službenoj dokumentaciji matplotlib biblioteke.

#iscrtavanje kreiranih objekata


#kreiramo velicinu podrucja gdje ce se iscrtavati geometrija
#figsize(3,3) oznacava velicinu u incima te dpi oznacava
#detaljnost prikaza
fig = pyplot.figure(figsize=(3, 3), dpi=90)
#kreiranje grafa
#add_subplot(111) oznacava da cemo kreirati samo jedan graf,
#ukoliko bi pisalo 211 oznacavalo bi da imamo dva grafa jedan
#ispod drugoga ...
ax = fig.add_subplot(111)

17
Prije nego iscrtamo točke ili objekte moramo pripremiti koordinate u obliku koji očekuje
matplotlib. Srećom postoji funkcija xy koja će vratiti x i y koordinate u obliku liste dužine
dva, odnosno dva elementa, upravo onako kako ih očekuje plot metoda. U primjeru koda
možete vidjeti prvi element liste se sprema u varijabli xLista, a drugi element liste u varijablu
yLista. Nakon toga pozivamo metodu plot kojoj predajemo liste koordinata i definiramo stil.
O stilovima se može više saznati u dokumentaciji, a u ovom primjeru svaka točka se prikazuje
kao crveni kvadrat (”rs” = Red Square).

#s obzirom da modul za iscrtavanje zahtijeva unos liste x koordinata


#i y koordinata odvojeno, funkcija xy razdvaja koordinatu x u
#varijablu xLista, a koodrinatu y u yLista
xLista,yLista = tocka1.xy
#plot funkcija iscrtava tocku tocka1 tako da ju predstavlja kao
#kvadraticni marker u crvenoj boji. Vise o stilovima pogledajte ovdje:
#http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.plot
ax.plot(xLista,yLista,"rs")

Na sličan način se iscrtava linija, no ovdje liniju crtamo plavom isprekidanom crtom.
Poligoni su nešto problematičniji jer se proces iscrtavanja razdvaja u dva dijela. Prvo se
crta unutrašnjost poligona, odnosno ispunjava se, a nakon toga crta obrub. Kako bi iscrtali
poligon moramo iskoristiti njegovu granicu, a do granice dolazimo preko atributa exterior.

#isto kao i kod tocke, u ovom dijelu koda se iscrtava isprekidana


#linija plave boje
xLista,yLista = linija1.xy
ax.plot(xLista,yLista,"b--")

#da bi iscrtali poligon moramo pretvoriti poligon u liniju


#pomocu exterior naredbe
xLista,yLista = poligon1.exterior.xy
#ispunjenost poligona postavljmo u zutu boju sa obrubom crne boje
ax.fill(xLista,yLista,"y")
ax.plot(xLista,yLista, "k-")

#na kraju je to potrebno prikazati na ekranu pomocu show() funkcije


pyplot.show()

#takoder mozemo spremiti graf u datoteku


#pyplot.savefig('vjezba.png')

Na kraju ostaje nam samo prikazati iscrtano, matplotlib ima ugrađeni preglednik koji se
poziva metodom show. Ukoliko sliku želimo iskoristiti na neki drugi način, uvijek je možemo
spremiti u rastersku datoteku, u primjeru je to PNG formata.

5.4 Zadatak 1

Zadatak 1: Napravite najmanje 10 točaka, 10 linija i 10 poligona te ih iscrtajte u


PNG datoteku.

18
NAPOMENA:
Ovaj zadatak je obavezan. Rješenje treba postaviti na e-ucenje na odgovarajuće mjesto.

19
Sažetak

• prostorni odnosi sa Shapely bibliotekom


• prostorni upiti i analize sa Shapely bibliotekom
6 Prostorni odnosi, upiti i analize
U ovoj vježbi prikazati će se koje funkcije omogućavaju određivanje prostornih odnosa
objekata u nekom proizvoljnom koordinatnom sustavu. Za početak stvorit ćemo nekoliko
prostornih objekata: poligone, linije i točke, između kojih će se utvrđivati prostorni odnosi.

Slika 6: Prostorni objekti korišteni u ovoj vježbi

# -*- coding: utf-8 -*-


from shapely.geometry import Polygon, LineString, Point

poligon1 = Polygon([(1,2),(3,4),(6,5),(4,2),(3,3),(1,2)])
poligon2 = Polygon([(4,6),(5,3),(10,5),(7,7),(4,6)])
linija1 = LineString([(3,7),(7,5),(7,2)])
linija2 = LineString([(1,4),(3,4),(6,5),(8,7)])
tocka1 = Point(5,4)
tocka2 = Point(4,3)
tocka3 = Point(2,5)

6.1 Prostorni odnosi


Ukoliko želimo ispitati sadržava li jedan objekt neki drugi, u ovom slučaju da li poligon
sadržava točku, koristit ćemo funkciju contains. Slično tome, ukoliko želimo provjeriti nalazi
li se točka unutar poligona ili nekog drugog objekta, koristi se funkcija within. Primijetite da
funkcije contains i within kao rezultat vraćaju istinu ili ne istinu.

#provjeravamo da li se objekt tocka1 nalazi unutar objekta poligon1.


#Funkcija vraca True jer se objekt tocka1 nalazi unutar

21
#objekta poligon1
poligon1.contains(tocka1)
#objekt tocka3 se na nalazi unutar objekta poligon1 i funckija vraca
#vrijednost False
poligon1.contains(tocka3)

#na isti nacin mozemo provjeravati i pomocu within funkcije


tocka1.within(poligon1)

Želimo li ispitati križa li linija poligon (definiciju križanja potražite u predavanjim) koristit
će se funkcija crosses. Zanimljivo je da linija ne križa samu sebe kao što se može vidjeti u
primjeru. Funkcija disjoint je vrlo korisna, jer omogućava utvrđivanje da li postoji bilo kakav
prostorni odnos između dva objekta.

#naredba vraca True jer linija1 kriza poligon2


linija1.crosses(poligon2)

#naredba vraca False jer linija1 ne kriza samu sebe


LineString(linija1).crosses(linija1)

#naredba vraca True jer linija1 i poligon1 nisu u nikakvom


#prostornom odnosu
linija1.disjoint(poligon1)

Funkcija intersects određuje da li objekt dodiruje granicu ili presijeca unutrašnjost nekog
drugog objekta. Razlikuje se od križanja po tome što križanje provjerava da li se vanjština
jednog objekta preklapa s unutrašnjosti drugog objekta. Intersects će vratiti istinitu ili ne
istinitu vrijednost.
Funkcija touches vratit će istinitu vrijednost ukoliko se granice, dva objekta dodiruju.

#naredba vraca True u oba slucaja jer linija2 dodiruje granicu


#poligon1 i presjeca unutrasnjost poligon2
linija2.intersects(poligon1)
linija2.intersects(poligon2)

#naredba vraca True jer linija2 dodiruje poligon1 bez da ulazi u njega
linija2.touches(poligon1)

#naredba vraca False jer linija2 ulazi u poligon2 ne dodirajuci


#njegovu granicu
linija2.touches(poligon2)

6.2 Prostorne analize i funkcije za procesiranje prostornih objekata


Ukoliko želimo odrediti granicu nekog objekta koristit ćemo funkciju boundary. Boundary
će vratiti objekt niže dimenzije, dakle granica poligona je linija, a granica linije skup toča-
ka, dok je granica točke prazan skup. Funkcija centroid vratiti objekt točke koji predstavlja

22
geometrijski centar poligona. Podsjećam da se geometrijski centar može nalaziti i izvan po-
ligona, primjerice ukoliko imamo poligon oblika tupog trokuta. Ukoliko želim točku koja se
uvijek nalazi unutar poligona, koristiti ćemo funkciju representative_point.

#vraca objekt nize dimenzije. Npr. granica poligona je linija,


#granica linije je skup tocaka, granica tocke je prazan skup
#vratiti ce Multipoint objekt
linija1.boundary
#vratiti ce liniju (LineString)
poligon1.boundary

#funkcija koja racuna geometrijskih centar poligona (objekt tocke)


poligon1.centroid

#funckija koja racuna tocku koja se sigurno nalazi unutar objekta


poligon1.representative_point

Razliku između dva objekta možemo saznati upotrebom funkcije difference. Ukoliko tra-
žimo razliku dva poligona rezultat će biti novi poligon. Tražimo li razliku između poligona i
linije rezultat će biti poligon, ali ako se traži razlika između linije i poligona, rezultat će biti
linija (Multilinija u našem slučaju). Ne postoji univerzalan odgovor koji je krajnji rezultat ove
funkcije jer ovisi koja dva prostorna objekta se uspoređuju.

poligon1.difference(poligon2) #vratiti će poligon, dio od poligon2 koji nije u poligon1

23
poligon2.difference(poligon1) #vratiti će poligon, dio od poligon1 koji nije u poligon2

poligon2.difference(linija1) #vratiti će poligon

24
linija1.difference(poligon2) #vratiti će liniju

Funkcija symmetric_difference vratiti će geometriju koja nije zajednička za oba objekta,


tj. kao da smo napravili razliku prvog, pa razliku drugog i onda ih zbrojili.

poligon2.symmetric_difference(poligon1)

Suprotno od funkcije difference je funkcija intersection, koja će kao rezultat dati zajednički
dio oba prostorna objekta.

linija2.intersection(poligon2) #vratiti ce liniju

25
poligon1.intersection(poligon2) #vratiti ce poligon

Dvije geometrije možemo zbrojiti funkcijom union. No treba biti oprezan oko tipa objekta,
npr. ako se želi napraviti zbroj poligona i linije rezultat će biti kolekcija geometrije. Kao i
kod funkcije difference, krajnji rezultat ovisi o odnosu tih dviju geometrija.

poligon1.union(poligon2) #vratiti ce jedan poligon

26
poligon1.union(linija1) #vratiti ce kolekciju geometija

Ukoliko bi željeli zbrojit više od dvije geometrije, morali bi prvo zbrojiti prvu i drugu, nakon
toga, rezultatu tog zbrajanja dodati treću geometriju itd. Koristeći funkciju unary_union
možemo zbrojiti listu geometrija odjednom.

#prvo ucitamo unary_union funkciju ukoliko nismo na početku


from shapely.ops import unary_union
#vratiti će kolekciju geometrija kao rezultat
kolekcijaGeometrija = unary_union([linija1, linija2, poligon1])

Funkcija buffer će vratiti “tampon zonu” nekog objekta u obliku poligona. Funkcija kreira
novi poligon na određenoj udaljenosti od izvorne geometrije.

linija1.buffer(1) #vratiti ce poligon

tocka1.buffer(0.5) #vratiti ce poligon

27
Funkcija convex_hull će vratiti najmanji poligon koji obuhvaća zadanu geometriju ili ko-
lekciju geometrija.

tocka3.union(poligon2).convex_hull #vratiti ce poligon

Funkcija envelope će vratiti najmanji mogući pravokutnik koji obuhvaća zadanu geometriju
ili kolekciju geometrija

tocka1.union(poligon2).envelope

Ukoliko bi željeli napraviti paralelnu liniju nekom linijskom objektu odmaknutu za određe-
nu udaljenost, možemo iskoristiti funkciju parallel_offset. Ova funkcija kao argument prima
udaljenost novije linije od linijskog objekta te stranu odmaka, gledajuću njezin smjer.

28
#funkcija koja vraća liniju paralelnu nekom linijskom objektu
paralelnaLinija = linija2.parallel_offset(1, 'left')

6.3 Zadatak 2

Zadatak 2: Nad objektima iz prethodnog zadatka (Zadatak 1), napravite po jednu


prostornu operaciju iz ovih vježbi i vizualizirajte ih.

NAPOMENA:
Ovaj zadatak je obavezan. Rješenje treba postaviti na e-ucenje na odgovarajuće mjesto.

29
Sažetak

• učitavanje SHP datoteke pomoću OGR modula


• učitavanje prostornih podataka iz SHP datoteke
• izvršavanje prostornih operacija nad učitanim podacima
• vizualizacija učitanih podataka i rezultata prostornih operacija
7 Obrada SHP datoteka
Ovom vježbom prikazati će se način na koji je moguće učitati prostorne i atributne in-
formacije iz SHP datoteke. Da bi mogli upravljati sa SHP datotekama, potrebno je koristiti
OGR modul koji dolazi zajedno sa instalacijom GDAL bibilioteke.
NAPOMENA:
GDAL biblioteka se koristi za manipulaciju rasterskih prostornih podataka dok se OGR modul za
koristi za manipulaciju vektorskih prostornih podataka.

Slika 7: Katastarski podaci unutar SHP datoteke koja se koristi za ovu vježbu

7.1 Čitanje SHP datoteke koristeći OGR modula


# -*- coding: utf-8 -*-
from shapely.wkb import loads
from osgeo import ogr
from matplotlib import pyplot

U gornjem dijelu koda, iz Shapely modula učitavamo funkciju loads koja nam indirektno
pomaže da pretvorimo OGR prostorni objekt u shapely prostorni objekt. Ovo je potrebno
napraviti jer OGR i Shapely su dva nezavisna modula. Jedan se koristi za učitavanje prostornih
podatka iz vanjskih izvora (OGR) dok drugi se koristi za prostornu analizu i manipulaciju
prostornih podataka (Shapely).
Modul OGR omogućava nam manipulaciju velikim brojem prostornih formata podataka
(poput DXF, GPX, PostgreSQL itd.) upotrebom standardnog programskog sučelja. U ovom
slučaju OGR ćemo koristiti za učitavanje geometrije iz SHP datoteke. Kasnije će se ta geome-
trija pomoću funkcije loads transformirati u format koji odgovara Shapely modulu.
#definica funkcije koja sluzi za crtanje jednog poligona
def crtajPoligon(poligon,graf):

31
xLista,yLista = poligon.exterior.xy
graf.fill(xLista,yLista,"y")
graf.plot(xLista,yLista, "k-")

fig = pyplot.figure(figsize=(4, 4),dpi=180)


ax = fig.add_subplot(111)
pyplot.axis([424021,427021,5037914,5040914])

Ovaj dio koda predstavlja pomoćnu funkciju crtajPoligon koja iscrtava poligone na neku
crtaču površinu tj. na graf. Iako ovaj dio nije nužan, demonstrira kako napraviti reorganizaciju
koda s ciljem boljeg razumijevanja i preglednosti koda.

#kreiramo varijablu datoteka koja sadrzi lokaciju na katastar.shp


#NAPOMENA: lokaciju katastar.shp datoteke podesite tako da odgovara
# lokaciji na disku gdje ste ju spremili.
# PAZITE na dvostruke \ ukoliko radite na Windows operativnom sustavu
datoteka = ogr.Open("d:\\temp02\\katastar.shp")
#varijabla sloj sadrzi sloj katastar koji se nalazi u shape datoteci
sloj = datoteka.GetLayerByName("katastar")

Dokumentaciju za Python funkcionalnost OGR modula možete pronaći u internetu http:


//pcjericks.github.io/py-gdalogr-cookbook/. Također, možemo se poslužiti introspek-
cijom dir(ogr) i ugrađenom Python dokumentacijom help(ime_funkcije). Kroz ove vježbe
pojasniti će se sve funkcije koje su potrebne za uspješno rješavanje zadataka.
Prvo otvaramo datoteku pomoću funkcije Open čiji rezultat spremamo u varijablu datoteka.
Lokaciju na katastar.shp datoteku promijenite tako da odgovara vašem slučaju.
NAPOMENA:
Pripazite na dvostruke \ukoliko radite na Windows operativnom sustavu.
Nakon toga tražimo sloj katastar pomoću funkcije GetLayerByName, kako bi kasnije mogli
manipulirati podacima tog sloja. Ukoliko ne znate naziv sloja u SHP datoteci, sloju možete
pristupiti funkcijom GetLayerByIndex. SHP datoteka će uvijek imati samo jedan sloj. Ova
funkcija ima više smisla kod izvora podataka s više slojeva, primjerice ukoliko bi uzimali
podatke dirketno iz baze poput PostgreSQL.

#uzimamo prvi poligon


cestica = sloj.GetNextFeature()
#petlja koja ce iterirati dok god postoji cestica unutar sloja
while cestica is not None:
#pomocu shapely loads funckije pretvaramo geometriju cestice u
#shapely polygon objekt
geometrijaCestice = loads(cestica.GetGeometryRef().ExportToWkb())
#pozivamo gore definiranu funkciju za crtanje poligona
crtajPoligon(geometrijaCestice, ax)
#primjer izvlacenja atributnih podataka o pojedinoj cestici
kc_broj = cestica.GetFieldAsString(1)
print 'Iscrtavanje cestice ' + kc_broj + ' !'
#uzimamo sljedecu cesticu iz sloja
cestica = sloj.GetNextFeature()

32
Funkcija GetNextFeature čita trenutni objekt iz sloja te se pomiče na sljedeći, odnosno pri
sljedećem pozivanju funkcije GetNextFeature taj sljedeći objekt postaje trenutni. Ovakav način
pristupa objektima (u ovom slučaju katastarskim česticama) nam omogućava iskorištavanje
petlje while. Petlja će se ponavljati sve dok varijabla cestica ima vrijednost. Ovaj način
iteracije objekata je vrlo čest u programiranju.
U navedenom kodu, prvo dohvaćamo geometriju objekta funkcijom GetGeometryRef(),
nakon toga tu geometriju izvozimo u WKB format (Well Known Binary) pomoću funkcije
ExportToWkb. Geometriju u WKB formatu prosljeđujemo funkciji loads iz Shapely modula,
koja vraća geometriju čestice u formatu iskoristiv za iscrtavanje. Ovi koraci su potrebni da bi
geometriju iz OGR formata pretvorili u shapely format. Tek nakon što geometriju pretvorimo
u shapely format, možemo ju iskoristiti za prostorne funkcije i operacije koje dolaze sa Shapely
modulom.
Sljedeći korak je pozivanje prethodno pripremljene funkcije za crtanje poligona crtajPoligon
kojoj kao argumente postavljamo varijable geomtriju geometrijaCestice i površinu za crtanje
ax. Nakon toga uzimamo sljedeći objekt iz sloja, a petlja se ponavlja.
Funkcijom GetFieldAsString(1) izvlačimo podatke o pojedinoj čestici na prvoj (1) koloni u
atributnoj tablici, u našem slučaju je to kolona KC_BROJ. SHP datoteka sadrži više kolona.
Ako bi željeli saznati podatke o općini pojedine čestice umjesto 1 upisali bi 2.
Pomoću Destroy funkcije “uništavamo” objekt datoteka. Ovo nije toliko bitno u ovom
slučaju, ali je dobra praksa uništiti objekte koji pokazuju prema datoteci ili na bazu.

#"unistavanje" objekta koji sadrzi lokaciju prema datoteci


datoteka.Destroy()

Za kraj pozivamo funkciju za crtanje, koja prikazuje čestice učitane iz SHP datoteke.

#iscrtavamo cestice
pyplot.show()

7.2 Resetiranje petlje


Napomenuli smo da pomoću funkcije GetNextFeature pomičemo trenutni objekt koji obra-
đujemo na sljedeći koji se nalazi unutar SHP datoteke. Kada više nema objekata unutar SHP
datoteke, petlja završava i kod se nastavlja izvršavati. Problem nastane u trenutku kada želi-
mo ponovo čitati istu datoteku unutar istog koda. S obzirom da trenutni objekt više ne postoji
jer smo došli do kraja datoteke, potrebno je “resetirati” datoteku na početak tj. pomaknuti
kursor na početak. To se radi pomoću funkcije ResetReading.

# -*- coding: utf-8 -*-


from shapely.geometry import Polygon
from shapely.wkb import loads
from osgeo import ogr

datoteka = ogr.Open("../katastar.shp")
sloj = datoteka.GetLayerByName("katastar")
kc1289Geometrija = ''
cestica = sloj.GetNextFeature()

33
while cestica is not None:
if cestica.KC_BROJ == '1289':
kc1289Geometrija = loads(cestica.GetGeometryRef().ExportToWkb())
cestica = sloj.GetNextFeature()

sloj.ResetReading()
cestica = sloj.GetNextFeature()

while cestica is not None:


geometrijaCestice = loads(cestica.GetGeometryRef().ExportToWkb())
if kc1289Geometrija.touches(geometrijaCestice):
print 'Cestica ' + cestica.KC_BROJ + ' dodiruje cesticu 1289!'
cestica = sloj.GetNextFeature()

datoteka.Destroy()

U ovom primjeru je prikazano na koji način se koristi ResetReading funkcija. Prvo smo
pomoću jedne petlje pronašli česticu 1289 te ju spremili u varijablu kc1289Geometrija. Nakon
toga smo morali resetirati kursor na početak jer smo došli do kraja datoteke. Drugom petljom
smo tražili koje čestice se dodiruju s česticom 1289.

7.3 Zadatak 3

Zadatak 3: Riješite sljedeće zadatke koristeći Shapely, OGR i matplotlib module.


Za rješavanje zadataka koristite datoteku katastar.shp. Vizualizirajte
(koristeći matplotlib) konačni rezultat kod svakog zadatka, ukoliko je
to moguće.

NAPOMENA:
Rješenja ovih zadataka biti će objašnjenja na narednim vježbama. Izrada ovog zadatka nije obavezna,
već služi kao samostalna vježba dosada naučenoga te kao priprema za kolokvij. Stoga, preporučeno je
da samostalno izradite ove zadatke prije nego dobijete rješenja od asistenata.

1. Odrediti broj čestica koje imaju površinu veću od 300

2. Odrediti broj čestica koje presijeca linija definirana točkama 425345,5039528 i 425466,5039527

3. Odredi kc_broj čestice s najvećom površinom

4. Na koordinati 425692,5039490 prevrnula se cisterna, potrebno je odrediti kc_broj čestice


koja je najviše površinski zahvaćena ako znamo da je radijus izlijevanja 25m

Dodatni zadaci:

1. Provjeriti postoje li čestice (i koje su to) koje ne sadrže vlastiti centroid

2. Ispisati kc_broj čestice s najdužim opsegom

3. Ispisati kc_broj čestice koja je najbliža točci s koordinatama 425209, 5039040

34
4. Ispisati sve čestice koje se nalaze (ili presijecaju) buffera 100 metara linije definirane
točakama 425345,5039528 i 425466,5039527

5. Izračunajte površinu i opseg buffera (20) linije definiranu točakama 425345,5039528 i


425466,5039527

6. Izračunajte koja je najveća udaljenost između dva poligona u zadanom setu podataka i
ispišite dva najudaljenija poligona

7. Izračunajte dužinu ruba buffera (50) linije definirane točakama 425345,5039528 i 425466,5039527

8. Ispišite koja je čestica najbliža čestici s brojem 1210/2.

9. Ispišite koji je zbroj svih površina čestica u zadanom setu podataka

10. Ispišite kc_broj čestice u kojoj se nalazi točka s koordinatama 425023,5039402

35
Sažetak

• čitanje atributa vezanih uz pojedinu geometriju


• definiranje filtera (WHERE)
• linearno referenciranje
8 Atributi i filteri nad SHP datotekama
8.1 Čitanje atributnih podataka SHP datoteka
U prijašnjoj vježbi bio je prikazan način čitanja SHP datoteka. Unutar te vježbe prikazan
je jedan od načina čitanja atributa koji opisuju određenu geometiju (GetFieldAsString(0)).
Ovom vježbom prikazati će se na koji način se još može pristupiti atributima.

from shapely.geometry import Polygon


from shapely.wkb import loads
from osgeo import ogr

datoteka = ogr.Open("../podaci/katastar.shp")
sloj = datoteka.GetLayerByName("katastar")

cestica = sloj.GetNextFeature()

while cestica is not None:


geometrijaCestice = loads(cestica.GetGeometryRef().ExportToWkb())
kc_broj = cestica.KC_BROJ
ko_naziv = cestica.GetField('KO_NAZIV')
print 'Cestica s oznakom ' + kc_broj + ' unutar opcine ' \
+ ko_naziv + ' ima ' + str(geometrijaCestice.area) + ' m2.'
cestica = sloj.GetNextFeature()

datoteka.Destroy()

Ovaj dio koda je vrlo sličan onome u prijašnjoj vježbi, samo umjesto da čitamo vrijednost
atributa prema mjestu na kojem se nalazi unutar tablice (GetFieldAsString(0)), ovdje ju či-
tamo dirketno putem imena polja. Broj čestice dobivamo direktnim pozivanjem imena polja
nad OGR objektom čestice,a opcinu pomoću GetField funkcije. Sva tri načina su ispravna.
str() funkciju smo koristili jer rezultat funkcije area je brojčana vrijednost, a potreban nam
je string.

8.2 Filtriranje atributnih podataka


Ako pogledamo sve dosadašnje primjere, svi u prilikom čitanja SHP datoteke čitali svaki
objekt koji se nalazi unutar te datoteke. Ovaj način je ispravan, ali ponekad nije potrebno
prelaziti kroz sve objekte već samo one koji su nam potrebni. U sljedećem primjeru možemo vi-
djeti na koji način možemo pročitati samo određene objekte unutar SHP datoteke. Primjerice,
ako želimo samo česticu čija je oznaka 4190/11 iz opcine Karlovac II.

from shapely.geometry import Polygon


from shapely.wkb import loads
from osgeo import ogr

datoteka = ogr.Open("../podaci/katastar.shp")
sloj = datoteka.GetLayerByName("katastar")

37
sloj.SetAttributeFilter('kc_broj = "4190/11" AND ko_naziv = "Karlovac II"')
cestica = sloj.GetNextFeature()
geometrijaCestice = loads(cestica.GetGeometryRef().ExportToWkb())
print 'Opseg cestice s oznakom 4190/11 je ' \
+ str(geometrijaCestice.length) + " m."

datoteka.Destroy()

SetAttributeFilter() funkcija kao parametar uzima string koji se sastoji od WHERE uvjeta
(podsjetite se kolegija Baze podataka i SQL WHERE uvjeta).

9 Linearno referenciranje
Linearno referenciranje je metoda definiranja objekta u prostoru pomoću negove udalje-
nosti duž nekog linijskog objekta. Najbolji primjer ovoga bi bila cesta i kilometarska oznaka
na cesti. Ukoliko kažemo da se nešto nalazi na 10-tom kilometru od Zagreba na cesti A1 te
ukoliko imamo liniju ceste A1 u nekom koordinatnom sustavu, možemo dobiti točnu lokaci-
ju (koordinatu) tog objekta. Linearno referenciranje je moguće samo na linijskim (krivulje)
objektima.
Uzmimo liniju iz prethodnih vježbi te odredimo koordinatu točke koja se nalazi na 3 metra
od početka te linije (pod pretpostavkom da su koordinate linije također u metrima).

linija2 = LineString([(1,4),(3,4),(6,5),(8,7)])
tocka_na_3m = linija2.interpolate(3)
print tocka_na_3m.wkt
#dobijemo POINT (3.948683298050514 4.316227766016838)

print linija2.length
#dobijemo 7.99070478491

Ukoliko bi zadana udaljenost od početka bila veća nego što je ukupna dužina cijele linije,
kao rezultat bi dobili zadnju točku bez obzira na zadanu vrijednost. Također, ukoliko bi za
udaljenost unijeli vrijednost od 0, dobili bi početnu točku linije.

38
tocka_na_10m = linija2.interpolate(10)
print tocka_na_10m.wkt
#dobijemo POINT (8 7)

tocka_na_0m = linija2.interpolate(0)
print tocka_na_0m.wkt
#dobijemo POINT (1 4)

Ovo je jedan od načina koji je moguće dobiti koordinatu točke pomoću linearnog referen-
ciranja. Drugi način je da umjesto da upisujemo točnu vrijednost udaljenosti, da upišemo
normaliziranu vrijednosti tj. vrijednost od 0 do 1. Vrijednost 0 označava početak linije, a 1
kraj linije. Uzmimo da želim izračunati koordinatu točke točno na polovici linije. Umjesto da
računamo na kojoj je udaljenosti točno polovica linije, možemo tu vrijednost dobiti pomoću
normalizirane vrijednosti tj. u ovom slučaju 0.5 .

tocka_na_polovici = linija2.interpolate(0.5, normalized=True)


print tocka_na_polovici.wkt
#dobijemo POINT (4.89295748844936 4.63098582948312)

tocka_na_10posto = linija2.interpolate(0.1, normalized=True)


print tocka_na_10posto.wkt
#dobijemo POINT (1.799070478491457 4)

tocka_na_kraju_linije = linija2.interpolate(1, normalized=True)


print tocka_na_kraju_linije.wkt
#dobijemo POINT (8 7)

39
Slika 8: Točka na 10% udaljenosti od početka linije (plava) i točka na kraju te linije (zelena).

40
Sažetak

• čitanje SHP datoteka pomoću Fiona modula


• stvaranje novih SHP datoteka
• definiranje atributa novih SHP datoteka
• zapisivanje prostornih podataka
10 Uvod u modul Fiona
U poglavlju 7 ste vidjeli na koji način je moguće čitati SHP datoteke pomoću GDAL/OGR
python modula. Ovaj modul je učinkovit, ali način na koji se mora koristiti nije intuitivan.
U ovoj vježbi biti će prikazan jednostavniji i intuitivniji način čitanja i pisanja SHP datoteka
pomoću Fiona modula. Fiona je python modul za čitanje i pisanje OGR podržanih formata.

10.1 Čitanje SHP datoteke koristeći Fiona modul


Sljedeći kod prikazuje čitanje SHP datoteke katastra kao i u poglavlju 7, samo ovoga puta
koristeći Fiona modul.
# -*- coding: utf-8 -*-
import fiona
from shapely.geometry import shape
from matplotlib import pyplot

fig = pyplot.figure(figsize=(4, 4),dpi=180)


ax = fig.add_subplot(111)

def crtajPoligon(poligon,graf):
xLista,yLista = poligon.exterior.xy
graf.fill(xLista,yLista,"y")
graf.plot(xLista,yLista, "k-")

with fiona.open('../katastar.shp', 'r', encoding='UTF-8') as datoteka:


for cestica in datoteka:
geometrijaCestice = shape(cestica['geometry'])
atributiCestice = cestica['properties']
crtajPoligon(geometrijaCestice, ax)
print 'Cestica s oznakom ' + atributiCestice['KC_BROJ'] + \
' unutar opcine ' + atributiCestice['OPCINA'] + \
' ima ' + str(geometrijaCestice.area) + ' m2.'

pyplot.show()

Kao i do sada, prvo učitavamo potrebne module, fiona, shapely i matplotlib. Nakon toga
definiramo područje gdje će se iscrtatvati čestice te pomoćnu funkciju crtajPoligon za crtanje
svake pojedine čestice. Za razliku od dosadašnjeg način otvaranja datoteka, ovdje koristimo
praktičniji način pomoću with izraza. Pomoću njega lakše kontroliramo učitavanje datoteka,
u ovom slučaju SHP datoteke. Ovo nije specifično za Fiona modul već za Python programski
jezik. Varijabla datoteka postaje iterator koji je moguće iterirati kao što je prikazano u
prijašnjim vježbama na listama. Ostatak koda je identičan kao i u poglavlju 7. Odmah se
vidi koliko je jasnije napisan kod i jednostavniji za čitati.

10.2 Stvaranje nove SHP datoteke


Iako i OGR modul ima mogućnosti stvaranja novih SHP datoteka, način na koji se on
mora koristiti je neintuitivan. Umjesto njega, koristiti ćemo Fiona modul koji je jednostavniji

42
i intuitivniji.

# -*- coding: utf-8 -*-


import fiona
from shapely.geometry import mapping, Point

nova_schema = { 'geometry': 'Point', 'properties': { 'naziv': 'str' } }


with fiona.open('nova_datoteka.shp', 'w', encoding='UTF-8', schema = nova_schema, \
driver = "ESRI Shapefile") as datoteka:
geomtocka = Point(276,443)
nova_tocka = {}
nova_tocka['geometry'] = mapping(geomtocka)
nova_tocka['properties'] = {'naziv' : 'Moja prva tocka'}
datoteka.write(nova_tocka)

geomtocka = Point(300,440)
nova_tocka = {}
nova_tocka['geometry'] = mapping(geomtocka)
nova_tocka['properties'] = {'naziv' : 'Moja druga tocka'}

datoteka.write(nova_tocka)

Ovdje je prikazan jednostavan primjer stvaranja nove SHP datoteke nova_datoteka.shp


koja sadrži dvije točke. Prvo definiramo schemu u obliku rječnika kako će izgledati struktura
nove SHP datoteke. U ovom slučaju to je SHP koji ima Point tip geometrije sa samo jednim
atributom naziv. U sljedećem redu otvaramo novu datoteku pomoću fiona.open funkcije koja
kao argumente prima:
• naziv datoteke

• način otvaranja, u ovom slučaju to je “w” što označava zapisivanje

• kodna stranica, u ovom slučaju to je “UTF-8”

• prethodno definiranu schemu

• koji je format novostvorene datoteke, u ovom slučaju to je SHP, ali može biti bilo koji
drugi OGR podržani format
Unutar with izraza, definirane su dvije shapely točke sa koordinatama (276, 443) i (300,440)
te su spremljene u varijablu geomtocka. Ukoliko želimo dodati novi zapis unutar nove SHP
datoteke moramo kreirati novi rječnik koji će sadržavati geometriju zajedno sa atributima.
Cilj je napraviti rječnik koji će imati strukturu u obliku GeoJSON-a. Koristeći mapping
funkciju, pripremamo shapely geometriju za GeoJSON format koji zahtijeva fiona modul.
Pomoću varijable datoteka zapisujemo (write) rječnik koji smo prethodno napravili, unutar
SHP datoteke. Nakon što izvršavanje koda izađe iz with bloka, varijabla datoteka se automatski
zatvara te ne moramo ju posebno zatvarati kao što je to bio prije slučaj kada nismo koristili
with izraz.
Ovdje smo vidjeli vrlo jednostavan primjer stvaranja nove SHP datoteke. U sljedećem
primjeru biti će prikazan primjer stvaranja nove SHP datoteke koristeći podatke iz postojeće

43
SHP datoteke. Iz datoteke katastar.shp izvući ćemo samo čestice koje imaju broj čestice ”897”,
”898” i ”899” te ih spremiti u datoteku dio_katastra.shp.

# -*- coding: utf-8 -*-


import fiona

with fiona.open('../katastar.shp', 'r', encoding='UTF-8') as datoteka:


with fiona.open('dio_katastra.shp', 'w', encoding='UTF-8', schema=datoteka.schema, driver=
for cestica in datoteka:

if cestica['properties']['KC_BROJ'] in ("897", "898", "899"):


out_datoteka.write(cestica)

Ovdje možemo vidjeti da se koriste dva with izraza, jedan kojim otvaramo postojeću da-
toteku (katastar.shp) i drugi za novu datoteku (dio_katastra.shp). Unutar drugog with izraza
iteriramo preko svih postojećih čistica i tražimo samo one koje imaju broj čestice ”897”, ”898”
ili ”899”. Možemo primjetiti da ne moramo stvoriti novi rječnik jer varijabla cestica je rječnik
(u GeoJSON obliku) te ju možemo direktno spremiti u novu datoteku.

44

You might also like