Wednesday, December 28, 2016

Python, Java, OSRM

OSRM harita servisi JSON ile bilgi gonderir; bu bilgiyi dekode etmek icin Python ve Java araclari var. Mesela bir yerden bir yere yol tarifi almak icin neler gerekir onlari gorelim.

Java

private static StringBuffer encodeSignedNumber(int num) {
    int sgn_num = num << 1;
    if (num < 0) {
        sgn_num = ~(sgn_num);
    }
    return(encodeNumber(sgn_num));
}

private static StringBuffer encodeNumber(int num) {
    StringBuffer encodeString = new StringBuffer();
    while (num >= 0x20) {
        int nextValue = (0x20 | (num & 0x1f)) + 63;
        encodeString.append((char)(nextValue));
        num >>= 5;
    }
    num += 63;
    encodeString.append((char)(num));
    return encodeString;
}

public static String encode(ArrayList<GeoPoint> polyline, int precision) {
    StringBuilder encodedPoints = new StringBuilder();
    int prev_lat = 0, prev_lng = 0;
    for (GeoPoint trackpoint:polyline) {
        int lat = trackpoint.getLatitudeE6() / precision;
        int lng = trackpoint.getLongitudeE6() / precision;
        encodedPoints.append(encodeSignedNumber(lat - prev_lat));
        encodedPoints.append(encodeSignedNumber(lng - prev_lng));
        prev_lat = lat;
        prev_lng = lng;
    }
    return encodedPoints.toString();

}

