Review eines Programms mit OSM-Abfragen

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);
       }
    
    
    
  }  

Das könnte hier untergehen. (Es ist mir auch gerade nicht ganz klar, wer du bist…)

Spricht was dagegen, das in einen eigenen Thread zu verschieben?
[wurde inzwischen verschoben]

Hallo Marco13, Nein dagegen spricht nichts.

Ein Problem des Programms ist, dass die Sprache zwar auf Deutsch ist, die Abfragen allerdings auf Englisch sein müssen. Das ist unpraktisch. Eine eigene Datenbank zu erstellen wäre wohl ein wenig aufwendig. Mir kam die Idee das Ganze mittels glosbe.com zu lösen. Dort kann gibt es eine API zum übersetzen, allerdings ist diese für mich zu komplex. Ich bekomme sie nicht geparst. Hier ein Beispiel. Kann jemand helfen?

mit dem OSM-Programm beschäftigst du dich doch anscheinend just auch schon mit Senden von HTML-Querys an eine API, was dir anscheinend bei glosbe auch schon gelingt,
und Parsen des XML-Ergebnisses mit z.B. DocumentBuilder / XPath,

da hast du bei glosbe doch genau dasselbe Problem, wieso Schwierigkeit?
ist dir XML und die Suche darin nach Elementen usw. nicht klar? das ist ein Thema für sich, bestens dokumentiert, findet man doch überall

und so kompliziert sieht das Ergebnis von glosbe nicht aus, meanings-Unterelemente, darunter liste mit Einträgen/ Beschreibungen


die Suche zeigt aber gut, wie wenig wahrscheinlich so eine Übersetzung zu nutzen ist,
‘bank’ war freilich ein besonders mehrdeutiges Wort,
aber die Ergebnisse über Sitzgelegenheit (Sport und anderes unterschieden), Finanzinstitut, ‘A place where bodies or substances of the human body are preserved’,
Sandbank bis hin zu geologischen Schichten…

wie willst du da im Programm sinnvolle Auswahl treffen falls mal mehrdeutig…, automatische Übersetzer sind ja mehr Star Trek, riesiges eigenes Problem,
dürfte das vorhandene Programm, egal zu welchem Zweck, fast immer übersteigen

wenn dein Programm nur begrenzten Wortschatz hat, dann lieber manuell gewählte Übersetzung gleich beifügen,
wenn es für beliebige Eingaben ist, dann kannst du nicht Übersetzung anbieten, nicht wenn du nicht google bist mit 500 Mitarbeitern dafür…

vielleicht noch Benutzer von mehreren Übersetungen auswählen lassen, Kontrolle und Verantwortung über letztliche englische Eingabe bieten,
nur intern etwas vorübersetzen/ Vorschläge machen