Apr
29
pgDIJKSTRA 2-way
Filed Under PostGIS | 3 Comments
Dari milis mapserver-id seputar fungsi pgDijkstra untuk routing 2-arah. Udah agak lama juga sih tapi sebenarnya pengen dicoba dulu sebelum diposting di sini. Cuma karena kesibukan yang sangat saat ini, ditumpahkan apa adanya dulu deh ![]()
Sekedar mau menambahkan. pgdijkstra sebenarnya bisa dipakai untuk perhitungan jalan searah.
Caranya field cost dan reverse_cost keduanya diisi.
Untuk arah yang tidak bisa dilalui diberi nilai yang besar, mis. ditambahkan 1000000.
Untuk jelasnya bisa baca di sini
Tutorial dalam link di atas menggunakan pgRouting, tapi cara yang sama bisa diterapkan pada pgdijkstra. Saya sendiri sudah mencoba cara ini pada pgdijkstra. Cuma untuk display pathnya, fungsi shortest_path_as_geometry yang ada pada pgdijkstra perlu sedikit dimodifikasi karena fungsi yang diberikan tidak memperhitungkan reverse_cost untuk menghasilkan pathnya.
Satu hal yg perlu diperhatikan arah arc mengikuti arah digitize. Ini yang agak repot krn adakalanya data jalan tidak di-digitize mengikuti arah jalan sebenarnya. Saya sendiri waktu mau menerapkan jalan 1-arah dg cara di atas, terpaksa mencek arah digitize dari shapefile yang ada. Cukup repot, lebih mudah kalo digitize sendiri datanya mengikuti arah jalan yg benar.
Menyambung posting saya sebelumnya, berikut saya kirimkan fungsi PL/pgSQL untuk menampilkan shortest path dg memperhitungkan reverse_cost. Fungsi-fungsi ini dimodifikasi dari modul pgDijkstra dari Sylvain Pasche. Untuk menampilkan shortest path dg memperhitungkan reverse_cost digunakan fungsi shortest_path_as_geometry_dir(). Penggunaannya sama persis dengan fungsi shortest_path_as_geometry() yang asli (lihat README_dijkstra_pgsq.txt dari paket modul pgDijkstra). Fungsi shortest_path_as_geometry_dir() memanggil fungsi shortest_path_as_geometry_internal_id_dir(), yg merupakan modifikasi dari shortest_path_as_geometry_internal_id(). Di fungsi inilah letak perbedaannya. Dalam fungsi shortest_path_as_geometry_internal_id_dir() fungsi shortest_path(sql text, source_id integer, target_id integer, directed boolean, has_reverse_cost boolean) dipanggil dg argumen directed = true dan has_reverse_cost = true.
Saya rasa cukup penjelasannya. Selanjutnya bisa lihat langsung kedua fungsi di bawah.
Selamat mencoba.
Thanks,
Ardi
-- Function: shortest_path_as_geometry_dir(geom_table “varchar”, geom_source anyelement, geom_target anyelement) CREATE OR REPLACE FUNCTION shortest_path_as_geometry_dir(geom_table “VARCHAR”, geom_source anyelement, geom_target anyelement) RETURNS SETOF geoms AS $BODY$ DECLARE r RECORD; source int4; target int4; path_result RECORD; v_id INTEGER; e_id INTEGER; geom geoms; BEGIN FOR r IN EXECUTE ‘SELECT id FROM ‘ || quote_ident(geom_table) || ‘_vertices WHERE geom_id = ‘ || quote_literal(geom_source) LOOP source = r.id; END LOOP; IF source IS NULL THEN RAISE EXCEPTION ‘Can”t find source edge’; END IF; FOR r IN EXECUTE ‘SELECT id FROM ‘ || quote_ident(geom_table) || ‘_vertices WHERE geom_id = ‘ || quote_literal(geom_target) LOOP target = r.id; END LOOP; IF target IS NULL THEN RAISE EXCEPTION ‘Can”t find target edge’; END IF; FOR geom IN SELECT * FROM shortest_path_as_geometry_internal_id_dir(geom_table, source, target) LOOP RETURN NEXT geom; END LOOP; RETURN; END; $BODY$ LANGUAGE ‘plpgsql’ VOLATILE STRICT; ALTER FUNCTION shortest_path_as_geometry_dir(geom_table “VARCHAR”, geom_source anyelement, geom_target anyelement) OWNER TO postgres;
-- Function: shortest_path_as_geometry_internal_id_dir(geom_table “varchar”, source int4, target int4) CREATE OR REPLACE FUNCTION shortest_path_as_geometry_internal_id_dir(geom_table “VARCHAR”, source int4, target int4) RETURNS SETOF geoms AS $BODY$ DECLARE r RECORD; path_result RECORD; v_id INTEGER; e_id INTEGER; geom geoms; BEGIN FOR path_result IN EXECUTE ‘SELECT vertex_id, edge_id FROM shortest_path(”SELECT id, source, target, cost, reverse_cost FROM ‘ || quote_ident(geom_table) || ‘_edges ”, ‘ || quote_literal(source) || ‘ , ‘ || quote_literal(target) || ‘ , TRUE, TRUE) ‘ LOOP v_id = path_result.vertex_id; e_id = path_result.edge_id; FOR r IN EXECUTE ‘SELECT gid, the_geom FROM ‘ || quote_ident(geom_table) || ‘ WHERE edge_id = ‘ || quote_literal(e_id) LOOP geom.gid := r.gid; geom.the_geom := r.the_geom; RETURN NEXT geom; END LOOP; END LOOP; RETURN; END; $BODY$ LANGUAGE ‘plpgsql’ VOLATILE STRICT; ALTER FUNCTION shortest_path_as_geometry_internal_id_dir(geom_table “VARCHAR”, source int4, target int4) OWNER TO postgres;
Apr
1
PostGIS Routing (bag.2)
Filed Under MapServer, PostGIS | 4 Comments
Lanjutan tutorial sebelumnya…..
Ketujuh, mapfile dengan menggunakan fungsi
shortest_path_as_geometry(’nama_table’,source_oid,target_oid):
CONNECTIONTYPE postgis CONNECTION "host=localhost dbname=roads user=routing password=password" DATA "the_geom from ( SELECT gid, the_geom from shortest_path_as_geometry('route', 1, 4552) ) as route using unique gid using srid=-1"
Catatan: untuk menampilkan hasil routingnya, hanya dengan memanggil fungsi shortest_path_as_geometry() dengan parameter nama_tabel (dalam hal ini tabel ‘route’) [koma] source_id sebagai titik awal berangkat routing dilihat pada kolom source_id di tabel ‘route’ dan [koma] target_id sebagai titik akhir atau tujuan routing dilihat pada kolom target_id di tabel ‘route’.
Hasilnya seperti di bawah ini:

Dengan hasil zooming untuk melihat lebih detail rute terpendek yang ditempuh:

Kedelapan,, rangkuman perintah sql yang dapat dibuat menjadi satu bentuk file (misalkan routing_full) setelah postgis, dijkstra dan data sql telah Anda masukkan berisi:
CREATE TABLE route (gid int UNIQUE, source_id int, target_id int, edge_id int) WITH OIDS; SELECT AddGeometryColumn('route', 'the_geom', -1, 'MULTILINESTRING', 2 ); INSERT INTO route (gid, the_geom) (SELECT gid, the_geom FROM jalanbandung); SELECT assign_vertex_id('route', 1); SELECT create_graph_tables('route', 'int4'); SELECT update_cost_from_distance('route');
dan jalankan dengan perintah:
C:\PgSQL > psql -U routing -d roads -f routing_full.sqltunggu dan database routing siap digunakan ![]()
Kesembilan, untuk tampilan yang dinamis, Anda dapat merubah source_id dan target_id pada script .map sesuai dengan masukan dari web. Caranya dapat dilihat pada tutorial sebelumnya
Kesepuluh, Selamat Mencoba.
Apr
1
PostGIS Routing (bag.1)
Filed Under MapServer, PostGIS | 2 Comments
Pernah lihat ato nyoba aplikasi yahoo maps?
Saat kita mencari arah atau jalur terpendek dari satu lokasi ke lokasi lainnya, marker jalan muncul sebagai penunjuk arah jalur terpendek yang harus kita tempuh. Aplikasi ini menggunakan metoda Vertex Simplication dengan menghitung jarak terpendek. Sampai saat ini, untuk menangani datanya dari database postgresql yang kita simpan dipakai diprogram pgDIJKSTRA/pgRouting dari PostLBS. Ini sebenarnya hasil oprekan yang sudah cukup lama dan dilakukan di atas Windows menggunakan fungsi pgDijkstra, PostgreSQL 8.1.0 dan tidak berjalan pada PostgreSQL 8.0. Awalnya sih dari melihat dari dokumen yang dibawa oleh Pak Hadi, aku jadi tertarik kenapa ada error di function PostgreSQL-nya.
Kita coba menggunakan database roads dengan database username routing.
Baiklah, catatan yang pertama dimulai dari:
Pertama, pastikan pada database telah terinstall postgis. Bisa dengan installer yang disediakan pada windows atau sistem operasi lainnya.Untuk melihat apakah sudah terinstall, pada database ada table geometry_columns (registrasi data geometry tiap table) dan spatial_ref_sys sebagai projection table-nya.
*update : Bila menggunakan installer windows v8.2.x sudah terinstall otomatis dan sudah terdapat template postgis. Kita hanya membuat database berdasarkan template ini.
Bila belum terinstall ataupun terbuat templatenya, silahkan lihat postingan sebelumnya. Hanya saja secara default, kepimilikan fungsi dan kedua tabel oleh database postgres. Untuk merubahnya kita lakukan perintah:
C:\PgSQL> psql -U postgres -d roads psql> ALTER TABLE geometry_columns OWNER TO routing; psql> ALTER TABLE spatial_ref_sys OWNER TO routing;
Kedua, masukkan data jalan anda. Misalkan jalanbandung.sql
C:\PgSQL > psql -U routing -d roads -f jalanbandung.sqlCatatan: Pada beberapa type mapserver, dibutuhkan OID table yang mengandung data geometri sedangkan default postgresql 8.1 yang dicoba default-nya without oids. Ubah table Anda memakai OIDS dengan mengedit file SQL Anda pada bagian CREATE TABLE namatable ( ….) WITH OIDS;
Ketiga, masukkan fungsi dijkstra:
C:\PgSQL> psql -U postgres -d roads -f dijkstra.sql C:\PgSQL> psql -U postgres -d roads -f dijkstra_postgis.sql
Catatan: Pada dijkstra.sql aku berhasil menemukan bug kecil terhadap fungsi create_graph_tables nantinya.
Oleh karena itu perlu diedit sedikit pada bagian :
"CREATE OR REPLACE FUNCTION create_graph_tables" // temukan di bagian bawahnya yang bertuliskan: EXECUTE 'CREATE TABLE ' || edges_table || ' (id serial, source int, target int, ' || 'cost float8, reverse_cost float8, UNIQUE (source, target))'; // ubah menjadi EXECUTE 'CREATE TABLE ' || edges_table || ' (id serial, source int, target int, ' || 'cost float8, reverse_cost float8) WITH OIDS';
Catatan: Belum dicoba pada fungsi yang terbaru
Keempat, buat satu table baru sebagai tempat hasil routing kita. Misalkan saja dengan nama table route. Caranya dengan membuat satu file sql baru route.sql dengan tabel isian berasal dari jalanbandung. File route.sql berisi:
CREATE TABLE route (gid int UNIQUE, source_id int, target_id int, edge_id int) WITH OIDS; SELECT AddGeometryColumn('route', 'the_geom', -1, 'MULTILINESTRING', 2 ); INSERT INTO route (gid, the_geom) (SELECT gid, the_geom FROM jalanbandung);
atau bisa dilakukan tanpa membuat file route.sql dengan mengetikkan di konsol pgsql dengan mengetikkan terlebih dulu:
C:\PgSQL> psql -U routing roadsdan untuk mengeksekusi route.sql kita berikan perintah:
C:\PgSQL> psql -U postgres -d roads -f route.sqlCatatan: Tabel ini bertujuan untuk menempatkan data gid dan data geometri dari tabel kita yang sebenarnya identik tanpa mengikutkan informasi dari kolom lain.Kita tidak bereksperimen dengan tabel data melainkan pada tabel route ini. Bisa Anda lihat isi tabel ini terdiri dari kolom: || gid || source_id || target_id || the_geom || dengan source_id, target_id dan edge_id masih kosong. Di sinilah peran fungsi dijkstra yang kita install tadi akan bermain.
Kelima, kolom source_id dan target_id pada tabel route dengan mengetikkan perintah sql:
C:\PgSQL> psql -U routing roads psql> SELECT assign_vertex_id('route', 0.000001);
Script ini akan berjalan tergantung ketelitian verteks yang Anda inginkan (di atas menggunakan 0.000001 satuan) dan besarnya banyaknya data Anda. Semakin teliti (misalnya 0.01 satuan) maka script akan berlangsung semakin lama. Hasilnya akan disimpan pada kolom source_id dan target_id tabel route dengan membuat id dan data geometri pada tabel baru vertices_tmp.
Catatan: Berdasarkan hasil percobaan, prosedur ini hanya bisa dijalankan sekali.Apabila Anda merasa gagal melakukannya (source_id,target_id pada tabel route masih kosong begitu juga tabel vertices_tmp) Anda harus menghapus database Anda dan mengulangi dari awal.Ini disebabkan karena saat melakukan assignment antara tabel route dan vertices_tmp, fungsi mencatat oid tabel vertices_tmp yang pertama kali dibuat. Sedangkan apabila prosedur ini diulangi, oid tabel vertices_tmp tentu saja sudah berubah. Namun bila ada saran dan masukan yang lebih berguna, aku sih sangat berterima kasih ![]()
Keenam, kolom edge_id pada tabel route masih kosong. Isikan dengan mengetikkan perintah sql:
C:\PgSQL> psql -U routing roads psql> SELECT create_graph_tables('route', 'int4'); // Script ini selain mengisi kolom edge_id, // juga akan membuat 2 tabel baru: route_edges dan route_vertices. // Sekarang lihat isi dari tabel route_edges. psql> SELECT * FROM route_edges LIMIT 3;
akan menghasilkan kira-kira seperti ini:
id | source | target | cost | reverse_cost ---+-------+-------+------+-------------- 1 | 1 | 2 | | 2 | 3 | 3 | | 4 | 2 | 2 | | (3 rows)
Untuk mengisi kolom cost sebagai hasil perhitungan besar jarak per path, gunakan perintah sql:
SELECT update_cost_from_distance('route'); SELECT * FROM route_edges LIMIT 3;
akan menghasilkan:
id | source | target | cost | reverse_cost ---+-------+-------+-------------------+-------------- 1 | 1 | 2 | 6857.46585793103 | 2 | 3 | 3 | 37349.9592156392 | 4 | 2 | 2 | 14040.5673116933 | (3 rows)
Bersambung biar gak kepanjangan…
Mar
31
PostGIS Sample
Filed Under PostGIS | 4 Comments
PostGIS Dynamic Input Dengan Mapserver CGI Mode
Pada script .map Anda, mungkin menggunakan koneksi PostGIS untuk mengakses data dan geometry. Pertanyaan yang muncul, bagaimana pada data yang ingin kita tampilkan bersifat dinamis. Misalnya saja untuk klasifikasi peta dalam NQuery Mode ataupun layer khusus yang menampilkan data dengan masukan (input) dari website.
Salah satu koneksi statis menampilkan data pada salah satu layer misalnya seperti ini:
CONNECTIONTYPE postgis CONNECTION "host=localhost dbname=bandung user=eric password=password" DATA "the_geom from bandung"
Sekarang kita ingin menambah satu layer lagi dengan klasifikasi kepadatan penduduk satu daerah kecamatan yang lebih dari 50rb orang. Kita tentu membuat kondisi khusus seperti ini:
CONNECTIONTYPE postgis CONNECTION "host=localhost dbname=bandung user=eric password=password" DATA "the_geom from bandung WHERE 'POPULASI' >= 50"
Atau menggunakan beberapa klasifikasi dengan pewarnaan yang berbeda:
CONNECTIONTYPE postgis CONNECTION "host=localhost dbname=bandung user=eric password=password" DATA "the_geom from bandung" CLASSITEM 'POPULASI' CLASS NAME 'Populasi Rendah' EXPRESSION ([POPULASI] >= 0 AND [POPULASI] < 50) COLOR 255 0 0 OUTLINECOLOR 0 0 0 END CLASS NAME 'Populasi Sedang' EXPRESSION ([POPULASI] >= 50 AND [POPULASI] < 200) COLOR 255 255 0 OUTLINECOLOR 0 0 0 END CLASS NAME 'Populasi Tinggi' EXPRESSION ([POPULASI] >= 200) COLOR 0 255 0 OUTLINECOLOR 0 0 0 END END
Lebih ke depan, setelah mempelajari dan menerapkan fungsi routing dijkstra, kita ingin menampilkan source_id dan target_id yang dinamis:
CONNECTIONTYPE postgis CONNECTION "host=localhost dbname=roads user=routing password=password" DATA "the_geom from (SELECT gid, the_geom from shortest_path_as_geometry('route', 1, 4567)) as route using unique gid using srid=-1"
Ganti angka 1 dan 4567 berdasarkan masukan. Katakan saja variabel srcID dan trgID.
Ganti saja parameter kondisi dengan suatu variabel. Contoh untuk kasus routing misalnya titik awal routing diberi variabel srcID dan titik tujuan diberi variabel trgID. Ubah sintaks di mapfile menjadi:
CONNECTIONTYPE postgis CONNECTION "host=localhost dbname=roads user=routing password=password" DATA "the_geom from ( SELECT gid, the_geom from shortest_path_as_geometry('route', %srcID%,%trgID%) ) as route using unique gid using srid=-1"
Dan jangan lupa pada template html dimasukkan variabel srcID dan trgID:
<input type="hidden" value="[srcID]" name="srcID" /> <input type="hidden" value="[trgID]" name="trgID" />
Metoda ini sangat simpel dan dapat dikembangkan misalnya dengan menggunakan javascript.
Selamat Mencoba
Mar
31
Install PostGIS
Filed Under FreeBSD, PostGIS | 11 Comments
Sekarang bagian dimana kita akan menginstall PostGIS sebagai media penyimpanan data kita menggunakan PostgreSQL database server. Mengapa PostgreSQL? Kenapa gak menggunakan MySQL yang notabene sudah biasa digunakan?
Pertama, saranku adalah jalan2 ke OpenGIS. Dari perkembangan awal Open Geospatial Consortium dibentuk, postgre dev-team menjadi salah satu pembentuk OGC standarisasi untuk pembentuk data geometri dalam database. Oracle kemudian berkontribusi semenjak merilis versi open database-nya Oracle 10g dan MySQL baru dapat mengimplementasikan pada versi 5.0. Tipe data geometri (wkb/wkt) yang dirilis mysql5 ini juga awalnya kurang disetujui oleh OGC karena tidak memenuhi standarisasi yang telah ditetapkan. Sebelum unsubscribe dari milis PostGIS, versi awal MySQL5 ini juga banyak dikritik oleh dev-team nya PostGIS dan belum layak disertakan dan disebut MyGIS. Mereka bahkan mengejek bahwa mysql belum dapat dikatakan sebagai true database dan jangan malu-malu kalau memang butuh bantuan untuk developnya. Saat ini kurang tahu juga perkembangannya tapi sepertinya sudah dapat diterima masyarakat GIS sendiri walaupun rata-rata masih menggunakan modul OGR/TAB yang diberikan GDAL menggunakan koneksi ODBC. Bagi yang sudah terbiasa menggunakan phpMyAdmin, tentu tidak akan menemukan tipe data geometri ini. tapi kalau Anda memasukkan tipe geometry akan diterima oleh mysql (yang tentu saja harus sesuai dengan standarisasi pembentukan data geometri ini).
Instalasi ini akan kita bagi menjadi 3: Instalasi PostgreSQL, Instalasi PostGIS dan Pembuatan Template PostGIS. Tidak lupa juga disertakan satu contoh untuk memasukkan data geometri ke dalam postgresql server. Dan lagi-lagi dilakukan di lingkungan FreeBSD ya. Soalnya bego kalau pakai yang laen ![]()
1. Instalasi PostgreSQL
Sangat disarankan untuk menggunakan postgesql 8.1 ke atas karena sudah lebih stabil dan standarisasi bentuk geometri telah ditetapkan. untuk versi 7.8 - 8.0.0 mempunyai bentuk masing-masing yang berbeda dan akan menyulitkan apabila terjadi pemindahan data (backup - upload) dari satu server ke server lain.
cd /usr/ports/databases/postgresql81-server && make install clean echo 'postgresql_enable="YES"'>> /etc/rc.conf echo 'postgresql_data="/usr/local/pgsql/data"'>> /etc/rc.conf echo 'postgresql_flags="-w -s -m fast"'>> /etc/rc.conf /usr/local/bin/initdb -D /usr/local/pgsql/data # pastikan semua direktori data dimiliki oleh user pgsql (ato postgres) chown -R pgsql : pgsql /usr/local/pgsql # edit konfigurasi untuk server Anda sesuai dengan kebutuhan ( postgresql.conf ) edit /usr/local/pgsql/data/postgresql.conf -- listen_addresses = 'localhost' # diaktifkan (uncomment) dan isi dengan -- listen_addresses = '*' # agar bisa konek dari alamat lain atau tinggalkan terkomen (default) # bila hanya localhost yang dapat melakukan koneksi (untuk keamanan) # edit konfigurasi untuk autentikasi user ( pg_hba.conf ) # secara default, koneksi dari localhost dibebaskan (tanpa password) # tentu ini sangat berbahaya untuk keamanan edit /usr/local/pgsql/data/pg_hba.conf # pada paling bawah cari bagian trust ganti dengan password # # TYPE DATABASE USER CIDR-ADDRESS METHOD # # "local" is for Unix domain socket connections only # local all all password # # IPv4 local connections: # host all all 127.0.0.1/32 password # # IPv6 local connections: # host all all ::1/128 password # Start PostgreSQL /usr/local/etc/rc.d/postgresql start
Selesai
2. Instalasi PostGIS
Ini bisa kita lakukan lewat port ataupun secara manual. Disarankan lewat cara manual karena ini bukan system library yang dibutuhkan program lain untuk berjalan dan lebih up-to-date tapi biar mudah kita install lewat port aja.
cd /usr/ports/databases/postgis && make install clean # semua diinstall di /usr/local/share/postgis (lwpostgis.sql, spatial_ref_sys.sql, ...)
3. Template PostGIS
Menggunakan PostGIS pada database sebenarnya agak merepotkan admin (root) karena membutuhkan superuser
postgresql untuk setting plpgsql dan memasukkan fungsi-fungsi-nya lewat data sql (lwpostgis.sql & spatial_ref_sys.sql)
Cara ini bisa kutuliskan sebagai berikut (menggunakan user eric):
$eric~> createdb jalan -W $eric~> psql -U pgsql -d roads -f lwpostgis.sql -W $eric~> psql -U pgsql -d roads -f spatial_ref_sys.sql -W $eric~> psql -U postgres -d roads -W psql> ALTER TABLE geometry_columns OWNER TO eric; psql> ALTER TABLE spatial_ref_sys OWNER TO eric;
Bandingkan dengan cara ini :
$eric~> createdb jalan -W -T template_postgis
Lebih simpel mana? ![]()
Sekarang kita buat template_postgis agar semua user bisa membuat database menggunakan template ini.
Cara ini diperoleh dari milis postgis oleh GeoLabs
$pgsql~> psql template1
\c template1 CREATE DATABASE template_postgis WITH template = template1; UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template_postgis'; \c template_postgis CREATE LANGUAGE plpgsql ; \i /usr/LOCAL/share/postgis/lwpostgis.sql; \i /usr/LOCAL/share/postgis/spatial_ref_sys.sql; GRANT ALL ON geometry_columns TO PUBLIC; GRANT ALL ON spatial_ref_sys TO PUBLIC; VACUUM FREEZE;
Sekarang semua user bisa membuat database gis sendiri lengkap dengan fungsi-fungsi geometri dengan mudah.
Oke, segitu aja. Kalau ada pertanyaan tulis di komen ato lewat email.
Yeahhh…. PostGIS rocks!!!