public static ArrayList<String []> readOsrmUrl(String urlString) {
    ArrayList<String []> res = new ArrayList<String []>();
    try {
        URL url = new URL(urlString);
        BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
        String line = "";
        while ((line = in.readLine()) != null) {
            String regex =
                "bearing_after.*?:(\\d+),.*?" +
                "\\[(-*\\d+\\.\\d+,-*\\d+\\.\\d+)\\].*?" +
                "distance.\\:(.*?),.*?" +
                "name.\\:(.*?)," ;
            Pattern r = Pattern.compile(regex);
            Matcher m = r.matcher(line);
            while (m.find( )) {
                String [] tmp = new String[4];
                tmp[0] = m.group(1);
                tmp[1] = m.group(2);
                tmp[2] = m.group(3);
                tmp[3] = m.group(4);
                res.add(tmp);
            }
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
    return res;
}

public static ArrayList<String []> shortestPath(double lat1, double lon1, double lat2, double lon2) {

    GeoPoint p1 = new GeoPoint(lat1, lon1);
    GeoPoint p2 = new GeoPoint(lat2, lon2);
    ArrayList<GeoPoint> l = new ArrayList<GeoPoint>();
    l.add(p1);
    l.add(p2);
    String geo = encode(l, 10);
    String ourl = "http://router.project-osrm.org/route/v1/foot/polyline("+ geo +
        ")?overview=simplified&steps=true&alternatives=false&geometries=polyline";
    ArrayList<String []> r = readOsrmUrl(ourl);

    return r;
}

Bu kodun kullandigi yardimci fonksiyonlar alttaki baglantida bulunabilir.


Python

Once,

apt-get install binutils libproj-dev gdal-bin python-gdal

sudo pip install geopandas polyline Fiona 

Su alttaki GH adresindeki Python kodlari fena degil, fakat tek script icinden pat diye isletebilmek icin biraz basitlestirme gerekti. Bu kod direk localhost:5000 uzerinde isleyen servise baglanir ve bilgiyi alir.

https://github.com/ustroetz/python-osrm

Alttaki kod yol bulma (route)  icin yeterli

import numpy as np
from pandas import DataFrame
from urllib2 import urlopen
from polyline import encode as polyline_encode
from ogr import Geometry
from polyline.codec import PolylineCodec
import json

def _chain(*lists):
    for li in lists:
        for elem in li: yield elem

class DefaultRequestConfig:
    def __init__(self):
        self.host = "http://localhost:5000"
        self.profile = "driving"
        self.version = "v1"

    def __str__(self):
        return("/".join([self.host, '*', self.version, self.profile]))

    def __repr__(self):
        return("/".join([self.host, '*', self.version, self.profile]))

    @staticmethod
    def __call__(addr=None):
        if not addr:
            return DefaultRequestConfig()
        else:
            tmp = addr.split('/')
            cla = DefaultRequestConfig()
            cla.host = tmp[0]
            i = len(tmp)
            cla.version = tmp[i-2]
            cla.profile = tmp[i-1]
            return cla

RequestConfig = DefaultRequestConfig()

def check_host(host):
    """ Helper function to get the hostname in desired format """
    if not ('http' in host and '//' in host) and host[len(host)-1] == '/':
        return ''.join(['http://', host[:len(host)-1]])
    elif not ('http' in host and '//' in host):
        return ''.join(['http://', host])
    elif host[len(host)-1] == '/':
        return host[:len(host)-1]
    else:
        return host

def decode_geom(encoded_polyline):
    ma_ligne = Geometry(2)
    lineAddPts = ma_ligne.AddPoint_2D
    for coord in PolylineCodec().decode(encoded_polyline):
        lineAddPts(coord[1], coord[0])
    return ma_ligne

def simple_route(coord_origin_old, coord_dest_old, coord_intermediate=None,
                 alternatives=False, steps=False, output="full",
                 geometry='polyline', overview="simplified",
                 url_config=RequestConfig, send_as_polyline=True):
    if geometry.lower() not in ('wkt', 'well-known-text', 'text', 'polyline',
                                'wkb', 'well-known-binary', 'geojson'):
        raise ValueError("Invalid output format")
    else:
        geom_request = "geojson" if "geojson" in geometry.lower() \
            else "polyline"

    coord_origin = tuple(reversed(coord_origin_old))
    coord_dest = tuple(reversed(coord_dest_old))

    host = check_host(url_config.host)

    if not send_as_polyline:
        url = [host, "/route/", url_config.version, "/", url_config.profile,
               "/", "{},{}".format(coord_origin[0], coord_origin[1]), ';']

        if coord_intermediate:
            url.append(";".join(
                [','.join([str(i), str(j)]) for i, j in coord_intermediate]))

        url.extend([
            '{},{}'.format(coord_dest[0], coord_dest[1]),
            "?overview={}&steps={}&alternatives={}&geometries={}".format(
                 overview, str(steps).lower(),
                 str(alternatives).lower(), geom_request)
            ])
    else:
        coords = [
            pt[::-1] for pt in _chain(
                        [coord_origin],
                        coord_intermediate if coord_intermediate else [],
                        [coord_dest])
            ]
        url = [
            host, "/route/", url_config.version, "/", url_config.profile, "/",
            "polyline(", polyline_encode(coords), ")",
            "?overview={}&steps={}&alternatives={}&geometries={}".format(
                 overview, str(steps).lower(),
                 str(alternatives).lower(), geom_request)
            ]
    rep = urlopen(''.join(url))
    parsed_json = json.loads(rep.read().decode('utf-8'))

    if "Ok" in parsed_json['code']:
        if geometry in ("polyline", "geojson") and output == "full":
            return parsed_json
        elif geometry in ("polyline", "geojson") and output == "routes":
            return parsed_json["routes"]
        else:
            if geometry == "wkb":
                func = Geometry.ExportToWkb
            elif geometry == "wkt":
                func = Geometry.ExportToWkt

            for route in parsed_json["routes"]:
                route["geometry"] = func(decode_geom(route["geometry"]))

        return parsed_json if output == "full" else parsed_json["routes"]

    else:
        raise ValueError(
            'Error - OSRM status : {} \n Full json reponse : {}'.format(
                parsed_json['code'], parsed_json))

# test
result1 = simple_route((40.987659,29.036428), (40.992186,29.039228),
                       output="routes",
                       geometry="wkt",
                       send_as_polyline=True, steps=True)
print result1

Bu arada ciktilarda enlem, boylam degerleri yer degisikligine ugramis, OSRM her nedense boyle yapiyor, biz sadece girdide sirayi degistirdik.

Wednesday, December 14, 2016

SQLite, Android, JDBC, Python

Android cep telefonlarında SQL bazlı erişilebilen bir taban gerekirse SQLite programı bu ihtiyaçı karşılıyor. Bu taban çok hafif, hızlı çalışır, taban olarak tek ihtiyaçı bir .db dosyasından ibarettir. Dizüstü bilgisayarında da SQLite kullanılabiliyor, pek çok dilden erişim var, Python, Ruby, Java, vs.. Diğer bazı özellikler tablo indeksleyebilmek, birleşim (join), alt sorgular (subjoin) - kuvvetli bir program.

Bizim için en çok gereken özellik dışarıdan yaratılan (mobil için) büyükçe bir tabanı, 20 MB civarı, telefona kopyalayarak bu veriye anahtar bazlı hızlı erişim sağlamak. SQLite bunu rahatça sağladı. Niye koca bir JSON'u Android'den okuyup, mesela HashMap üzerinden, o şekilde direk erişim yapmadık? Çünkü o şekilde tek bir obje için 20 MB'in tamamını hafızaya yüklemek gerekir, SQLite, her diğer saygıdeğer ilişkisel tabanın yapacağı gibi, düzgün indekslendiği durumda disk'te sadece gerekli yere gider ve gereken satırı yükler, tabanının tamamını hafızaya yüklemeden.

Geliştirme ortamında veriyi Ubuntu'da Python ile yaratıyoruz. Dizüstü Ubuntu ortamında kurmak

sudo apt-get install sqlite3 libsqlite3-dev

Basit kod

import sqlite3
conn = sqlite3.connect('taban.db')

c.execute('''CREATE TABLE vs (key text primary key not null, ... )''')
c.execute('INSERT INTO vs values (...)')
...
conn.commit()
conn.close()

Eger taban.db yoksa yaratilir. 

Android 

Yaratılan tabanı SD kartına kopyalarsak Android SQLite'i ona rahatça erişiyor. 

import android.database.sqlite.*;
import android.database.*;
..
f = "/storage/emulated/0/Downloads/taban.db"
SQLiteDatabase db = SQLiteDatabase.openDatabase(f, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
Cursor c = db.rawQuery("SELECT key FROM vs where ..", null);
c.moveToFirst();
Log.d("cam", "key"+c.getString(0));
..
c.close();
db.close();

Bu kod işler, burada problem yok.

Fakat üstteki API JDBC değil, yani standart bir arayüz değil. Eğer geliştirme ortamında birim testi yazmak istersek bu kod baş ağrısı yaratacaktır. Gerçi üstteki kullanımın taklitleme (mocking) üzerinden testi mümkün, ama bizce en iyisi Android üzerinde JDBC kullanmak. 

Şu arkadaşlar Android için bir JDBC kodu yazmışlar, 

https://github.com/SQLDroid/SQLDroid

Jar'i indirmek icin 

http://search.maven.org/#search%7Cga%7C1%7Csqldroid

Biraz onceki kodu

import java.sql.*;
..
try {
    Class clazz = Class.forName("org.sqldroid.SQLDroidDriver");
    DriverManager.registerDriver((Driver)clazz.newInstance());
} catch (Exception e) {
    e.printStackTrace();
}

String jdbcUrl = "jdbc:sqldroid:" + "/storage/emulated/0/Downloads/taban.db"
try {
    Connection conn = DriverManager.getConnection(jdbcUrl);
    Statement stmt = conn.createStatement();
    String sql = "SELECT key FROM vs where ..";
    ResultSet rs = stmt.executeQuery(sql);
    rs.next();
    Log.d("cam", "key"+rs.getString(1));
    rs.close();
    conn.close();         
} catch (SQLException e) {
    throw new RuntimeException(e);
}       

olarak değiştirebiliriz. Tabii SQLDroid jar'ını projemizin lib dizine koymayı unutmuyoruz.

Dikkat: Android DB API'si kolonlara 0 indis bazlı erişiyor, JDBC 1 indis bazlı erişiyor.

Birim testler şimdi daha kolaylaştı; Android kodundaki veri erişimini belli metotlara koyarız, bu metotlar dışarıdan bir taban bağlantısı Connection alırlar; Android ortamından bu objenin gerçekleştirimi / gerçek hali SQLDroıdConnection olur, geliştirme ortamında org.sqlite.JDBC olur.. ama test edilen metot bunlardan habersiz bir şekilde ona verilen Connection ile güzelce çalışır.

Dizustu icin JDBC

try {
    Class clazz = Class.forName("org.sqlite.JDBC");
    DriverManager.registerDriver((Driver)clazz.newInstance());
    String jdbcUrl = "jdbc:sqlite:" + "/vs/vs/taban.db";
    Connection connection = DriverManager.getConnection(jdbcUrl);
} catch (Exception e) {
    e.printStackTrace();
}

Not: Akla şu soru gelebilir, "Android'in kapalı API'sinin hangi jar'ı kullandığını bulsam, o jar'ı dizüstü'nde kullansam, testi bu şekilde işletebilir miyim?". Bu olmuyor, Android içindeki SQLite'i telefon dışında işletmek mümkün değil. Android benzetici (emulator) ile tabii tüm telefon fonksiyonları dizüstü'nde işletilebilir, ama bu da uzun iş. Zaten o sebeple insanlar taklitleme işine girmişler, ama o da bize göre külfetli.

Dizustu ortami icin Java JDBC SQLite jar'i

https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.8.9.1/

Monday, December 12, 2016

Gson, Java Objelerini JSON Olarak Yazmak, Okumak

Java nesnelerini diske nasıl yazıp okuruz, eski ismiyle (!) serileştiririz (serialization) konusuna bakarken şu kodu gördük,

https://github.com/google/gson

Gson projesi Google tarafından geliştirilmiş, pek çok kişinin alışık olduğu JSON formatına objelerin yazılıp okunmasını sağlıyor.

Bizim için en çok gereken "objeler arası göstergeç takibi olup olmadığı", yani A nesnesi B nesnesine referans ediyor, acaba A'yı diske yaz dediğimizde B referansı takip edilip o da A ile beraber yazılacak mı? Ufak bir test bunun olduğunu gösteriyor.

Kurmak için derlemeye gerek yok, Maven tüm dünyayı indirebilir, tek bir jar yeterli,

http://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.0/gson-2.8.0.jar

Simdi

public class Exam {
    public String SUBJECT;
    public double GRADE;
    @Override
    public String toString() {
        return SUBJECT + " - " + GRADE;
    }    
}

public class Person {
    public String NAME;
    public String LOCATION;
    public Exam EXAM;
    @Override
    public String toString() {
        return NAME + " - " + LOCATION;
    }    
}

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

public class Test {
    
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().create();
        Exam ee = new Exam();
        ee.SUBJECT = "adsasf";
        Person pp = new Person();
        pp.NAME = "Husnu";
        pp.EXAM = ee;   
        try {
            Writer writer = new OutputStreamWriter(new FileOutputStream("Output.json") , "UTF-8");
            gson.toJson(pp, writer);
            writer.close();
        } catch (Exception e) {System.err.println("yazim hatasi"); }
    }
}

Bu kodlar kendi java dosyalarinda olacak tabii ki.. Derleyelim,

javac -classpath gson-2.8.0.jar:. Test.java
java  -classpath gson-2.8.0.jar:. Test

Kod isledi, sonuc olarak Output.json yazildi, icinde 

{"NAME":"Husnu","EXAM":{"SUBJECT":"adsasf","GRADE":0.0}}

goruluyor.

Okumak icin iki turlu yol gosterelim, ilki direk diskten okumak, ikincisi bir String icindeki objeyi okumak.

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.*;

public class Test2 {
    
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().create();
        try {
            // disk
            InputStream in = Person.class.getResourceAsStream("Output.json");       
            Reader reader = new InputStreamReader(in, "UTF-8");
            Person p1 = gson.fromJson(reader, Person.class);
            System.out.println(p1);

            // string
            String s = "{'NAME':'Husnu','EXAM':{'SUBJECT':'adsasf','GRADE':0.0}}";
            Person p2 = gson.fromJson(s, Person.class);
            System.out.println(p2);
            
        } catch (Exception e) { System.err.println("okuma hatasi"); }
        
    }
}

Şimdi ilginç bir kullanım görelim. Acaba Java bağlamında sözlük içinde sözlük içeren bir veri yapısını nasıl okurum / yazarım, daha doğrusu Java objesi olarak yazılıp / okunan şey neye benzer? Belki bu tür veriyi Python'dan üretiyorum, ve onu olduğu gibi Java'da okuyabilmek istiyorum. Bir deneme yaptık, tahmin olarak herhalde (GeoMap.java icinde)

import java.util.*;
public class GeoMap extends HashMap> { }

gibi bir kod olacakti. Yazmak icin 

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.*;

public class Test3 {
    
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().create();
        
        GeoMap m = new GeoMap();
        m.put("11.111 22.2222", new HashMap());
        m.put("22.111 22.2222", new HashMap());
        m.get("11.111 22.2222").put("11.111 22.4444", "10.0");
        m.get("22.111 22.2222").put("33.111 22.2222", "11.0");
        
        try {
            Writer writer = new OutputStreamWriter(new FileOutputStream("Output.json") , "UTF-8");
            gson.toJson(m, writer);
            writer.close();
        } catch (Exception e) {System.err.println("yazim hatasi"); }    
    }
}

