com.graphhopper.matching.GPXFile Maven / Gradle / Ivy
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.matching;
import com.graphhopper.routing.Path;
import com.graphhopper.util.Constants;
import com.graphhopper.util.GPXEntry;
import com.graphhopper.util.Helper;
import com.graphhopper.util.Instruction;
import com.graphhopper.util.InstructionList;
import com.graphhopper.util.PointList;
import com.graphhopper.util.Translation;
import java.io.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* A simple utility method to import from and export to GPX files.
*
* @author Peter Karich
*/
public class GPXFile {
static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
static final String DATE_FORMAT_Z = "yyyy-MM-dd'T'HH:mm:ss'Z'";
static final String DATE_FORMAT_Z_MS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
private final List entries;
private final boolean includeElevation = false;
private InstructionList instructions;
public GPXFile() {
entries = new ArrayList();
}
public GPXFile(List entries) {
this.entries = entries;
}
public GPXFile(MatchResult mr, InstructionList il) {
this.instructions = il;
this.entries = new ArrayList(mr.getEdgeMatches().size());
// TODO fetch time from GPX or from calculated route?
long time = 0;
for (int emIndex = 0; emIndex < mr.getEdgeMatches().size(); emIndex++) {
EdgeMatch em = mr.getEdgeMatches().get(emIndex);
PointList pl = em.getEdgeState().fetchWayGeometry(emIndex == 0 ? 3 : 2);
for (int i = 0; i < pl.size(); i++) {
if (pl.is3D()) {
entries.add(new GPXEntry(pl.getLatitude(i), pl.getLongitude(i), pl.getElevation(i), time));
} else {
entries.add(new GPXEntry(pl.getLatitude(i), pl.getLongitude(i), time));
}
}
}
}
public List getEntries() {
return entries;
}
public GPXFile doImport(String fileStr) {
try {
return doImport(new FileInputStream(fileStr));
} catch (FileNotFoundException ex) {
throw new RuntimeException(ex);
}
}
public GPXFile doImport(InputStream is) {
SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
SimpleDateFormat formatterZ = new SimpleDateFormat(DATE_FORMAT_Z);
SimpleDateFormat formatterZMS = new SimpleDateFormat(DATE_FORMAT_Z_MS);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringElementContentWhitespace(true);
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(is);
NodeList nl = doc.getElementsByTagName("trkpt");
for (int index = 0; index < nl.getLength(); index++) {
Node n = nl.item(index);
if (!(n instanceof Element)) {
continue;
}
Element e = (Element) n;
double lat = Double.parseDouble(e.getAttribute("lat"));
double lon = Double.parseDouble(e.getAttribute("lon"));
NodeList timeNodes = e.getElementsByTagName("time");
if (timeNodes.getLength() == 0) {
throw new IllegalStateException("GPX without time is illegal");
}
String text = timeNodes.item(0).getTextContent();
long millis;
if (text.contains("Z")) {
try {
// Try whole second matching
millis = formatterZ.parse(text).getTime();
} catch (ParseException ex) {
// Error: try looking at milliseconds
millis = formatterZMS.parse(text).getTime();
}
} else {
millis = formatter.parse(revertTZHack(text)).getTime();
}
NodeList eleNodes = e.getElementsByTagName("ele");
if (eleNodes.getLength() == 0) {
entries.add(new GPXEntry(lat, lon, millis));
} else {
double ele = Double.parseDouble(eleNodes.item(0).getTextContent());
entries.add(new GPXEntry(lat, lon, ele, millis));
}
}
return this;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Hack to parse time in Java and convert +0100 into +01:00
*/
private static String revertTZHack(String str) {
return str.substring(0, str.length() - 3) + str.substring(str.length() - 2);
}
@Override
public String toString() {
return "entries " + entries.size() + ", " + entries;
}
// TODO DUPLICATE CODE from GraphHopper InstructionList!
//
public String createString() {
long startTimeMillis = 0;
SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT_Z);
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
String header = ""
+ ""
+ "\n"
+ " "
+ ""
+ "GraphHopper GPX "
+ ""
+ ""
+ " ";
StringBuilder gpxOutput = new StringBuilder(header);
gpxOutput.append("\n").append("GraphHopper MapMatching").append(" ");
if (instructions != null && !instructions.isEmpty()) {
gpxOutput.append("\n");
Instruction nextInstr = null;
for (Instruction currInstr : instructions) {
if (null != nextInstr) {
instructions.createRteptBlock(gpxOutput, nextInstr, currInstr);
}
nextInstr = currInstr;
}
instructions.createRteptBlock(gpxOutput, nextInstr, null);
gpxOutput.append("\n ");
}
gpxOutput.append("");
for (GPXEntry entry : entries) {
gpxOutput.append("\n");
if (includeElevation) {
gpxOutput.append("").append(Helper.round2(entry.getEle())).append(" ");
}
gpxOutput.append("");
gpxOutput.append(" ");
}
gpxOutput.append(" ");
gpxOutput.append(" ");
// we could now use 'wpt' for via points
gpxOutput.append(" ");
return gpxOutput.toString().replaceAll("\\'", "\"");
}
public GPXFile doExport(String gpxFile) {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(gpxFile));
writer.append(createString());
return this;
} catch (IOException ex) {
throw new IllegalStateException(ex);
} finally {
Helper.close(writer);
}
}
public static void write(Path path, String gpxFile, Translation translation) {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(gpxFile));
writer.append(path.calcInstructions(translation).createGPX());
} catch (IOException ex) {
throw new IllegalStateException(ex);
} finally {
Helper.close(writer);
}
}
}