package common;
/********************************************************************************************************************
* $Id: Cookie.java 859 2008-03-31 10:17:30Z wolfgang_fahl $
*
* Copyright (c) 2008, Wolfgang Fahl, BITPlan GmbH (http://www.bitplan.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.StringReader;
import java.io.Writer;
import java.text.NumberFormat;
import java.util.StringTokenizer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.xml.serialize.DOMSerializer;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import com.meterware.httpunit.*;
/**
* get a Route from Google Maps and convert it as a GPX file
* useable by Garmin tracking devices - can be imported in MapSource software then ...
*
*/
public class GoogleMapsExample {
/**
* shall we show debug information?
*/
private boolean DEBUG=true;
/**
* get a Route description as a Garmin compatible GPX file
* @param startPoint
* @param destPoint
*/
public void getRouteAsGPX(String startPoint,String destPoint, String filename,boolean withDisplay) throws Exception {
String kml=getRouteFromGoogleMaps(startPoint,destPoint,withDisplay,false);
if (DEBUG) {
System.out.println(kml);
}
// http://wiki.openstreetmap.org/index.php/JOSM
// here is a so called open source kml to gpx converter
// http://www.fish-track.com/?page_id=3
Document gpxdoc=convertKMLtoGPX(kml);
// output the result
xmlSerialize(gpxdoc,filename);
}
/**
* create the xml output for the given document
* @param document
* @param filename
* @throws Exception
*/
public void xmlSerialize(Document document,String filename) throws Exception {
OutputFormat outputOptions = new OutputFormat();
// outputOptions.setOmitXMLDeclaration(true);
outputOptions.setIndent( 4 );
outputOptions.setMethod( "xml" );
//if (System.getProperty("os.name").startsWith("Windows")) {
outputOptions.setEncoding("ISO-8859-1");
Writer writer = new BufferedWriter(new FileWriter(new File(filename)));
DOMSerializer serializer = new XMLSerializer( writer,outputOptions );
serializer.serialize( document );
writer.close();
}
/**
* get the subnode with the given tagname
* @param parent
* @param tagName
* @return
*/
public Element getSubNode(Element parent,String tagName, boolean throwException) {
NodeList subNodes=parent.getElementsByTagName(tagName);
if (subNodes.getLength()!=1) {
if (throwException)
throw new RuntimeException("getSubNode failed for "+parent+" expected 1 child with tag name '"+tagName+"' but got "+subNodes.getLength());
else
return null;
}
return (Element)subNodes.item(0);
}
/**
* get the latitude and longitude from a route point
* @param kmlRoutePoint
* @return
*/
public String[] extractCoordinates(Element kmlRoutePoint) {
String[] result=new String[2];
Element point=getSubNode(kmlRoutePoint,"Point",false);
if (point==null)
return null;
Element coordNode=getSubNode(point,"coordinates",true);
String coords=coordNode.getTextContent();
StringTokenizer coordSplitter=new StringTokenizer(coords,",",false);
if (coordSplitter.countTokens()<=2) {
throw new RuntimeException("extract coordinates failed for "+kmlRoutePoint+" expected at least two coordinates but got "+coordSplitter.countTokens()+" '"+coords+"'");
}
result[0]=coordSplitter.nextToken();
result[1]=coordSplitter.nextToken();
return result;
}
/**
* convert the given kml file to gpx format
* @param kml - the kml version of the file
* @return
*/
public Document convertKMLtoGPX(String kml) throws Exception {
DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
DocumentBuilder builder= factory.newDocumentBuilder();
Document kmldoc = builder.parse(new InputSource(new StringReader(kml)) );
Document gpxdoc = builder.newDocument();
String comment="Converted by httpunit GoogleMapsExample";
gpxdoc.appendChild(gpxdoc.createComment(comment));
org.w3c.dom.Element root = gpxdoc.createElement("gpx");
root.setAttribute("xmlns", "http://www.topografix.com/GPX/1/1");
root.setAttribute("creator","KML2GPX Example by BITPlan");
root.setAttribute("version","1.1");
gpxdoc.appendChild(root);
org.w3c.dom.Element metadata = gpxdoc.createElement("metadata");
org.w3c.dom.Element metadatalink = gpxdoc.createElement("link");
metadatalink.setAttribute("href","http://www.bitplan.com");
metadata.appendChild(metadatalink);
org.w3c.dom.Element metadatatext = gpxdoc.createElement("text");
metadatatext.setTextContent("BITPlan GmbH, Willich, Germany");
metadatalink.appendChild(metadatatext);
root.appendChild(metadata);
org.w3c.dom.Element route = gpxdoc.createElement("rte");
root.appendChild(route);
NodeList routePoints=kmldoc.getElementsByTagName("Placemark");
for (int i=0;i<routePoints.getLength();i++) {
Element kmlRoutePoint=(Element)routePoints.item(i);
String name=getSubNode(kmlRoutePoint,"name",true).getTextContent();
if (DEBUG)
System.out.println("found route point "+i+": "+name);
String coords[]=extractCoordinates(kmlRoutePoint);
if (coords!=null) {
org.w3c.dom.Element routePoint = gpxdoc.createElement("rtept");
routePoint.setAttribute("lon", coords[0] );
routePoint.setAttribute("lat", coords[1] );
org.w3c.dom.Element routePointName=gpxdoc.createElement("name");
routePointName.setTextContent(name);
routePoint.appendChild(routePointName);
route.appendChild(routePoint);
}
}
return gpxdoc;
}
/**
* the url to use
*/
public static String url="http://maps.google.com/maps";
/**
* the directions string to look for
*/
public static String directions="directions";
/**
This is how to use the example in germany:
GoogleMapsExample.url="http://maps.google.de/maps";
GoogleMapsExample.directions="Route berechnen";
*/
/**
* get a route from google maps with the given start and destination points
* @param startPoint
* @param destPoint
* @param withDisplay
* @param asKML
*/
public String getRouteFromGoogleMaps(String startPoint,String destPoint, boolean withDisplay, boolean asKML) throws Exception {
// and now indirectly
// create the conversation object which will maintain state for us
WebConversation wc = new WebConversation();
// Obtain the main page on the meterware web site
WebRequest request = new GetMethodWebRequest(url);
request.setParameter("output", "html");
WebResponse response = wc.getResponse( request );
if (withDisplay && DEBUG)
BrowserDisplayer.showResponseInBrowser(response);
// find the link which contains the string for directions and click it
WebLink directionsLink = response.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, directions);
if (directionsLink==null) {
System.err.println("could not find "+directions+" in response");
if (DEBUG)
BrowserDisplayer.showResponseInBrowser(response);
System.exit(1);
}
response = directionsLink.click();
if (withDisplay && DEBUG)
BrowserDisplayer.showResponseInBrowser(response);
WebForm lookupForm = response.getFormWithID("d_form");
request = lookupForm.getRequest();
request.setParameter( "saddr", startPoint );
request.setParameter( "daddr", destPoint );
response = wc.getResponse( request );
if (withDisplay)
BrowserDisplayer.showResponseInBrowser(response);
if (asKML) {
// request.setParameter("output", "kml");
FormParameter parameter = lookupForm.getParameter( "output" );
FormControl outputControl=parameter.getControl();
outputControl.setAttribute("value", "kml");
response = wc.getResponse( request );
if (withDisplay && DEBUG)
BrowserDisplayer.showResponseInBrowser(response);
}
return (response.getText());
}
/**
* get the distance between to given Zip codes
* @param
*/
public String getDistance(String startPoint, String endPoint, boolean withDisplay) throws Exception {
String route=getRouteFromGoogleMaps(startPoint,endPoint,withDisplay,false);
String [] driveLocale={"Drive:","Fahrt:"};
String [] unitLocale ={"mi","km"};
for (int i=0;i<driveLocale.length;i++) {
int drivePos=route.indexOf(driveLocale[i]);
if (drivePos>0) {
String driveString=route.substring(drivePos);
int unitPos=driveString.indexOf(unitLocale[i]);
if (unitPos>0) {
String distanceString=driveString.substring(1, unitPos+unitLocale[i].length());
int divPos;
while ((divPos=distanceString.indexOf("<div>"))>0) {
distanceString=distanceString.substring(divPos+5);
}
distanceString=distanceString.replace(" "," ");
return distanceString;
}
}
}
return "?";
}
/**
* Start the Route as GPX converter with the given command line parameters
* display usage with and example if no parameters are given
* @param params
*/
public static void main( String[] params ) {
try {
if (params.length < 3) {
System.out.println( "Usage: java RouteAsGPX [from] [to] ([filename]|'distance') [nodisplay]" );
System.out.println( " e.g. java RouteAsGPX sfo 94526 sfoexample.gpx");
System.out.println( " to get the route as a Garmin compatible GPX file");
System.out.println( " e.g. java RouteAsGPX sfo 94526 distance");
System.out.println( " to calculate the distance");
String[] defaultParams={"sfo","94526","distance"};
// defaultParams={"sfo","94526","sfoexample.gpx"};
params=defaultParams;
System.out.println( "will demonstrate usage with the route "+defaultParams[0]+" - "+defaultParams[1]+" and store to "+defaultParams[2]);
}
GoogleMapsExample routeAsGPX=new GoogleMapsExample();
boolean withDisplay=true;
if (params.length>=4)
withDisplay=false;
String startPoint=params[0];
String endPoint =params[1];
String filename =params[2];
if (filename.equals("distance")) {
String distanceS=routeAsGPX.getDistance(startPoint, endPoint, withDisplay);
// String distanceS=NumberFormat.getInstance().format(distance);
System.out.println("The distance between "+startPoint+" and "+endPoint+" is "+distanceS);
} else {
routeAsGPX.getRouteAsGPX(startPoint, endPoint, filename,withDisplay);
}
} catch (Exception e) {
System.err.println( "Exception: " + e );
e.printStackTrace();
}
}
}