Bu kod hakikaten bekleneni yapti, veri suna benzedi, 

{"22.111 22.2222":{"33.111 22.2222":"11.0"},"11.111 22.2222":{"11.111 22.4444":"10.0"}}

Okumak icin alttaki kod; isi biraz ilginclestirelim dedik, bir zip dosyasi icinden json okuyoruz (test icin ustteki dosya elle ziplenebilir)

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.zip.*;
import java.io.*;

public class Test4 {
    
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().create();
        try {
            ZipFile  zipFile =  new  ZipFile ("Output.json.zip");
            ZipEntry e = zipFile.getEntry("Output.json");
            InputStream in = zipFile.getInputStream(e);     
            Reader reader = new InputStreamReader(in, "UTF-8");
            GeoMap p = gson.fromJson(reader, GeoMap.class);
            System.out.println(p.size());
            System.out.println(p.get("22.111 22.2222"));
            
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("okuma hatasi");
        }
        
    }
}

OSM, PostGIS, Örnek Sorgular

Daha onceki yazida OSM (Open Street Map) veri tabanını nasıl Postgresql (PG) tabanına yükleneceğini gördük. PG + PostGIS ve OSM verisi hakikaten çok kuvvetli bir üçlü. OSM verisi Wikipedia'nın ansiklopedik bilgi için yaptığını dünya yer verisi için yapmaya uğraşıyor, gönüllüler kendi uğraşları ile bu tabanı güncel tutuyorlar. PG tabanı zaten Oracle'ın yerine geçmesi için yazılmış bir açık yazılım, PostGIS uzantısı iyi işliyor. Açıkça söylemek gerekirse bu üçlü etrafında koca bir şirket kurulabilir. İngilizce bir deyimi tercüme etmek gerekirse "sınır gökyüzü (sky is the limit)".

