brouter/brouter-routing-app/src/main/java/btools/routingapp/CoordinateReader.java
2023-03-16 17:06:09 +01:00

296 lines
9.1 KiB
Java

package btools.routingapp;
import android.graphics.Point;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import btools.router.OsmNodeNamed;
import btools.router.OsmNogoPolygon;
/**
* Read coordinates from a gpx-file
*/
public class CoordinateReader {
protected static String[] posnames
= new String[]{"from", "via1", "via2", "via3", "via4", "via5", "via6", "via7", "via8", "via9", "to"};
private final String internalDir;
public List<OsmNodeNamed> waypoints;
public List<OsmNodeNamed> nogopoints;
public String basedir;
public String rootdir;
public String tracksdir;
public List<OsmNodeNamed> allpoints;
private boolean nogosOnly;
private Map<String, Map<String, OsmNodeNamed>> allpointsMap;
private HashMap<String, OsmNodeNamed> pointmap;
public CoordinateReader(String basedir) {
this.basedir = basedir;
internalDir = basedir + "/brouter/import";
tracksdir = "/brouter/import/tracks";
rootdir = "/brouter/import";
}
public static CoordinateReader obtainValidReader(String basedir) throws IOException {
return obtainValidReader(basedir, false);
}
public static CoordinateReader obtainValidReader(String basedir, boolean nogosOnly) throws IOException {
CoordinateReader cor = new CoordinateReader(basedir);
cor.nogosOnly = nogosOnly;
cor.readFromTo();
return cor;
}
public int getTurnInstructionMode() {
return 4; // comment style
}
/*
* read the from and to position from a gpx-file
* (with hardcoded name for now)
*/
public void readPointmap() throws IOException {
if (!_readPointmap(internalDir + "/favourites_bak.gpx")) {
_readPointmap(internalDir + "/favourites.gpx");
}
_readNogoLines(basedir + tracksdir);
}
private boolean _readPointmap(String filename) throws IOException {
BufferedReader br;
try {
br = new BufferedReader(
new InputStreamReader(
new FileInputStream(filename)));
} catch (FileNotFoundException e) {
// ignore until it's reading error
return false;
}
OsmNodeNamed n = null;
for (; ; ) {
String line = br.readLine();
if (line == null) break;
int idx0 = line.indexOf(" lat=\"");
int idx10 = line.indexOf("<name>");
if (idx0 >= 0) {
n = new OsmNodeNamed();
idx0 += 6;
int idx1 = line.indexOf('"', idx0);
n.ilat = (int) ((Double.parseDouble(line.substring(idx0, idx1)) + 90.) * 1000000. + 0.5);
int idx2 = line.indexOf(" lon=\"");
if (idx2 < 0) continue;
idx2 += 6;
int idx3 = line.indexOf('"', idx2);
n.ilon = (int) ((Double.parseDouble(line.substring(idx2, idx3)) + 180.) * 1000000. + 0.5);
if (idx3 < 0) continue;
}
if (n != null && idx10 >= 0) {
idx10 += 6;
int idx11 = line.indexOf("</name>", idx10);
if (idx11 >= 0) {
n.name = line.substring(idx10, idx11).trim();
checkAddPoint("(one-for-all)", n);
}
}
}
br.close();
return true;
}
private void _readNogoLines(String dirname) {
File dir = new File(dirname);
if (dir.exists() && dir.isDirectory()) {
for (final File file : dir.listFiles()) {
final String name = file.getName();
if (name.startsWith("nogo") && name.endsWith(".gpx")) {
try {
_readNogoLine(file);
} catch (Exception ignored) {
}
}
}
}
}
private void _readNogoLine(File file) throws Exception {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new FileReader(file));
List<Point> tmpPts = new ArrayList<>();
int eventType = xpp.getEventType();
int numSeg = 0;
boolean bIsNogoPoint = false;
String sNogoName = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG: {
if (xpp.getName().equals("trkpt") || xpp.getName().equals("rtept") || xpp.getName().equals("wpt")) {
final String lon = xpp.getAttributeValue(null, "lon");
final String lat = xpp.getAttributeValue(null, "lat");
if (lon != null && lat != null) {
tmpPts.add(new Point(
(int) ((Double.parseDouble(lon) + 180.) * 1000000. + 0.5),
(int) ((Double.parseDouble(lat) + 90.) * 1000000. + 0.5)));
if (xpp.getName().equals("wpt")) bIsNogoPoint = true;
}
} else if (bIsNogoPoint && xpp.getName().equals("name")) {
sNogoName = xpp.nextText();
}
break;
}
case XmlPullParser.END_TAG: {
if (xpp.getName().equals("trkseg") || xpp.getName().equals("rte")) { // rte has no segment
OsmNogoPolygon nogo;
if (tmpPts.size() > 0) {
if (tmpPts.get(0).x == tmpPts.get(tmpPts.size() - 1).x &&
tmpPts.get(0).y == tmpPts.get(tmpPts.size() - 1).y) {
nogo = new OsmNogoPolygon(true);
} else {
nogo = new OsmNogoPolygon(false);
}
for (Point p : tmpPts) {
nogo.addVertex(p.x, p.y);
}
nogo.calcBoundingCircle();
final String name = file.getName();
nogo.name = name.substring(0, name.length() - 4);
if (numSeg > 0) {
nogo.name += Integer.toString(numSeg + 1);
}
numSeg++;
checkAddPoint("(one-for-all)", nogo);
}
tmpPts.clear();
} else if (xpp.getName().equals("wpt")) {
Point p = tmpPts.get(tmpPts.size() - 1);
if (p != null) {
OsmNodeNamed nogo = new OsmNodeNamed();
nogo.ilon = p.x;
nogo.ilat = p.y;
nogo.name = (sNogoName != null ? sNogoName : "nogo1000 x");
nogo.isNogo = true;
nogo.radius = 20;
try {
nogo.radius = (sNogoName != null ? Integer.parseInt(sNogoName.substring(4, sNogoName.indexOf(" "))) : 20);
} catch (Exception e) {
try {
nogo.radius = (sNogoName != null ? Integer.parseInt(sNogoName.substring(4)) : 20);
} catch (Exception e1) {
nogo.radius = 20;
}
}
bIsNogoPoint = false;
sNogoName = null;
checkAddPoint("(one-for-all)", nogo);
tmpPts.clear();
}
}
break;
}
}
eventType = xpp.next();
}
}
public void readAllPoints() throws Exception {
allpointsMap = new TreeMap<>();
readFromTo();
allpoints = new ArrayList<>();
Set<String> names = new HashSet<>();
for (String category : allpointsMap.keySet()) {
Map<String, OsmNodeNamed> cat = allpointsMap.get(category);
if (cat != null && cat.size() < 101) {
for (OsmNodeNamed wp : cat.values()) {
if (names.add(wp.name)) {
allpoints.add(wp);
}
}
} else {
OsmNodeNamed nocatHint = new OsmNodeNamed();
nocatHint.name = "<big category " + category + " supressed>";
allpoints.add(nocatHint);
}
}
}
/*
* read the from, to and via-positions from a gpx-file
*/
public void readFromTo() throws IOException {
pointmap = new HashMap<>();
waypoints = new ArrayList<>();
nogopoints = new ArrayList<>();
readPointmap();
boolean fromToMissing = false;
for (String name : posnames) {
OsmNodeNamed n = pointmap.get(name);
if (n != null) {
waypoints.add(n);
} else {
if ("from".equals(name)) fromToMissing = true;
if ("to".equals(name)) fromToMissing = true;
}
}
if (fromToMissing) waypoints.clear();
}
protected void checkAddPoint(String category, OsmNodeNamed n) {
if (allpointsMap != null) {
if (category == null) category = "";
Map<String, OsmNodeNamed> cat = allpointsMap.get(category);
if (cat == null) {
cat = new TreeMap<>();
allpointsMap.put(category, cat);
}
if (cat.size() < 101) {
cat.put(n.name, n);
}
return;
}
boolean isKnown = false;
for (String posname : posnames) {
if (posname.equals(n.name)) {
isKnown = true;
break;
}
}
if (isKnown) {
if (pointmap.put(n.name, n) != null) {
if (!nogosOnly) {
throw new IllegalArgumentException("multiple " + n.name + "-positions!");
}
}
} else if (n.name != null && n.name.startsWith("nogo")) {
n.isNogo = true;
n.nogoWeight = Double.NaN;
nogopoints.add(n);
}
}
}