EDIT: Abgetrennt von https://forum.byte-welt.net/java-forum/allgemeine-themen/21259-osm-abfragen.html
Hallo,
lange war in diesem Thread nichts mehr zu lesen. Daher belebe ich ihn mal wieder. Ich habe mich an ein kleines Programm gemacht, dass die Anforderungen (weitgehend) erfüllt. Neben OSM kommt auch Google zum Einsatz, einfach, weil die OSM-Daten nicht immer Vollständig sind.
Ich würde mich freuen, wenn ihr Euch das Programm einmal anschauen könntet und gegebenenfalls Tipps habt wie man es noch verbessern kann. Ich stehe was Java betrifft noch ziemlich am Anfang und bin froh noch das eine oder andere dazu zu lernen.
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.NamedNodeMap;
import org.xml.sax.SAXException;
public class Geodaten {
public static void main(String[] args) throws Exception
{
Geodaten start = new Geodaten();
}
//Hauptprogramm
public Geodaten() throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
Scanner antwort = new Scanner(System.in);
Scanner currentline;
//Initialization
boolean endloop=false;
// Begruessung
System.out.println("Hallo, wollen Sie etwas suchen?");
// Schleife
while (!endloop){
currentline=new Scanner(antwort.nextLine().toLowerCase());
if (currentline.findInLine("nein")==null){
System.out.print("Was suchen Sie? ");
String art = br.readLine();
art = art(art);
System.out.print("Wo suchen Sie es?");
String ort = br.readLine();
sucheLatUndLon(ort,art);
System.out.print("Wollen Sie weitersuchen?");
}
else {
System.out.println("Auf wiedersehen.");
endloop=true;
}
}
}
private String art (String art){
/*
Suchmöglichkeiten
bar
cafe
biergarten
pub
car_rental
car_sharing
car_wash
dentist
dentist
pharmacy
doctors
bank
atm
fuel
ice_cream
restaurant
fast_food
brothel
stripclub
swingerclub
casino
theatre
nightclub
planetarium
gym
post_office
register_office
sauna
social_facility
bus_station
grit_bin
clock
hunting_stand
telephone
vending_machine
waste_disposal
fire_station
school
college
kindergarten
parking
place_of_worship
bbq
bench
fire_station
*/
art = art.toLowerCase();
art = art.replace("oder", "|");
return art;
}
private void sucheLatUndLon(String ort, String art){
try {
//Eingabe Prüfen
String zahl = "[0-9]*";
String regex = zahl+"."+zahl+","+zahl+"."+zahl;
//Falls Lat+Lon
if (ort.matches(regex)) {
ort = ort;
}
//Falls Adresse --> Umwandeln
else{
try {
System.setProperty("java.net.useSystemProxies", "true");
String latLongs[] = getLatLongPositions(ort);
ort = latLongs[0]+","+latLongs[1];
} catch (Exception ex) {
Logger.getLogger(Geodaten.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Liste erstellen
ArrayList <GeodatenObjekte> geoobjekte = new ArrayList <>();
//String zerlegen
String[] stringResult = ort.split(",");
//Ausgangspositionen
double lat = Double.parseDouble(stringResult[0]);
double lon = Double.parseDouble(stringResult[1]);
//Entfernung in Metern
double wert = 750;
//Werte berechnen
quadratBerechnen(lat, lon, geoobjekte, wert, art);
//Nach Entfernung sortieren
Collections.sort(geoobjekte, Entfernung);
if (geoobjekte.isEmpty()){
System.out.println("Es wurde leider nichts gefunden");
}
else {
//Ein Fund
if(geoobjekte.size() == 1){
//Eingangssatz
String ausgabe = "Am nächsten ist die " + geoobjekte.get(0).getName() + ". Sie ist " + einheitAngeben(geoobjekte.get(0).getDistanz()) + ".";
System.out.println(ausgabe);
}
//Mehrere Funde
else{
String ausgabe = "Am nächsten ist die " + geoobjekte.get(0).getName() + ". Insgesamt existieren " + geoobjekte.size() + " Möglichkeiten im nähreren Umkreis. Ich erstelle eine Liste.";
System.out.println(ausgabe);
int z = 1;
for (GeodatenObjekte i : geoobjekte){
ausgabe = z+ ". " + i.getName()+" : " + i.getOrt() + " (Distanz: " + einheitAngeben(i.getDistanz())+")";
System.out.println(ausgabe);
z = z+1;
}
}
}
} catch (IOException | ParserConfigurationException | SAXException ex) {
Logger.getLogger(Geodaten.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Richtige Einheit angeben
private static String einheitAngeben(double distanz){
String einheitAngeben = null;
if (distanz == 0){
einheitAngeben = "direkt dort";
}
else if (distanz < 1){
distanz = distanz * 1000;
einheitAngeben = gerichteteZahl(distanz) + " Meter entfernt";
}
else {
einheitAngeben = gerichteteZahl(distanz) + " Kilometer entfernt";
}
return einheitAngeben;
}
//Komma nur falls nötig
private static String gerichteteZahl(double distanz){
String gerichteteZahl;
if( (distanz - (int)distanz) == 0){
int i = (int)distanz;
gerichteteZahl = i+"";
}
else{
DecimalFormat format = new DecimalFormat("###000.##");
gerichteteZahl = format.format(new Double(distanz))+"";
}
return gerichteteZahl;
}
//Adresse in Lat und Lon
private static String[] getLatLongPositions(String address) throws Exception
{
int responseCode = 0;
String api = "http://maps.googleapis.com/maps/api/geocode/xml?address=" + URLEncoder.encode(address, "UTF-8") + "&sensor=true";
URL url = new URL(api);
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
httpConnection.connect();
responseCode = httpConnection.getResponseCode();
if(responseCode == 200)
{
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();;
Document document = builder.parse(httpConnection.getInputStream());
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("/GeocodeResponse/status");
String status = (String)expr.evaluate(document, XPathConstants.STRING);
if(status.equals("OK"))
{
expr = xpath.compile("//geometry/location/lat");
String latitude = (String)expr.evaluate(document, XPathConstants.STRING);
expr = xpath.compile("//geometry/location/lng");
String longitude = (String)expr.evaluate(document, XPathConstants.STRING);
return new String[] {latitude, longitude};
}
else
{
System.out.println("Es wurden leider keine passenden Daten gefunden.");
}
}
return null;
}
//Quadrat berechnen
private void quadratBerechnen(double lat, double lon, ArrayList <GeodatenObjekte> geoobjekte, double wert, String art) throws IOException, ParserConfigurationException, SAXException{
try {
//Erdradius
double r=6371000;
//Berechnung
//Oberen Wert
double latOben = lat + (wert/r) * 180/Math.PI;
double lonOben = lon + (wert/(r*Math.cos(Math.PI*lat/180))) * 180/Math.PI;
//Unteren Wert
wert = wert*-1;
double latUnten = lat + (wert/r) * 180/Math.PI;
double lonUnten = lon + (wert/(r*Math.cos(Math.PI*lat/180))) * 180/Math.PI;
//File downloaden
System.out.println("Ich sehe nach.");
File osmXmlFile = new File("md.osm.xml");
downloadSample(osmXmlFile, latOben, lonOben, latUnten, lonUnten, art);
//Daten auswerten
datenHolen(osmXmlFile, geoobjekte, lat, lon, art);
} catch (Exception ex) {
Logger.getLogger(Geodaten.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Distanz zum Ausgangsort berechnen
private static double distanceInKm(double lat1, double lon1, double lat2, double lon2) {
//Erdumfang
int radius = 6371;
//Werte abziehen
double lat = Math.toRadians(lat2 - lat1);
double lon = Math.toRadians(lon2- lon1);
//Berechnung
double ausgabe = Math.sin(lat / 2) * Math.sin(lat / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(lon / 2) * Math.sin(lon / 2);
ausgabe = 2 * Math.atan2(Math.sqrt(ausgabe), Math.sqrt(1 - ausgabe));
ausgabe = radius * ausgabe;
ausgabe = Math.round(Math.abs(ausgabe)*100)/100.0;
double distanceInKm = ausgabe;
return distanceInKm;
}
//Daten herunterladen
private static void downloadSample(File file, double latOben, double lonOben, double latUnten, double lonUnten, String art) throws IOException {
String grundUrl = "http://www.overpass-api.de/api/xapi?node[bbox=";
String lat02 = latOben+"";
String lon02 = lonOben+",";
String lat01 = latUnten+",";
String lon01 = lonUnten+",";
String url = grundUrl+lon01+lat01+lon02+lat02+"][amenity="+art+"][@meta]";
URL downloadUrl = new URL(url);
InputStream in = downloadUrl.openStream();
OutputStream out = new FileOutputStream(file);
byte[] buffer = new byte[10000];
try {
int len = in.read(buffer);
while (len > 0) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
} finally {
out.close();
in.close();
}
}
void datenHolen(File osmXmlFile, ArrayList <GeodatenObjekte> geoobjekte, double lat, double lon, String art) throws ParserConfigurationException, SAXException, IOException, Exception{
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(osmXmlFile);
//Normalisieren
doc.getDocumentElement().normalize();
//Arten
NodeList nList = doc.getElementsByTagName("node");
//XML durchgehen
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Node item = nList.item(temp);
NamedNodeMap attributes = item.getAttributes();
String name = art;
if (item.getNodeName().equals("node")) {
NodeList tagXMLNodes = item.getChildNodes();
Map<String, String> tags = new HashMap<>();
for (int j = 1; j < tagXMLNodes.getLength(); j++) {
Node tagItem = tagXMLNodes.item(j);
NamedNodeMap tagAttributes = tagItem.getAttributes();
if (tagAttributes != null) {
tags.put(tagAttributes.getNamedItem("k").getNodeValue(), tagAttributes.getNamedItem("v")
.getNodeValue());
if (tagAttributes.getNamedItem("k").getNodeValue().equalsIgnoreCase("name")){
name = (tagAttributes.getNamedItem("v").getNodeValue());
}
}
}
}
if(name.equals(art)){
String b = "" + art.charAt(0);
b = b.toUpperCase();
name = b + art.substring(1);
}
String osmNr = attributes.getNamedItem("id").getNodeValue();
double lat_x = Double.parseDouble(attributes.getNamedItem("lat").getNodeValue());
double lon_x = Double.parseDouble(attributes.getNamedItem("lon").getNodeValue());
double distanz = distanceInKm(lat_x, lon_x, lat, lon);
String ortsangabe = ortBestimmen(lat_x, lon_x);
geoobjekte.add(new GeodatenObjekte(osmNr, lat_x, lon_x,name,ortsangabe,distanz));
}
}
}
private static String ortBestimmen(double lat_x,double lon_x) throws Exception
{
int responseCode = 0;
String address = "Ort unbekannt";
String api = "http://maps.googleapis.com/maps/api/geocode/xml?latlng="+lat_x+','+lon_x+"&sensor=true";
URL url = new URL(api);
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
httpConnection.connect();
responseCode = httpConnection.getResponseCode();
if(responseCode == 200)
{
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();;
Document document = builder.parse(httpConnection.getInputStream());
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("/GeocodeResponse/status");
String status = (String)expr.evaluate(document, XPathConstants.STRING);
if(status.equals("OK"))
{
expr = xpath.compile("//formatted_address");
address = (String)expr.evaluate(document, XPathConstants.STRING);
address = address.replace(", Germany", "");
}
}
return address;
}
private static final Comparator<GeodatenObjekte> Entfernung = new Comparator<GeodatenObjekte>() {
@Override
public int compare(GeodatenObjekte first, GeodatenObjekte second) {
return doCompare(first.getDistanz(), second.getDistanz());
}
};
private static <T extends Comparable<? super T>> int doCompare(T t0, T t1)
{
if (t0 == null)
{
if (t1 == null)
{
return 0;
}
return 1;
}
if (t1 == null)
{
return -1;
}
return t0.compareTo(t1);
}
}