OSM etraftaki pek çok cismi, yeri, binayı enlem / boylamı ile birlikte kategorize de etmiş, yani veri zengin. Mesela tüm restoranları görmek için

select name,st_asText(st_transform(way, 4326)) from planet_osm_point where amenity = 'restaurant';

Soyle bir sonuc geldi

Remise POINT(13.0948499639389 52.4143189771462)
RBB-Kantine „Teestube“ POINT(13.1212677994774 52.3899105025706)
Mensa Griebnitzsee POINT(13.1278047499684 52.3935486680721)
Piazza Toscana POINT(13.122158209587 52.3947633697572)
..

Cep telefonundan "bana yakındaki restoranları göster" gibi bir komut bu veriyi kullanabilir mesela.

Bu amenity (tesis) kolonunda pek çok diğer ilginç değer var, bazı örnekler

select distinct(amenity) from planet_osm_point;

police_box
car_sharing
bank;post_office
lockbox
conference_centre
car_club
waste_basket
hospital
register_office
nursing_service
contemporary_art_gallery
stock_exchange
ebsuinesslotse
public_building
lockers
biergarten
post_office
elevator
doctors
food_court
gambling
stroller_repair
variety_store
gallery
taxi
Beratungsstelle
toilets
luggage_locker
shelter
nightclub;restaurant;art_gallery;pub
fire_station
coworking_space
..

Evet bir cop tenekesi bile tabanda bulunabiliyor,

http://wiki.openstreetmap.org/wiki/Tag:amenity%3Dwaste_basket

Caddeler

Mesela belli bir enlem / boylamın 1 km yakınındaki tüm yürünebilen caddeleri görmek istiyoruz,

SELECT
osm_id,
name,
st_asText(st_startpoint(st_transform(way, 4326))),
st_asText(st_endpoint(st_transform(way, 4326))),
st_distance(st_startpoint(st_transform(way, 4326)),st_endpoint(st_transform(way, 4326)))
FROM planet_osm_line
where 1=1
and highway in ('footway','living_street','residential')
and st_dwithin(st_transform(way, 4326),st_geomfromtext('POINT(13.427 52.540)',4326)::geography, 1000)
and st_distance(st_startpoint(st_transform(way, 4326)),st_endpoint(st_transform(way, 4326))) > 0

Daha çetrefil sorgular düşünülebilir, mesela PostGIS iki coğrafi obje arasındaki kesişmeleri bulabiliyor. Belli bir kordinat yakınındaki tüm yürünebilen caddeleri alalım, ve bu kümeyi kendisi birleştirelim (join) ve hangi yol hangisi ile kesişiyor onu bulalım,

SELECT p1.osm_id as o1, p2.osm_id as o2,
       st_asText(st_transform(st_intersection(p1.way,p2.way), 4326)) 
FROM
       planet_osm_line as p1 inner join planet_osm_line as p2
       on st_intersects(p1.way,p2.way) 
where 1=1
      and p1.highway in ('footway','living_street','residential')
      and p2.highway in ('footway','living_street','residential')
      and st_dwithin(st_transform(p1.way, 4326),st_geomfromtext('POINT(13.4270146842 52.5408961579)',4326)::geography,1000)
      and st_dwithin(st_transform(p2.way, 4326),st_geomfromtext('POINT(13.4270146842 52.5408961579)',4326)::geography,1000)
      and p1.osm_id < p2.osm_id 

Hic fena degil.

Kitap olarak PostGIS In Action tavsiye edilir.

Monday, December 5, 2016

GPSTk, GPS Uydularinin Yeri

Uydu Ile Yer Bulma

[Bu bolume ekler olabilir].

GPS sistemi alicinin (cep telefonu) yerine bulmak icin GPS uydularini kullanir. Bu uydularin yeri bilinir - alicimiz acildiginda bu bilgi uydulardan alinir (almanac denen veri), ve ardindan sinyal zaman farklari uzerinden alicinin uyduya olan mesafesi hesaplanir (pseudorange), ve en az 4 uydu mesafesi ve uydularin kesin yerleri uzerinden alicinin yeri hesaplanabilir.

Fakat GPS Test gibi app'lerde bazen goruyoruz ki 10-12 uydu gorulmeden yer hesabi yapilmiyor. Burada ilerleme yapmak isteyen maceraci (!) arkadaslar icin alttakileri paylasalim; eger alici/uydu mesafesi alinabilirse (Android Nougat, API 24'ten itibaren bu ham mesafeyi veriyor) bu hesap daha hizli bir sekilde yapilabilir belki.

Her gun / saat GPS uydularinin nerede olacaginin tahmini alttaki sitede ham veri olarak paylasiliyor.

http://www.linz.govt.nz/data/geodetic-services/positionz/rinex-data-archive

(Tabii bu durumda bu veri her gun indirilecek, ama bir muhendislik al/ver durumu, belki gunun ufak bir kisminda kisa bir Internet baglantisi uzerinden uydu yer tahminleri alinir, sonra tum gun sadece uydu verisi ile yere bulunabilir).

Veri RINEX formatinda. 5 Aralik 2016 icin navigasyon dosyasi

https://apps.linz.govt.nz/ftp/positionz/2016/339/auto3390.16n.Z

5 Aralik 339. gun, 1 gunun tum verisi icin 0, n navigasyon demek.

Bu veriyi isleyebilen ve pek cok faydali hesap yapabilen bir proje

https://github.com/SGL-UT/GPSTk

Acilinca dizine girilir

mkdir build
cd build
cmake ..
make
sudo make install

Simdi bir ornek derlemek icin examples altina girilir,

g++ example3.cpp -I/usr/local/include/ -L/usr/local/lib -lgpstk 

Nasil isletilecegi icin GH'a bakilabilir.

Bir de Python bazli bazi kodlar var,

https://github.com/scienceopen/gpstk-examples-python

Fakat bu kod icin derleme asiri hafiza gerektiriyor. Script'lerde bir bozukluk olmus herhalde. Maceracilar buraya da dalabilir.

Bu uydu hesaplarinin matematigi hakkinda kaynak ararken tanidik bir isim gorduk, Lineer Cebir'in efsanevi hocasi Gilbert Strang meger bu alanda bir kitap yazmis. Kitapta surekli referans edilen Matlab kodlari surada.

Not:

"Fakat Android N piyada gorulen tum telefonlarda yok"; bunun cevabi biraz daha macera - rivayete gore Cynogen Mod 14, mesela Samsung Galaxy SIII icin bile Nougat kurulmasini sagliyor. CM ve benzeri ROM'lar "alternatif Android" kurulumlari sunarlar; burada flashlama (flashing) gibi kavramlar var; Bu arkadaslar Android'i kaynaklardan tekrar derleyip, gerekeni uyarlayip istemedikleri seyleri disari atarak temiz bir Android surumu olusturuyorlar. Acik kaynagin yararlari.

Thursday, December 1, 2016

Islenmis OSM Verisi Yerel Diskte, osm2pgsql, PostGIS

Daha once OSRM projesi ile OSM verisi uzerinden nasil servis sunabilir, bunu gorduk. Peki ya ham veriyi almak istiyorsak ne yapariz?

osm2pgsql adli arac apt-get ile kurulabiliyor, yerel diskteki osm.bz2 tipindeki dosyalari isleyip direk Postgresql tabanina veriyi yazabiliyor. PG kurmak altta. Ek olarak bir de lokasyon modulu nasil kurulur onu da gorecegiz, bu eklere PostGIS adi veriliyor, PG'nin lokasyon verisinin islenmesini saglayan ozel fonksiyonlari var.

sudo apt-get install postgresql make cmake g++ libboost-dev libboost-system-dev   libboost-filesystem-dev libexpat1-dev zlib1g-dev   libbz2-dev libpq-dev libgeos-dev libgeos++-dev libproj-dev lua5.2   liblua5.2-dev osm2pgsql postgresql-9.5-postgis-2.2 pgadmin3 postgresql-contrib-9.5

Not: Uzerine oldugumuz Ubuntu versiyonuna gore hangi PG kuruldugu degisik olabilir, bu durumda 9.5 yerine o versiyon koyulabilir.

Baslamak, durdurmak icin sudo service postgresql stop ya da start. Kurulus sirasinda mevcut kullanicinizin direk erisebilecegi postgres adli bir kullanici yaratilmis olmali.

sudo -u postgres createdb gis

ile taban yaratilir.

sudo -i -u postgres

ile oteki kullaniciya girilir,

psql -d gis -c 'CREATE EXTENSION postgis; CREATE EXTENSION hstore;'

Simdi

osm2pgsql berlin-latest.osm.bz2 --slim

Tabana bakariz, psql -d gis, komut satirinda \dt

planet_osm_line
planet_osm_nodes
planet_osm_point
planet_osm_polygon
planet_osm_rels
planet_osm_roads
planet_osm_ways

tablolarini gormemiz lazim. Artik gereken ham veri bu tablolar icinde. Eger veriyi disari cikartmak istiyorsak, mesela tabandaki tum caddeler,

psql -d gis -t -A -F";" -c \
     "SELECT  osm_id,name,highway,\
     st_asText(st_startpoint(st_transform(way, 4326))), \
     st_asText(st_endpoint(st_transform(way, 4326))) \
     FROM planet_osm_line " > output.csv

Not: Ayni cadde ismi ustteki sorgu sonucu birden fazla satirda ve baslangic / bitis noktasi ile gozukebilir. Bu durumda buyuk cogunlukla ayni caddeyi parcalar haline goruyoruz demektir.

PostGIS icin iyi bir kitap PostGIS in Action.

osm2po

Alttaki Java bazli bir proje (kapali kod ne yazik ki), Geofabrik sitesinden gerekli veriyi alip bir Postgresql tabani uzerinde isletilebilecek SQL dosyasi uretiyor.

http://osm2po.de

java -Xmx1g -jar osm2po-core-5.1.0-signed.jar prefix=tr tileSize=x http://download.geofabrik.de/europe/turkey-latest.osm.pbf postp.0.class=de.cm.osm2po.plugins.postp.PgRoutingWriter

cagrisi yeterli. Gerekli dosya tr altdizini icinde olacak. Fakat bu kutuphanenin bazi verileri disarida biraktigini gorduk.

osm2pgrouting

Ham OSM verisinin Postgresql tabana yazabilen bir proje

https://github.com/pgRouting/osm2pgrouting.

Derlemek gerekli.. Ayrica tabani pgrouting icin hazirlamak lazim, bazi create extension komutlari gerekiyor. Ustteki README icinde bunlar var.

Bu kodun bir problemi eger yeterince hafiza yoksa (2 GB bile yetmeyebilir) tek bir bolge verisi uzerinde bile program cokebiliyor.

Postgresql GUI

Uzun zamandir taban semasini gosteren, sorgu isleten GUI araci olarak Squirrel kullaniyorduk (ondan once Toad). Fakat Squirrel projesinde fazla hareket yok; alternatif bir arac SQL Workbench/J.

http://www.sql-workbench.net/

Masaustu ikonu

[Desktop Entry]
Comment=
Terminal=false
Name=SWJ
Exec=/bin/sh /home/burak/Downloads/Workbench-Build121/sqlworkbench.sh
Type=Application
Icon=/usr/share/icons/Win7-icons/apps/gnome-networktool.png

Farkli tabanlara baglanti destegi var. Postgresql icin JDBC jar suradan

https://jdbc.postgresql.org/download.html

SWJ icinden File | Manage Drivers secilir, oradan Postgresql icin indirilen jar secilir.

SQLLite icin jar

https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.8.9.1/

Yine manage drivers'dan sqllite icin yeni profil yaratilir. Sonra yeni baglanti yaratilir, File | Connect Window'dan sol ust kosedeki dugme ile.


Tuesday, November 29, 2016

Yol Tarifi, Harita Bilgisi: osrm-backend

Verili herhangi bir enlem / boylam kordinatına en yakın sokak, yol isimlerini, yerlerini bulabilen, hatta bir noktadan diğerine nasıl gidileceğini veren bir veri tabanı ve program ÖSRM. Aslında bu arkadaşlar OpenStreetMap adli projenin veri tabanını daha iyi erişilebilir hale getirmişler.

https://github.com/Project-OSRM

Proje C++ bazlı, hızlı işliyor. İçinde OSM projesinin dosyalarını alıp onları daha ufaltan, ve bir servis ve APİ üzerinden dış erişime hazır hale getiren kodlar var. Bu servisin nasıl işlediğini göstermek için kendileri bir bedava servis işletiyorlar,

http://router.project-osrm.org

Mesela alttaki kordinata en yakin cadde hangisidir

http://router.project-osrm.org/nearest/v1/foot/29.036428,40.987659

ile bulunabiliyor, çıktı JSON formatında. İki nokta arasında nasıl gidilir, hangi caddeler kullanılır,

http://router.project-osrm.org/route/v1/foot/29.036428,40.987659;29.039228,40.992186

URL icinde v1 ardindan gidis sekli verilmeli, araba icin car, bisiklet icin bicycle; ustteki yuruyerek.

İstenen her  türden veri üstteki bedava servisten alınabilir, ama başkasının servisini fazla yormamak (!) için (ve yerel bazlı erişim daha hızlı olur tabii) kendi servisimizi oluşturabiliriz.

Kod Github'dan indirilir, ve apt-get install alttakiler uzerinde isletilir,

cmake libtbb-dev lua5.2 libboost-all-dev liblua52 libluabind-dev liblua5.2-dev libluabind-dev libstxxl-dev libxml2 libxml2-dev libosmpbf-dev libbz2-dev libprotobuf-dev

Simdi proje dizinine girilip

mkdir -p build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build .
sudo cmake --build . --target install

isletilir. Ayrica ayni dizinde hangi ulasim sekli var ise, onun lua dosyasina Unix sembolik baglanti kurulmali, mesela araba yontemi icin

ln -s profiles/car.lua .

Kurulum bitti, simdi veri lazim, mesela Turkiye icin

http://download.geofabrik.de/europe/turkey.html turkey-latest.osm.bz2

Tum veri icin http://download.geofabrik.de

Bu dosya acilir, simdi dosya uzerinde

osrm-extract turkey-latest.osm

ve

osrm-contract turkey-latest.osrm

Dikkat bu komutlari lua linki neredeyse oradan isletmek lazim. O zaman osrm dosya referansina dizin ismi eklemek gerekebilir.

Bu son komut uzun surecek, 30-40 dakika gibi.. Bittikten sonra artik veri hazir, veri dizininde

osrm-routed map.osrm

isletilir. Bu komut 5000 port'unu dinleyen bir servis baslatir. Artik ustteki turunden tum komutlarda http://router.project-osrm.org yerine http://localhost:5000 kullanilabilir.

Baglantilar

https://www.digitalocean.com/community/tutorials/how-to-set-up-an-osrm-server-on-ubuntu-14-04

https://github.com/Project-OSRM/osrm-backend/wiki/Running-OSRM

https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md

Tuesday, November 22, 2016

Bilgisayari Konusturmak, Metinden Konusma (Text-to-Speech)

Python

pip install gtts, pyttsx

from gtts import gTTS
import os
tts = gTTS(text='Good morning', lang='en')
tts.save("good.mp3")

ya da 

import pyttsx
engine = pyttsx.init()
engine.say('Good morning.')
engine.runAndWait()

Android uygulamasi icinde cep telefonunu konusturmak icin arayuz var. Herhangi bir Activity icinde

import android.speech.tts.TextToSpeech;

public class MyActivity extends Activity
{
    ...

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        ...
        t1=new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
                @Override
                public void onInit(int status) {
                    if(status != TextToSpeech.ERROR) {
                        t1.setLanguage(Locale.UK);
                    }
                }
            });
     }
}

Ustteki onInit konusturma yapmadan once islemis olmali. Simdi herhangi bir metni okutmak icin

String toSpeak = "How much wood could a woodchuck chuck";
t1.speak(toSpeak, TextToSpeech.QUEUE_FLUSH, null);