@@ -50,14 +50,13 @@
import java.util.List;

import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;
import static slash.common.io.Transfer.trim;
import static slash.navigation.base.RouteCharacteristics.Track;
import static slash.navigation.base.RouteCharacteristics.Waypoints;
import static slash.navigation.googlemaps.GoogleMapsPosition.parsePosition;
import static slash.navigation.googlemaps.GoogleMapsPosition.parsePositions;
import static slash.navigation.kml.KmlUtil.marshal20;
import static slash.navigation.kml.KmlUtil.unmarshal20;
import static slash.navigation.util.RouteComments.commentRoutePositions;

/**
* Reads and writes Google Earth 3 (.kml) files.
@@ -72,39 +71,31 @@ public String getName() {
}

public void read(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws Exception {
process(source, startDate, context);
}

void process(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException, JAXBException {
Object o = unmarshal20(source);
if (o instanceof Kml) {
Kml kml = (Kml) o;
context.addRoutes(extractTracks(kml.getDocument(), kml.getFolder(), startDate));
extractTracks(kml.getDocument(), kml.getFolder(), startDate, context);
}
if (o instanceof Document) {
Document document = (Document) o;
context.addRoutes(extractTracks(document, null, startDate));
extractTracks(document, null, startDate, context);
}
if (o instanceof Folder) {
Folder folder = (Folder) o;
context.addRoutes(extractTracks(null, folder, startDate));
extractTracks(null, folder, startDate, context);
}
}

private List<KmlRoute> extractTracks(Document document, Folder folder, CompactCalendar startDate) {
private void extractTracks(Document document, Folder folder, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
List<Object> elements = null;
if (document != null && document.getDocumentOrFolderOrGroundOverlay().size() > 0)
elements = document.getDocumentOrFolderOrGroundOverlay();

if (folder != null && folder.getDocumentOrFolderOrGroundOverlay().size() > 0)
elements = folder.getDocumentOrFolderOrGroundOverlay();

if (elements == null)
return emptyList();

List<KmlRoute> routes = extractTracks(extractName(elements), extractDescriptionList(elements), elements, startDate);
commentRoutePositions(routes);
return routes;
if (elements != null)
extractTracks(extractName(elements), extractDescriptionList(elements), elements, startDate, context);
}

private JAXBElement findElement(List elements, String name) {
@@ -187,29 +178,23 @@ private List<NetworkLink> findNetworkLinks(List<Object> elements) {
return networkLinks;
}

private List<KmlRoute> extractTracks(String name, List<String> description, List<Object> elements, CompactCalendar startDate) {
List<KmlRoute> result = new ArrayList<KmlRoute>();

private void extractTracks(String name, List<String> description, List<Object> elements, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
List<Placemark> placemarks = findPlacemarks(elements);
result.addAll(extractWayPointsAndTracksFromPlacemarks(name, description, placemarks, startDate));
extractWayPointsAndTracksFromPlacemarks(name, description, placemarks, startDate, context);

List<NetworkLink> networkLinks = findNetworkLinks(elements);
result.addAll(extractWayPointsAndTracksFromNetworkLinks(networkLinks));
extractWayPointsAndTracksFromNetworkLinks(networkLinks, context);

List<Folder> folders = findFolders(elements);
for (Folder folder : folders) {
List<Object> overlays = folder.getDocumentOrFolderOrGroundOverlay();
String folderName = concatPath(name, extractName(overlays));
result.addAll(extractTracks(folderName, description, overlays, startDate));
extractTracks(folderName, description, overlays, startDate, context);
}

return result;
}

private List<KmlRoute> extractWayPointsAndTracksFromPlacemarks(String name, List<String> description, List<Placemark> placemarks, CompactCalendar startDate) {
List<KmlRoute> result = new ArrayList<KmlRoute>();

List<KmlPosition> wayPoints = new ArrayList<KmlPosition>();
private void extractWayPointsAndTracksFromPlacemarks(String name, List<String> description, List<Placemark> placemarks, CompactCalendar startDate, ParserContext<KmlRoute> context) {
List<KmlPosition> waypoints = new ArrayList<KmlPosition>();
for (Placemark placemark : placemarks) {
String placemarkName = asComment(extractName(placemark.getDescriptionOrNameOrSnippet()),
extractDescription(placemark.getDescriptionOrNameOrSnippet()));
@@ -219,33 +204,28 @@ private List<KmlRoute> extractWayPointsAndTracksFromPlacemarks(String name, List
// all placemarks with one position form one waypoint route
KmlPosition wayPoint = positions.get(0);
enrichPosition(wayPoint, extractTime(placemark.getDescriptionOrNameOrSnippet()), placemarkName, extractDescription(placemark.getDescriptionOrNameOrSnippet()), startDate);
wayPoints.add(wayPoint);
waypoints.add(wayPoint);
} else {
// each placemark with more than one position is one track
String routeName = concatPath(name, asName(placemarkName));
List<String> routeDescription = extractDescriptionList(placemark.getDescriptionOrNameOrSnippet());
if (routeDescription == null)
routeDescription = description;
RouteCharacteristics characteristics = parseCharacteristics(routeName, Track);
result.add(new KmlRoute(this, characteristics, routeName, routeDescription, positions));
context.appendRoute(new KmlRoute(this, characteristics, routeName, routeDescription, positions));
}
}
if (wayPoints.size() != 0) {
if (waypoints.size() != 0) {
RouteCharacteristics characteristics = parseCharacteristics(name, Waypoints);
result.add(0, new KmlRoute(this, characteristics, name, description, wayPoints));
context.prependRoute(new KmlRoute(this, characteristics, name, description, waypoints));
}
return result;
}

private List<KmlRoute> extractWayPointsAndTracksFromNetworkLinks(List<NetworkLink> networkLinks) {
List<KmlRoute> result = new ArrayList<KmlRoute>();
private void extractWayPointsAndTracksFromNetworkLinks(List<NetworkLink> networkLinks, ParserContext<KmlRoute> context) throws IOException {
for (NetworkLink networkLink : networkLinks) {
String url = networkLink.getUrl().getHref();
List<KmlRoute> routes = parseRouteFromUrl(url);
if (routes != null)
result.addAll(routes);
context.parse(url);
}
return result;
}

private List<KmlPosition> extractPositions(LineString lineString) {
@@ -404,15 +384,15 @@ private Kml createKml(List<KmlRoute> routes) {

public void write(KmlRoute route, OutputStream target, int startIndex, int endIndex) throws IOException {
try {
KmlUtil.marshal20(createKml(route), target);
marshal20(createKml(route), target);
} catch (JAXBException e) {
throw new IllegalArgumentException(e);
}
}

public void write(List<KmlRoute> routes, OutputStream target) throws IOException {
try {
KmlUtil.marshal20(createKml(routes), target);
marshal20(createKml(routes), target);
} catch (JAXBException e) {
throw new IllegalArgumentException(e);
}
@@ -49,7 +49,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;

@@ -59,7 +58,6 @@
import static slash.navigation.base.RouteCharacteristics.Waypoints;
import static slash.navigation.kml.KmlUtil.marshal21;
import static slash.navigation.kml.KmlUtil.unmarshal21;
import static slash.navigation.util.RouteComments.commentRoutePositions;

/**
* Reads and writes Google Earth 4 (.kml) files.
@@ -74,21 +72,16 @@ public String getName() {
}

public void read(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws Exception {
process(source, startDate, context);
}

void process(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException, JAXBException {
KmlType kmlType = unmarshal21(source);
process(kmlType, startDate, context);
}

protected void process(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) {
protected void process(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
if (kmlType == null || kmlType.getFeature() == null)
return;
context.addRoutes(extractTracks(kmlType, startDate));
extractTracks(kmlType, startDate, context);
}


@SuppressWarnings({"UnusedDeclaration", "unchecked"})
private <T> List<JAXBElement<T>> find(List<JAXBElement<? extends FeatureType>> elements, String name, Class<T> resultClass) {
List<JAXBElement<T>> result = new ArrayList<JAXBElement<T>>();
@@ -99,9 +92,7 @@ private <T> List<JAXBElement<T>> find(List<JAXBElement<? extends FeatureType>> e
return result;
}

private List<KmlRoute> extractTracks(KmlType kmlType, CompactCalendar startDate) {
List<KmlRoute> routes = new ArrayList<KmlRoute>();

private void extractTracks(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
FeatureType feature = kmlType.getFeature().getValue();
if (feature instanceof ContainerType) {
ContainerType containerType = (ContainerType) feature;
@@ -110,7 +101,7 @@ private List<KmlRoute> extractTracks(KmlType kmlType, CompactCalendar startDate)
features = ((FolderType) containerType).getFeature();
else if (containerType instanceof DocumentType)
features = ((DocumentType) containerType).getFeature();
routes = extractTracks(trim(containerType.getName()), trim(containerType.getDescription()), features, startDate);
extractTracks(trim(containerType.getName()), trim(containerType.getDescription()), features, startDate, context);
}

if (feature instanceof PlacemarkType) {
@@ -122,42 +113,34 @@ else if (containerType instanceof DocumentType)
for (KmlPosition position : positions) {
enrichPosition(position, extractTime(placemarkType.getTimePrimitive()), placemarkName, placemarkType.getDescription(), startDate);
}
routes = Arrays.asList(new KmlRoute(this, Waypoints, placemarkName, null, positions));
context.appendRoute(new KmlRoute(this, Waypoints, placemarkName, null, positions));
}

commentRoutePositions(routes);
return routes;
}

private List<KmlRoute> extractTracks(String name, String description, List<JAXBElement<? extends FeatureType>> features, CompactCalendar startDate) {
List<KmlRoute> result = new ArrayList<KmlRoute>();

private void extractTracks(String name, String description, List<JAXBElement<? extends FeatureType>> features, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
List<JAXBElement<PlacemarkType>> placemarks = find(features, "Placemark", PlacemarkType.class);
result.addAll(extractWayPointsAndTracksFromPlacemarks(name, description, placemarks, startDate));
extractWayPointsAndTracksFromPlacemarks(name, description, placemarks, startDate, context);

List<JAXBElement<NetworkLinkType>> networkLinks = find(features, "NetworkLink", NetworkLinkType.class);
result.addAll(extractWayPointsAndTracksFromNetworkLinks(networkLinks));
extractWayPointsAndTracksFromNetworkLinks(networkLinks, context);

List<JAXBElement<FolderType>> folders = find(features, "Folder", FolderType.class);
for (JAXBElement<FolderType> folder : folders) {
FolderType folderTypeValue = folder.getValue();
String folderName = concatPath(name, folderTypeValue.getName());
result.addAll(extractTracks(folderName, description, folderTypeValue.getFeature(), startDate));
extractTracks(folderName, description, folderTypeValue.getFeature(), startDate, context);
}

List<JAXBElement<DocumentType>> documents = find(features, "Document", DocumentType.class);
for (JAXBElement<DocumentType> document : documents) {
DocumentType documentTypeValue = document.getValue();
String documentName = concatPath(name, documentTypeValue.getName());
result.addAll(extractTracks(documentName, description, documentTypeValue.getFeature(), startDate));
extractTracks(documentName, description, documentTypeValue.getFeature(), startDate, context);
}
return result;
}

private List<KmlRoute> extractWayPointsAndTracksFromPlacemarks(String name, String description, List<JAXBElement<PlacemarkType>> placemarkTypes, CompactCalendar startDate) {
List<KmlRoute> result = new ArrayList<KmlRoute>();

List<KmlPosition> wayPoints = new ArrayList<KmlPosition>();
private void extractWayPointsAndTracksFromPlacemarks(String name, String description, List<JAXBElement<PlacemarkType>> placemarkTypes, CompactCalendar startDate, ParserContext<KmlRoute> context) {
List<KmlPosition> waypoints = new ArrayList<KmlPosition>();
for (JAXBElement<PlacemarkType> placemarkType : placemarkTypes) {
PlacemarkType placemarkTypeValue = placemarkType.getValue();
String placemarkName = asComment(trim(placemarkTypeValue.getName()),
@@ -168,34 +151,29 @@ private List<KmlRoute> extractWayPointsAndTracksFromPlacemarks(String name, Stri
// all placemarks with one position form one waypoint route
KmlPosition wayPoint = positions.get(0);
enrichPosition(wayPoint, extractTime(placemarkTypeValue.getTimePrimitive()), placemarkName, placemarkTypeValue.getDescription(), startDate);
wayPoints.add(wayPoint);
waypoints.add(wayPoint);
} else {
// each placemark with more than one position is one track
String routeName = concatPath(name, asName(placemarkName));
List<String> routeDescription = asDescription(placemarkTypeValue.getDescription() != null ? placemarkTypeValue.getDescription() : description);
RouteCharacteristics characteristics = parseCharacteristics(routeName, Track);
result.add(new KmlRoute(this, characteristics, routeName, routeDescription, positions));
context.appendRoute(new KmlRoute(this, characteristics, routeName, routeDescription, positions));
}
}
if (wayPoints.size() > 0) {
if (waypoints.size() > 0) {
RouteCharacteristics characteristics = parseCharacteristics(name, Waypoints);
result.add(0, new KmlRoute(this, characteristics, name, asDescription(description), wayPoints));
context.prependRoute(new KmlRoute(this, characteristics, name, asDescription(description), waypoints));
}
return result;
}

private List<KmlRoute> extractWayPointsAndTracksFromNetworkLinks(List<JAXBElement<NetworkLinkType>> networkLinkTypes) {
List<KmlRoute> result = new ArrayList<KmlRoute>();
private void extractWayPointsAndTracksFromNetworkLinks(List<JAXBElement<NetworkLinkType>> networkLinkTypes, ParserContext<KmlRoute> context) throws IOException {
for (JAXBElement<NetworkLinkType> networkLinkType : networkLinkTypes) {
LinkType linkType = networkLinkType.getValue().getUrl();
if (linkType != null) {
String url = linkType.getHref();
List<KmlRoute> routes = parseRouteFromUrl(url);
if (routes != null)
result.addAll(routes);
context.parse(url);
}
}
return result;
}

private List<KmlPosition> extractPositions(JAXBElement<? extends GeometryType> geometryType) {
@@ -50,7 +50,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;

@@ -59,8 +58,8 @@
import static slash.common.io.Transfer.trim;
import static slash.navigation.base.RouteCharacteristics.Track;
import static slash.navigation.base.RouteCharacteristics.Waypoints;
import static slash.navigation.kml.KmlUtil.marshal22Beta;
import static slash.navigation.kml.KmlUtil.unmarshal22Beta;
import static slash.navigation.util.RouteComments.commentRoutePositions;

/**
* Reads and writes Google Earth 4.2 (.kml) files.
@@ -75,18 +74,14 @@ public String getName() {
}

public void read(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws Exception {
process(source, startDate, context);
}

void process(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException, JAXBException {
KmlType kmlType = unmarshal22Beta(source);
process(kmlType, startDate, context);
}

protected void process(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) {
protected void process(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
if (kmlType == null || kmlType.getAbstractFeatureGroup() == null)
return;
context.addRoutes(extractTracks(kmlType, startDate));
extractTracks(kmlType, startDate, context);
}

@SuppressWarnings({"UnusedDeclaration", "unchecked"})
@@ -99,9 +94,7 @@ private <T> List<JAXBElement<T>> find(List<JAXBElement<? extends AbstractFeature
return result;
}

private List<KmlRoute> extractTracks(KmlType kmlType, CompactCalendar startDate) {
List<KmlRoute> routes = new ArrayList<KmlRoute>();

private void extractTracks(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
AbstractFeatureType feature = kmlType.getAbstractFeatureGroup().getValue();
if (feature instanceof AbstractContainerType) {
AbstractContainerType containerType = (AbstractContainerType) feature;
@@ -110,7 +103,7 @@ private List<KmlRoute> extractTracks(KmlType kmlType, CompactCalendar startDate)
features = ((FolderType) containerType).getAbstractFeatureGroup();
else if (containerType instanceof DocumentType)
features = ((DocumentType) containerType).getAbstractFeatureGroup();
routes = extractTracks(trim(containerType.getNameElement()), trim(containerType.getDescription()), features, startDate);
extractTracks(trim(containerType.getNameElement()), trim(containerType.getDescription()), features, startDate, context);
}

if (feature instanceof PlacemarkType) {
@@ -122,42 +115,34 @@ else if (containerType instanceof DocumentType)
for (KmlPosition position : positions) {
enrichPosition(position, extractTime(placemarkType.getAbstractTimePrimitiveGroup()), placemarkName, placemarkType.getDescription(), startDate);
}
routes = Arrays.asList(new KmlRoute(this, Waypoints, placemarkName, null, positions));
context.appendRoute(new KmlRoute(this, Waypoints, placemarkName, null, positions));
}

commentRoutePositions(routes);
return routes;
}

private List<KmlRoute> extractTracks(String name, String description, List<JAXBElement<? extends AbstractFeatureType>> features, CompactCalendar startDate) {
List<KmlRoute> result = new ArrayList<KmlRoute>();

private void extractTracks(String name, String description, List<JAXBElement<? extends AbstractFeatureType>> features, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
List<JAXBElement<PlacemarkType>> placemarks = find(features, "Placemark", PlacemarkType.class);
result.addAll(extractWayPointsAndTracksFromPlacemarks(name, description, placemarks, startDate));
extractWayPointsAndTracksFromPlacemarks(name, description, placemarks, startDate, context);

List<JAXBElement<NetworkLinkType>> networkLinks = find(features, "NetworkLink", NetworkLinkType.class);
result.addAll(extractWayPointsAndTracksFromNetworkLinks(networkLinks));
extractWayPointsAndTracksFromNetworkLinks(networkLinks, context);

List<JAXBElement<FolderType>> folders = find(features, "Folder", FolderType.class);
for (JAXBElement<FolderType> folder : folders) {
FolderType folderTypeValue = folder.getValue();
String folderName = concatPath(name, folderTypeValue.getNameElement());
result.addAll(extractTracks(folderName, description, folderTypeValue.getAbstractFeatureGroup(), startDate));
extractTracks(folderName, description, folderTypeValue.getAbstractFeatureGroup(), startDate, context);
}

List<JAXBElement<DocumentType>> documents = find(features, "Document", DocumentType.class);
for (JAXBElement<DocumentType> document : documents) {
DocumentType documentTypeValue = document.getValue();
String documentName = concatPath(name, documentTypeValue.getNameElement());
result.addAll(extractTracks(documentName, description, documentTypeValue.getAbstractFeatureGroup(), startDate));
extractTracks(documentName, description, documentTypeValue.getAbstractFeatureGroup(), startDate, context);
}
return result;
}

private List<KmlRoute> extractWayPointsAndTracksFromPlacemarks(String name, String description, List<JAXBElement<PlacemarkType>> placemarkTypes, CompactCalendar startDate) {
List<KmlRoute> result = new ArrayList<KmlRoute>();

List<KmlPosition> wayPoints = new ArrayList<KmlPosition>();
private void extractWayPointsAndTracksFromPlacemarks(String name, String description, List<JAXBElement<PlacemarkType>> placemarkTypes, CompactCalendar startDate, ParserContext<KmlRoute> context) {
List<KmlPosition> waypoints = new ArrayList<KmlPosition>();
for (JAXBElement<PlacemarkType> placemarkType : placemarkTypes) {
PlacemarkType placemarkTypeValue = placemarkType.getValue();
String placemarkName = asComment(trim(placemarkTypeValue.getNameElement()),
@@ -168,31 +153,27 @@ private List<KmlRoute> extractWayPointsAndTracksFromPlacemarks(String name, Stri
// all placemarks with one position form one waypoint route
KmlPosition wayPoint = positions.get(0);
enrichPosition(wayPoint, extractTime(placemarkTypeValue.getAbstractTimePrimitiveGroup()), placemarkName, placemarkTypeValue.getDescription(), startDate);
wayPoints.add(wayPoint);
waypoints.add(wayPoint);
} else {
// each placemark with more than one position is one track
String routeName = concatPath(name, asName(placemarkName));
List<String> routeDescription = asDescription(placemarkTypeValue.getDescription() != null ? placemarkTypeValue.getDescription() : description);
RouteCharacteristics characteristics = parseCharacteristics(routeName, Track);
result.add(new KmlRoute(this, characteristics, routeName, routeDescription, positions));
context.appendRoute(new KmlRoute(this, characteristics, routeName, routeDescription, positions));
}
}
if (wayPoints.size() > 0) {
if (waypoints.size() > 0) {
RouteCharacteristics characteristics = parseCharacteristics(name, Waypoints);
result.add(0, new KmlRoute(this, characteristics, name, asDescription(description), wayPoints));
context.prependRoute(new KmlRoute(this, characteristics, name, asDescription(description), waypoints));
}
return result;
}

private List<KmlRoute> extractWayPointsAndTracksFromNetworkLinks(List<JAXBElement<NetworkLinkType>> networkLinkTypes) {
List<KmlRoute> result = new ArrayList<KmlRoute>();
private void extractWayPointsAndTracksFromNetworkLinks(List<JAXBElement<NetworkLinkType>> networkLinkTypes, ParserContext<KmlRoute> context) throws IOException {
for (JAXBElement<NetworkLinkType> networkLinkType : networkLinkTypes) {
Link link = networkLinkType.getValue().getLink();
if (link != null) {
String url = link.getHref();
List<KmlRoute> routes = parseRouteFromUrl(url);
if (routes != null)
result.addAll(routes);
context.parse(url);
}

List<JAXBElement<?>> rest = networkLinkType.getValue().getRest();
@@ -201,13 +182,10 @@ private List<KmlRoute> extractWayPointsAndTracksFromNetworkLinks(List<JAXBElemen
if (rValue instanceof LinkType) {
LinkType linkType = (LinkType) rValue;
String url = linkType.getHref();
List<KmlRoute> routes = parseRouteFromUrl(url);
if (routes != null)
result.addAll(routes);
context.parse(url);
}
}
}
return result;
}

private List<KmlPosition> extractPositions(JAXBElement<? extends AbstractGeometryType> geometryType) {
@@ -369,15 +347,15 @@ private KmlType createKmlType(List<KmlRoute> routes) {

public void write(KmlRoute route, OutputStream target, int startIndex, int endIndex) {
try {
KmlUtil.marshal22Beta(createKmlType(route), target);
marshal22Beta(createKmlType(route), target);
} catch (JAXBException e) {
throw new IllegalArgumentException(e);
}
}

public void write(List<KmlRoute> routes, OutputStream target) throws IOException {
try {
KmlUtil.marshal22Beta(createKmlType(routes), target);
marshal22Beta(createKmlType(routes), target);
} catch (JAXBException e) {
throw new IllegalArgumentException(e);
}
@@ -73,7 +73,6 @@
import static java.lang.Math.toDegrees;
import static java.lang.Math.toRadians;
import static java.lang.String.valueOf;
import static java.util.Arrays.asList;
import static slash.common.hex.HexDecoder.decodeBytes;
import static slash.common.io.Transfer.formatPositionAsString;
import static slash.common.io.Transfer.isEmpty;
@@ -82,8 +81,8 @@
import static slash.navigation.base.RouteCharacteristics.Track;
import static slash.navigation.base.RouteCharacteristics.Waypoints;
import static slash.navigation.googlemaps.GoogleMapsPosition.parseExtensionPositions;
import static slash.navigation.kml.KmlUtil.marshal22;
import static slash.navigation.kml.KmlUtil.unmarshal22;
import static slash.navigation.util.RouteComments.commentRoutePositions;

/**
* Reads and writes Google Earth 5 (.kml) files.
@@ -99,18 +98,14 @@ public String getName() {
}

public void read(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws Exception {
process(source, startDate, context);
}

void process(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException, JAXBException {
KmlType kmlType = unmarshal22(source);
process(kmlType, startDate, context);
}

protected void process(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) {
protected void process(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
if (kmlType == null || kmlType.getAbstractFeatureGroup() == null)
return;
context.addRoutes(extractTracks(kmlType, startDate));
extractTracks(kmlType, startDate, context);
}

@SuppressWarnings({"UnusedDeclaration", "unchecked"})
@@ -123,9 +118,7 @@ private <T> List<JAXBElement<T>> find(List<JAXBElement<? extends AbstractFeature
return result;
}

protected List<KmlRoute> extractTracks(KmlType kmlType, CompactCalendar startDate) {
List<KmlRoute> routes = new ArrayList<KmlRoute>();

protected void extractTracks(KmlType kmlType, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
AbstractFeatureType feature = kmlType.getAbstractFeatureGroup().getValue();
if (feature instanceof AbstractContainerType) {
AbstractContainerType containerType = (AbstractContainerType) feature;
@@ -134,7 +127,7 @@ protected List<KmlRoute> extractTracks(KmlType kmlType, CompactCalendar startDat
features = ((FolderType) containerType).getAbstractFeatureGroup();
else if (containerType instanceof DocumentType)
features = ((DocumentType) containerType).getAbstractFeatureGroup();
routes = extractTracks(trim(containerType.getName()), trim(containerType.getDescription()), features, startDate);
extractTracks(trim(containerType.getName()), trim(containerType.getDescription()), features, startDate, context);
}

if (feature instanceof PlacemarkType) {
@@ -145,7 +138,7 @@ else if (containerType instanceof DocumentType)
for (KmlPosition position : positions) {
enrichPosition(position, extractTime(placemarkType.getAbstractTimePrimitiveGroup()), placemarkName, placemarkType.getDescription(), startDate);
}
routes = asList(new KmlRoute(this, Waypoints, placemarkName, null, positions));
context.appendRoute(new KmlRoute(this, Waypoints, placemarkName, null, positions));
}

if (feature instanceof TourType) {
@@ -156,38 +149,32 @@ else if (containerType instanceof DocumentType)
for (KmlPosition position : positions) {
enrichPosition(position, extractTime(tourType.getAbstractTimePrimitiveGroup()), tourName, tourType.getDescription(), startDate);
}
routes = asList(new KmlRoute(this, Track, tourName, null, positions));
context.appendRoute(new KmlRoute(this, Track, tourName, null, positions));
}

commentRoutePositions(routes);
return routes;
}

private List<KmlRoute> extractTracks(String name, String description, List<JAXBElement<? extends AbstractFeatureType>> features, CompactCalendar startDate) {
List<KmlRoute> result = new ArrayList<KmlRoute>();

private void extractTracks(String name, String description, List<JAXBElement<? extends AbstractFeatureType>> features, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException {
List<JAXBElement<PlacemarkType>> placemarks = find(features, "Placemark", PlacemarkType.class);
result.addAll(extractWayPointsAndTracksFromPlacemarks(name, description, placemarks, startDate));
extractWayPointsAndTracksFromPlacemarks(name, description, placemarks, startDate, context);

List<JAXBElement<NetworkLinkType>> networkLinks = find(features, "NetworkLink", NetworkLinkType.class);
result.addAll(extractWayPointsAndTracksFromNetworkLinks(networkLinks));
extractWayPointsAndTracksFromNetworkLinks(networkLinks, context);

List<JAXBElement<FolderType>> folders = find(features, "Folder", FolderType.class);
for (JAXBElement<FolderType> folder : folders) {
FolderType folderTypeValue = folder.getValue();
String folderName = trim(folderTypeValue.getName());
// ignore speed and marks folders
if (folderName == null || (!folderName.equals(SPEED) && !folderName.equals(MARKS)))
result.addAll(extractTracks(concatPath(name, folderName), description, folderTypeValue.getAbstractFeatureGroup(), startDate));
extractTracks(concatPath(name, folderName), description, folderTypeValue.getAbstractFeatureGroup(), startDate, context);
}

List<JAXBElement<DocumentType>> documents = find(features, "Document", DocumentType.class);
for (JAXBElement<DocumentType> document : documents) {
DocumentType documentTypeValue = document.getValue();
String documentName = concatPath(name, documentTypeValue.getName());
result.addAll(extractTracks(documentName, description, documentTypeValue.getAbstractFeatureGroup(), startDate));
extractTracks(documentName, description, documentTypeValue.getAbstractFeatureGroup(), startDate, context);
}
return result;
}

private Calendar extractTime(JAXBElement<? extends AbstractTimePrimitiveType> timePrimitiveType) {
@@ -204,10 +191,8 @@ private Calendar extractTime(JAXBElement<? extends AbstractTimePrimitiveType> ti
return null;
}

private List<KmlRoute> extractWayPointsAndTracksFromPlacemarks(String name, String description, List<JAXBElement<PlacemarkType>> placemarkTypes, CompactCalendar startDate) {
List<KmlRoute> result = new ArrayList<KmlRoute>();

List<KmlPosition> wayPoints = new ArrayList<KmlPosition>();
private void extractWayPointsAndTracksFromPlacemarks(String name, String description, List<JAXBElement<PlacemarkType>> placemarkTypes, CompactCalendar startDate, ParserContext<KmlRoute> context) {
List<KmlPosition> waypoints = new ArrayList<KmlPosition>();
for (JAXBElement<PlacemarkType> placemarkType : placemarkTypes) {
PlacemarkType placemarkTypeValue = placemarkType.getValue();
String placemarkName = asComment(trim(placemarkTypeValue.getName()), trim(placemarkTypeValue.getDescription()));
@@ -221,31 +206,27 @@ private List<KmlRoute> extractWayPointsAndTracksFromPlacemarks(String name, Stri
// all placemarks with one position form one waypoint route
KmlPosition wayPoint = positions.get(0);
enrichPosition(wayPoint, extractTime(placemarkTypeValue.getAbstractTimePrimitiveGroup()), placemarkName, placemarkTypeValue.getDescription(), startDate);
wayPoints.add(wayPoint);
waypoints.add(wayPoint);
} else {
// each placemark with more than one position is one track
String routeName = concatPath(name, asName(placemarkName));
List<String> routeDescription = asDescription(placemarkTypeValue.getDescription() != null ? placemarkTypeValue.getDescription() : description);
RouteCharacteristics characteristics = parseCharacteristics(routeName, Track);
result.add(new KmlRoute(this, characteristics, routeName, routeDescription, positions));
context.appendRoute(new KmlRoute(this, characteristics, routeName, routeDescription, positions));
}
}
if (wayPoints.size() > 0) {
if (waypoints.size() > 0) {
RouteCharacteristics characteristics = parseCharacteristics(name, Waypoints);
result.add(0, new KmlRoute(this, characteristics, name, asDescription(description), wayPoints));
context.prependRoute(new KmlRoute(this, characteristics, name, asDescription(description), waypoints));
}
return result;
}

private List<KmlRoute> extractWayPointsAndTracksFromNetworkLinks(List<JAXBElement<NetworkLinkType>> networkLinkTypes) {
List<KmlRoute> result = new ArrayList<KmlRoute>();
private void extractWayPointsAndTracksFromNetworkLinks(List<JAXBElement<NetworkLinkType>> networkLinkTypes, ParserContext<KmlRoute> context) throws IOException {
for (JAXBElement<NetworkLinkType> networkLinkType : networkLinkTypes) {
Link link = networkLinkType.getValue().getLink();
if (link != null) {
String url = link.getHref();
List<KmlRoute> routes = parseRouteFromUrl(url);
if (routes != null)
result.addAll(routes);
context.parse(url);
}

List<JAXBElement<?>> rest = networkLinkType.getValue().getRest();
@@ -254,13 +235,10 @@ private List<KmlRoute> extractWayPointsAndTracksFromNetworkLinks(List<JAXBElemen
if (rValue instanceof LinkType) {
LinkType linkType = (LinkType) rValue;
String url = linkType.getHref();
List<KmlRoute> routes = parseRouteFromUrl(url);
if (routes != null)
result.addAll(routes);
context.parse(url);
}
}
}
return result;
}

private List<KmlPosition> asExtendedKmlPositions(List<String> strings) {
@@ -721,15 +699,15 @@ private KmlType createKmlType(List<KmlRoute> routes) {

public void write(KmlRoute route, OutputStream target, int startIndex, int endIndex) {
try {
KmlUtil.marshal22(createKmlType(route), target);
marshal22(createKmlType(route), target);
} catch (JAXBException e) {
throw new IllegalArgumentException(e);
}
}

public void write(List<KmlRoute> routes, OutputStream target) throws IOException {
try {
KmlUtil.marshal22(createKmlType(routes), target);
marshal22(createKmlType(routes), target);
} catch (JAXBException e) {
throw new IllegalArgumentException(e);
}
@@ -22,25 +22,16 @@

import slash.common.io.CompactCalendar;
import slash.navigation.base.BaseNavigationPosition;
import slash.navigation.base.BaseRoute;
import slash.navigation.base.NavigationFormatParser;
import slash.navigation.base.ParserContext;
import slash.navigation.base.ParserResult;
import slash.navigation.base.RouteCharacteristics;
import slash.navigation.googlemaps.GoogleMapsPosition;

import javax.xml.bind.JAXBException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -53,7 +44,6 @@
import static slash.common.io.Transfer.formatPositionAsString;
import static slash.common.io.Transfer.parseDouble;
import static slash.common.io.Transfer.trim;
import static slash.navigation.base.NavigationFormats.getReadFormats;
import static slash.navigation.base.RouteCharacteristics.Route;
import static slash.navigation.base.RouteCharacteristics.Track;
import static slash.navigation.base.RouteCharacteristics.Waypoints;
@@ -66,7 +56,6 @@
*/

public abstract class KmlFormat extends BaseKmlFormat {
private static final Logger log = Logger.getLogger(KmlFormat.class.getName());
static final Preferences preferences = Preferences.userNodeForPackage(KmlFormat.class);

static final String WAYPOINTS = "Waypoints";
@@ -98,8 +87,6 @@ public <P extends BaseNavigationPosition> KmlRoute createRoute(RouteCharacterist
return new KmlRoute(this, characteristics, name, null, (List<KmlPosition>) positions);
}

abstract void process(InputStream source, CompactCalendar startDate, ParserContext<KmlRoute> context) throws IOException, JAXBException;

protected KmlPosition asKmlPosition(GoogleMapsPosition position) {
return new KmlPosition(position.getLongitude(), position.getLatitude(), position.getElevation(), null, null, position.getComment());
}
@@ -310,28 +297,6 @@ protected String concatPath(String path, String fragment) {
return result;
}

protected List<KmlRoute> parseRouteFromUrl(String url) {
return parseRouteFromUrl(url, KmlRoute.class);
}

protected <T> List<T> parseRouteFromUrl(String url, Class<T> resultClass) {
List<T> routes = new ArrayList<T>();
try {
NavigationFormatParser parser = new NavigationFormatParser();
ParserResult result = parser.read(new URL(url), getReadFormats());
if (result != null) {
for (BaseRoute route : result.getAllRoutes()) {
if (resultClass.isInstance(route))
routes.add(resultClass.cast(route));
}
}
} catch (Exception e) {
e.printStackTrace();
log.fine("Error reading url " + url + ": " + e.getMessage());
}
return routes;
}

protected float getLineWidth() {
return preferences.getFloat("lineWidth", 3.0f);
}
@@ -112,8 +112,8 @@

public class KmlRoute extends BaseRoute<KmlPosition, BaseKmlFormat> {
private String name;
private final List<String> description;
private final List<KmlPosition> positions;
private List<String> description;
private List<KmlPosition> positions;

public KmlRoute(BaseKmlFormat format, RouteCharacteristics characteristics,
String name, List<String> description, List<KmlPosition> positions) {
@@ -73,7 +73,7 @@ public void read(InputStream source, CompactCalendar startDate, ParserContext<Km
ZipInputStream zip = new ZipInputStream(source);
try {
while ((zip.getNextEntry()) != null) {
delegate.process(new NotClosingUnderlyingInputStream(zip), startDate, context);
delegate.read(new NotClosingUnderlyingInputStream(zip), startDate, context);
zip.closeEntry();
}
} finally {
@@ -146,7 +146,7 @@ private Lmx createLmx(GpxRoute route, int startIndex, int endIndex) {

public void read(InputStream source, CompactCalendar startDate, ParserContext<GpxRoute> context) throws Exception {
Lmx lmx = unmarshal(source);
context.addRoute(process(lmx));
context.appendRoute(process(lmx));
}

public void write(GpxRoute route, OutputStream target, int startIndex, int endIndex) throws IOException {
@@ -190,7 +190,7 @@ private List<MagicMapsIktRoute> process(XMLEventReader eventReader) throws XMLSt
public void read(InputStream source, CompactCalendar startDate, ParserContext<MagicMapsIktRoute> context) throws Exception {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader eventReader = factory.createXMLEventReader(source, UTF8_ENCODING);
context.addRoutes(process(eventReader));
context.appendRoutes(process(eventReader));
}

private void writeHeader(String name, String description, XMLEventWriter writer, XMLEventFactory eventFactory) throws XMLStreamException {
@@ -88,7 +88,7 @@ public void read(BufferedReader reader, CompactCalendar startDate, String encodi
}

if (positions.size() > 0)
context.addRoute(createRoute(Track, null, positions));
context.appendRoute(createRoute(Track, null, positions));
}

boolean isNameValue(String line) {
@@ -142,7 +142,7 @@ public void read(BufferedReader reader, CompactCalendar startDate, String encodi
}

if (positions.size() > 0)
context.addRoute(createRoute(getCharacteristics(), null, positions));
context.appendRoute(createRoute(getCharacteristics(), null, positions));
}

boolean haveDifferentLongitudeAndLatitude(NmeaPosition predecessor, NmeaPosition successor) {
@@ -79,7 +79,7 @@ private NmnRoute process(Route route) {

public void read(InputStream source, CompactCalendar startDate, ParserContext<NmnRoute> context) throws Exception {
Route route = unmarshal(source);
context.addRoute(process(route));
context.appendRoute(process(route));
}


@@ -227,7 +227,7 @@ public void read(InputStream source, CompactCalendar startDate, ParserContext<Wg
}

if (readedPositions == expectedPositionCount)
context.addRoute(createRoute(Route, null, positions));
context.appendRoute(createRoute(Route, null, positions));
}
}

@@ -118,7 +118,7 @@ public void read(BufferedReader reader, CompactCalendar startDate, String encodi
}

if (hasValidSections(sections))
context.addRoutes(extractRoutes(sections));
context.appendRoutes(extractRoutes(sections));
}

boolean isSectionTitle(String line) {
@@ -150,7 +150,7 @@ public void read(InputStream source, CompactCalendar startDate, ParserContext<Wg
if (position != null && activeRoute != null)
activeRoute.getPositions().add(position);
else {
context.addRoutes(result);
context.appendRoutes(result);
return;
}

@@ -163,6 +163,6 @@ public void read(InputStream source, CompactCalendar startDate, ParserContext<Wg
int minCorrectPositions = (int) (readBytes / (double) SBP_RECORD_LENGTH * 0.95);
if (pointCount < minCorrectPositions)
return;
context.addRoutes(result);
context.appendRoutes(result);
}
}
@@ -226,7 +226,7 @@ public void read(InputStream source, CompactCalendar startDate, ParserContext<Wg
activeRoute = createRoute(Track,
TRACK_NAME_DATE_FORMAT.format(position.getTime().getTime()),
new ArrayList<BaseNavigationPosition>());
context.addRoute(activeRoute);
context.appendRoute(activeRoute);
}

activeRoute.getPositions().add(position);
@@ -242,7 +242,7 @@ private List<GpxRoute> process(TrainingCenterDatabaseT trainingCenterDatabaseT)

public void read(InputStream source, CompactCalendar startDate, ParserContext<GpxRoute> context) throws Exception {
TrainingCenterDatabaseT trainingCenterDatabase = TcxUtil.unmarshal1(source);
context.addRoutes(process(trainingCenterDatabase));
context.appendRoutes(process(trainingCenterDatabase));
}


@@ -191,7 +191,7 @@ private List<GpxRoute> process(TrainingCenterDatabaseT trainingCenterDatabaseT)

public void read(InputStream source, CompactCalendar startDate, ParserContext<GpxRoute> context) throws Exception {
TrainingCenterDatabaseT trainingCenterDatabase = TcxUtil.unmarshal2(source);
context.addRoutes(process(trainingCenterDatabase));
context.appendRoutes(process(trainingCenterDatabase));
}


@@ -142,7 +142,7 @@ public void read(BufferedReader reader, CompactCalendar startDate, String encodi
}

if (positions.size() > 0)
context.addRoute(createRoute(Waypoints, routeName, sortPositions(positions)));
context.appendRoute(createRoute(Waypoints, routeName, sortPositions(positions)));
}

private List<TourPosition> sortPositions(List<TourPosition> positions) {
@@ -150,83 +150,82 @@ public static String formatNumberedPosition(NumberPattern numberPattern, String

@SuppressWarnings("unchecked")
public static void commentRoutePositions(List<? extends BaseRoute> routes) {
if(routes.size() < 2)
return;

Map<LongitudeAndLatitude, String> comments = new HashMap<LongitudeAndLatitude, String>();
Map<LongitudeAndLatitude, Double> elevations = new HashMap<LongitudeAndLatitude, Double>();
Map<LongitudeAndLatitude, CompactCalendar> times = new HashMap<LongitudeAndLatitude, CompactCalendar>();
Map<LongitudeAndLatitude, Double> speeds = new HashMap<LongitudeAndLatitude, Double>();

for (BaseRoute<BaseNavigationPosition, BaseNavigationFormat> route : routes) {
for (BaseNavigationPosition position : route.getPositions()) {
if (!position.hasCoordinates())
continue;

if (position.getComment() != null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
if (comments.get(lal) == null) {
comments.put(lal, position.getComment());
if (routes.size() > 1) {
Map<LongitudeAndLatitude, String> comments = new HashMap<LongitudeAndLatitude, String>();
Map<LongitudeAndLatitude, Double> elevations = new HashMap<LongitudeAndLatitude, Double>();
Map<LongitudeAndLatitude, CompactCalendar> times = new HashMap<LongitudeAndLatitude, CompactCalendar>();
Map<LongitudeAndLatitude, Double> speeds = new HashMap<LongitudeAndLatitude, Double>();

for (BaseRoute<BaseNavigationPosition, BaseNavigationFormat> route : routes) {
for (BaseNavigationPosition position : route.getPositions()) {
if (!position.hasCoordinates())
continue;

if (position.getComment() != null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
if (comments.get(lal) == null) {
comments.put(lal, position.getComment());
}
}
}

if (position.getElevation() != null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
if (elevations.get(lal) == null) {
elevations.put(lal, position.getElevation());
if (position.getElevation() != null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
if (elevations.get(lal) == null) {
elevations.put(lal, position.getElevation());
}
}
}

if (position.getSpeed() != null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
if (speeds.get(lal) == null) {
speeds.put(lal, position.getSpeed());
if (position.getSpeed() != null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
if (speeds.get(lal) == null) {
speeds.put(lal, position.getSpeed());
}
}
}

if (position.getTime() != null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
if (times.get(lal) == null) {
times.put(lal, position.getTime());
if (position.getTime() != null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
if (times.get(lal) == null) {
times.put(lal, position.getTime());
}
}
}
}
}

for (BaseRoute<BaseNavigationPosition, BaseNavigationFormat> route : routes) {
for (BaseNavigationPosition position : route.getPositions()) {
if (!position.hasCoordinates())
continue;

if (position.getComment() == null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
String comment = comments.get(lal);
if (comment != null) {
position.setComment(comment);
for (BaseRoute<BaseNavigationPosition, BaseNavigationFormat> route : routes) {
for (BaseNavigationPosition position : route.getPositions()) {
if (!position.hasCoordinates())
continue;

if (position.getComment() == null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
String comment = comments.get(lal);
if (comment != null) {
position.setComment(comment);
}
}
}

if (position.getElevation() == null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
Double elevation = elevations.get(lal);
if (elevation != null) {
position.setElevation(elevation);
if (position.getElevation() == null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
Double elevation = elevations.get(lal);
if (elevation != null) {
position.setElevation(elevation);
}
}
}

if (position.getSpeed() == null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
Double speed = speeds.get(lal);
if (speed != null) {
position.setSpeed(speed);
if (position.getSpeed() == null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
Double speed = speeds.get(lal);
if (speed != null) {
position.setSpeed(speed);
}
}
}

if (position.getTime() == null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
CompactCalendar time = times.get(lal);
if (time != null) {
position.setTime(time);
if (position.getTime() == null) {
LongitudeAndLatitude lal = new LongitudeAndLatitude(position);
CompactCalendar time = times.get(lal);
if (time != null) {
position.setTime(time);
}
}
}
}
@@ -119,7 +119,7 @@ public void read(InputStream source, CompactCalendar startDate, ParserContext<Vi
InputStreamReader reader = new InputStreamReader(source);
try {
PoiList poiList = unmarshal(reader);
context.addRoute(process(poiList));
context.appendRoute(process(poiList));
}
finally {
reader.close();
@@ -118,7 +118,7 @@ public void read(InputStream source, CompactCalendar startDate, ParserContext<Wg
sourceData.put(header);
sourceData.put(data);

context.addRoutes(internalRead(sourceData));
context.appendRoutes(internalRead(sourceData));
}
}
}
@@ -32,6 +32,7 @@
import java.util.Collections;
import java.util.List;

import static java.io.File.createTempFile;
import static slash.common.io.Files.getExtension;
import static slash.navigation.base.NavigationFormats.asFormat;
import static slash.navigation.base.NavigationFormats.getReadFormatsPreferredByExtension;
@@ -82,7 +83,7 @@ private BaseNavigationFormat handleWriteOnlyFormats(BaseNavigationFormat targetF

@SuppressWarnings("unchecked")
private void convertSingleRouteRoundtrip(BaseNavigationFormat sourceFormat, BaseNavigationFormat targetFormat, File source, BaseRoute sourceRoute) throws IOException {
File target = File.createTempFile("singletarget", targetFormat.getExtension());
File target = createTempFile("singletarget", targetFormat.getExtension());
target.deleteOnExit();
try {
parser.write(sourceRoute, targetFormat, false, false, target);
@@ -118,7 +119,7 @@ private void convertSingleRouteRoundtrip(BaseNavigationFormat sourceFormat, Base

@SuppressWarnings("unchecked")
private void convertMultipleRouteRoundtrip(BaseNavigationFormat sourceFormat, BaseNavigationFormat targetFormat, File source, List<BaseRoute> sourceRoutes) throws IOException {
File target = File.createTempFile("multitarget", targetFormat.getExtension());
File target = createTempFile("multitarget", targetFormat.getExtension());
target.deleteOnExit();
try {
parser.write(sourceRoutes, (MultipleRoutesFormat) targetFormat, target);
@@ -176,7 +177,7 @@ void convertSplitRoundtrip(String testFileName, BaseNavigationFormat sourceForma

File[] targets = new File[fileCount];
for (int i = 0; i < targets.length; i++)
targets[i] = File.createTempFile("splittarget", targetFormat.getExtension());
targets[i] = createTempFile("splittarget", targetFormat.getExtension());
try {
parser.write(sourceRoute, targetFormat, false, false, targets);

@@ -53,6 +53,7 @@
import slash.navigation.itn.TomTomRoute;
import slash.navigation.itn.TomTomRouteFormat;
import slash.navigation.jaxb.JaxbUtils;
import slash.navigation.kml.BaseKmlFormat;
import slash.navigation.kml.KmlFormat;
import slash.navigation.kml.KmlRoute;
import slash.navigation.kml.KmzFormat;
@@ -102,6 +103,7 @@

import static java.io.File.separator;
import static java.lang.Math.min;
import static java.util.Arrays.asList;
import static slash.common.io.CompactCalendar.UTC;
import static slash.common.io.Files.collectFiles;
import static slash.common.io.Transfer.isEmpty;
@@ -982,25 +984,23 @@ public static void readFiles(String prefix, String extension, int routeCount, bo
}
}

public static List<GpxRoute> readSampleGpxFile(GpxFormat format, String fileName) throws Exception {
File source = new File(SAMPLE_PATH + fileName);
public static List<GpxRoute> readGpxFile(GpxFormat format, String fileName) throws Exception {
File source = new File(fileName);
ParserContext<GpxRoute> context = new ParserContextImpl<GpxRoute>();
format.read(new FileInputStream(source), null, context);
return context.getRoutes();
}

public static List<KmlRoute> readSampleKmlFile(KmlFormat format, String fileName) throws Exception {
File source = new File(SAMPLE_PATH + fileName);
ParserContext<KmlRoute> context = new ParserContextImpl<KmlRoute>();
format.read(new FileInputStream(source), null, context);
return context.getRoutes();
}

public static List<KmlRoute> readSampleKmzFile(KmzFormat format, String fileName) throws Exception {
File source = new File(SAMPLE_PATH + fileName);
ParserContext<KmlRoute> context = new ParserContextImpl<KmlRoute>();
format.read(new FileInputStream(source), null, context);
return context.getRoutes();
public static List<KmlRoute> readKmlFile(BaseKmlFormat format, String fileName) throws Exception {
File source = new File(fileName);
NavigationFormatParser parser = new NavigationFormatParser();
ParserResult result = parser.read(source, asList((NavigationFormat) format));
List<KmlRoute> routes = new ArrayList<KmlRoute>();
for (BaseRoute route : result.getAllRoutes()) {
if (route instanceof KmlRoute)
routes.add((KmlRoute) route);
}
return routes;
}

public static List<TomTomRoute> readSampleTomTomRouteFile(String fileName, boolean setStartDateFromFile) throws Exception {
@@ -84,7 +84,7 @@ public void test(File file) throws IOException {
!file.getName().endsWith(".mps") && !file.getName().endsWith(".rte") &&
!file.getName().endsWith(".tef") && !file.getName().endsWith(".wpt"))
assertNotNull("Route has no name", result.getTheRoute().getName());
// a GoPal 3 track without positions which is not rejected because the following Nmn4Format would try to readSampleGpxFile if forever
// a GoPal 3 track without positions which is not rejected because the following Nmn4Format would try to readGpxFile if forever
// a OziExplorer Route has a first route without a single position
if (!file.getName().equals("dieter3-GoPal3Track.trk") && !file.getName().equals("ozi-condecourt.rte"))
assertTrue("Route " + file + " has no positions", result.getTheRoute().getPositionCount() > 0);
@@ -38,8 +38,9 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static slash.navigation.base.NavigationTestCase.SAMPLE_PATH;
import static slash.navigation.base.NavigationTestCase.TEST_PATH;
import static slash.navigation.base.NavigationTestCase.readSampleGpxFile;
import static slash.navigation.base.NavigationTestCase.readGpxFile;

public class GpxFormatIT {

@@ -113,7 +114,7 @@ public void testUnmarshal11TypeError() throws IOException {

@Test
public void testAkGpxReadWriteRoundtrip() throws Exception {
List<GpxRoute> routes = readSampleGpxFile(new Gpx10Format(), "ak.gpx");
List<GpxRoute> routes = readGpxFile(new Gpx10Format(), SAMPLE_PATH + "ak.gpx");
assertNotNull(routes);
assertEquals(1, routes.size());
GpxRoute route = routes.get(0);
@@ -122,7 +123,7 @@ public void testAkGpxReadWriteRoundtrip() throws Exception {

@Test
public void testGarminExtensions() throws Exception {
List<GpxRoute> routes = readSampleGpxFile(new Gpx11Format(), "MS.gpx");
List<GpxRoute> routes = readGpxFile(new Gpx11Format(), SAMPLE_PATH + "MS.gpx");
assertNotNull(routes);
assertEquals(2, routes.size());
GpxRoute route = routes.get(0);
@@ -39,7 +39,7 @@
import static slash.navigation.base.NavigationTestCase.SAMPLE_PATH;
import static slash.navigation.base.NavigationTestCase.readFile;
import static slash.navigation.base.NavigationTestCase.readFiles;
import static slash.navigation.base.NavigationTestCase.readSampleGpxFile;
import static slash.navigation.base.NavigationTestCase.readGpxFile;
import static slash.navigation.base.NavigationTestCase.readSampleTomTomRouteFile;
import static slash.navigation.base.RouteCharacteristics.Route;
import static slash.navigation.base.RouteCharacteristics.Track;
@@ -67,7 +67,7 @@ public void testAllTripmasterKmlTracks() throws IOException {

@Test
public void testTripmaster1dot4GpxTrack() throws Exception {
List<GpxRoute> routes = readSampleGpxFile(new Gpx10Format(), "tripmaster1.gpx");
List<GpxRoute> routes = readGpxFile(new Gpx10Format(), SAMPLE_PATH + "tripmaster1.gpx");
assertNotNull(routes);
assertEquals(1, routes.size());
GpxRoute route = routes.get(0);
@@ -108,7 +108,7 @@ public void testTripmaster1dot4GpxTrack() throws Exception {

@Test
public void testTripmasterGpxTrack() throws Exception {
List<GpxRoute> routes = readSampleGpxFile(new Gpx10Format(), "tripmaster2.gpx");
List<GpxRoute> routes = readGpxFile(new Gpx10Format(), SAMPLE_PATH + "tripmaster2.gpx");
assertNotNull(routes);
assertEquals(1, routes.size());
GpxRoute route = routes.get(0);
@@ -32,7 +32,7 @@
import static slash.common.TestCase.assertDoubleEquals;

public class Kml21FormatTest {
Kml21Format format = new Kml21Format();
private Kml21Format format = new Kml21Format();

@Test
public void testPointCoordinates() throws Exception {
@@ -21,12 +21,9 @@
package slash.navigation.kml;

import org.junit.Test;
import slash.navigation.base.ParserContext;
import slash.navigation.base.ParserContextImpl;
import slash.navigation.kml.binding20.Kml;

import javax.xml.bind.JAXBException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
@@ -38,17 +35,21 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static slash.common.TestCase.assertEquals;
import static slash.navigation.base.NavigationTestCase.SAMPLE_PATH;
import static slash.navigation.base.NavigationTestCase.TEST_PATH;
import static slash.navigation.base.NavigationTestCase.readSampleKmlFile;
import static slash.navigation.base.NavigationTestCase.readSampleKmzFile;
import static slash.navigation.base.NavigationTestCase.readKmlFile;
import static slash.navigation.base.RouteCharacteristics.Track;
import static slash.navigation.kml.KmlUtil.newUnmarshaller20;
import static slash.navigation.kml.KmlUtil.unmarshal20;
import static slash.navigation.kml.KmlUtil.unmarshal21;
import static slash.navigation.kml.KmlUtil.unmarshal22;
import static slash.navigation.kml.KmlUtil.unmarshal22Beta;

public class KmlFormatIT {

@Test
public void testReader() throws FileNotFoundException, JAXBException {
Reader reader = new FileReader(TEST_PATH + "from20.kml");
Kml kml = (Kml) KmlUtil.newUnmarshaller20().unmarshal(reader);
Kml kml = (Kml) newUnmarshaller20().unmarshal(reader);
assertNotNull(kml);
assertNotNull(kml.getFolder());
assertEquals(3, kml.getFolder().getDocumentOrFolderOrGroundOverlay().size());
@@ -57,7 +58,7 @@ public void testReader() throws FileNotFoundException, JAXBException {
@Test
public void testInputStream() throws FileNotFoundException, JAXBException {
InputStream in = new FileInputStream(TEST_PATH + "from20.kml");
Kml kml = (Kml) KmlUtil.newUnmarshaller20().unmarshal(in);
Kml kml = (Kml) newUnmarshaller20().unmarshal(in);
assertNotNull(kml);
assertNotNull(kml.getFolder());
assertEquals(3, kml.getFolder().getDocumentOrFolderOrGroundOverlay().size());
@@ -66,7 +67,7 @@ public void testInputStream() throws FileNotFoundException, JAXBException {
@Test
public void testUnmarshal20() throws IOException, JAXBException {
Reader reader = new FileReader(TEST_PATH + "from20.kml");
Kml kml = KmlUtil.unmarshal20(reader);
Kml kml = unmarshal20(reader);
assertNotNull(kml);
assertNotNull(kml.getFolder());
assertEquals(3, kml.getFolder().getDocumentOrFolderOrGroundOverlay().size());
@@ -76,7 +77,7 @@ public void testUnmarshal20() throws IOException, JAXBException {
public void testUnmarshal20TypeError() throws IOException {
Reader reader = new FileReader(TEST_PATH + "from20.kml");
try {
KmlUtil.unmarshal21(reader);
unmarshal21(reader);
assertTrue(false);
} catch (JAXBException e) {
}
@@ -85,15 +86,15 @@ public void testUnmarshal20TypeError() throws IOException {
@Test
public void testUnmarshal21() throws IOException, JAXBException {
Reader reader = new FileReader(TEST_PATH + "from21.kml");
slash.navigation.kml.binding21.KmlType kml = KmlUtil.unmarshal21(reader);
slash.navigation.kml.binding21.KmlType kml = unmarshal21(reader);
assertNotNull(kml);
}

@Test
public void testUnmarshal21TypeError() throws IOException {
Reader reader = new FileReader(TEST_PATH + "from21.kml");
try {
KmlUtil.unmarshal20(reader);
unmarshal20(reader);
assertTrue(false);
} catch (JAXBException e) {
}
@@ -102,47 +103,61 @@ public void testUnmarshal21TypeError() throws IOException {
@Test
public void testUnmarshal22Beta() throws IOException, JAXBException {
Reader reader = new FileReader(TEST_PATH + "from22beta.kml");
slash.navigation.kml.binding22beta.KmlType kml = KmlUtil.unmarshal22Beta(reader);
slash.navigation.kml.binding22beta.KmlType kml = unmarshal22Beta(reader);
assertNotNull(kml);
}

@Test
public void testUnmarshal22() throws IOException, JAXBException {
Reader reader = new FileReader(TEST_PATH + "from22.kml");
slash.navigation.kml.binding22.KmlType kml = KmlUtil.unmarshal22(reader);
slash.navigation.kml.binding22.KmlType kml = unmarshal22(reader);
assertNotNull(kml);
}

private void assertRoutesEquals(List<KmlRoute> firstRoutes, List<KmlRoute> secondRoutes) {
for (int i = 0; i < firstRoutes.size(); i++) {
KmlRoute first = firstRoutes.get(i);
KmlRoute second = secondRoutes.get(i);
assertEquals(first.getCharacteristics(), second.getCharacteristics());
assertEquals(first.getDescription(), second.getDescription());
assertEquals(first.getName(), second.getName());
}
for (int i = 0; i < firstRoutes.size(); i++) {
KmlRoute first = firstRoutes.get(i);
KmlRoute second = secondRoutes.get(i);
assertPositionsEquals(first.getPositions(), second.getPositions());
}
assertEquals(firstRoutes, secondRoutes);
}

private void assertPositionsEquals(List<KmlPosition> firstPositions, List<KmlPosition> secondPositions) {
for (int i = 0; i < firstPositions.size(); i++) {
KmlPosition first = firstPositions.get(i);
KmlPosition second = secondPositions.get(i);
assertEquals(first.getComment(), second.getComment());
assertEquals(first.getElevation(), second.getElevation());
assertEquals(first.getLatitude(), second.getLatitude());
assertEquals(first.getLongitude(), second.getLongitude());
}
}

@Test
public void testKmlVsKmz20() throws Exception {
List<KmlRoute> kmlRoute = readSampleKmlFile(new Kml20Format(), "magnalox ID13885_Hiroshima Race Course.kml");
List<KmlRoute> kmzRoute = readSampleKmzFile(new Kmz20Format(), "magnalox ID13885_Hiroshima Race Course.kmz");
assertEquals(kmlRoute, kmzRoute);
List<KmlRoute> kmlRoute = readKmlFile(new Kml20Format(), SAMPLE_PATH + "magnalox ID13885_Hiroshima Race Course.kml");
List<KmlRoute> kmzRoute = readKmlFile(new Kmz20Format(), SAMPLE_PATH + "magnalox ID13885_Hiroshima Race Course.kmz");
assertRoutesEquals(kmlRoute, kmzRoute);
}

@Test
public void testKmlVsKmz21() throws Exception {
List<KmlRoute> kmlRoute = readSampleKmlFile(new Kml21Format(), "magnalox ID13885_Hiroshima Race Course by Google Earth.kml");
List<KmlRoute> kmzRoute = readSampleKmzFile(new Kmz21Format(), "magnalox ID13885_Hiroshima Race Course by Google Earth.kmz");
List<KmlRoute> kmlRoute = readKmlFile(new Kml21Format(), SAMPLE_PATH + "magnalox ID13885_Hiroshima Race Course by Google Earth.kml");
List<KmlRoute> kmzRoute = readKmlFile(new Kmz21Format(), SAMPLE_PATH + "magnalox ID13885_Hiroshima Race Course by Google Earth.kmz");
assertEquals(kmlRoute, kmzRoute);
}

@Test
public void testNetworkLink20() throws Exception {
List<KmlRoute> routes = readSampleKmlFile(new Kml20Format(), "www.gps-tour.info20.kml");
assertNotNull(routes);
assertEquals(6, routes.size());
for (KmlRoute route : routes) {
assertTrue(route.getPositionCount() > 0);
}
assertEquals(18724, routes.get(1).getPositionCount());
assertEquals(2658, routes.get(4).getPositionCount());
}

@Test
public void testItnConvKml() throws Exception {
List<KmlRoute> routes = readSampleKmlFile(new BrokenKml21Format(), "bcr_with_itnconv.kml");
List<KmlRoute> routes = readKmlFile(new BrokenKml21Format(), SAMPLE_PATH + "bcr_with_itnconv.kml");
assertNotNull(routes);
assertEquals(2, routes.size());
for (KmlRoute route : routes) {
@@ -153,30 +168,29 @@ public void testItnConvKml() throws Exception {
}

@Test
public void testNetworkLink21() throws Exception {
List<KmlRoute> routes = readSampleKmlFile(new Kml21Format(), "www.gps-tour.info21.kml");
assertEquals(6, routes.size());
for (KmlRoute route : routes) {
assertTrue(route.getPositionCount() > 0);
}
assertEquals(18724, routes.get(1).getPositionCount());
assertEquals(2658, routes.get(4).getPositionCount());
public void testDirectVsNetworklink20() throws Exception {
List<KmlRoute> directRoute = readKmlFile(new Kml20Format(), TEST_PATH + "from20.kml");
List<KmlRoute> networkLinkRoute = readKmlFile(new Kml20Format(), TEST_PATH + "from20nwlink.kml");
assertRoutesEquals(directRoute, networkLinkRoute);
}

@Test
public void testNetworkLink22() throws Exception {
List<KmlRoute> routes = readSampleKmlFile(new Kml22Format(), "www.gps-tour.info22.kml");
assertEquals(6, routes.size());
for (KmlRoute route : routes) {
assertTrue(route.getPositionCount() > 0);
}
assertEquals(18724, routes.get(1).getPositionCount());
assertEquals(2658, routes.get(4).getPositionCount());
public void testDirectVsNetworklink21() throws Exception {
List<KmlRoute> directRoute = readKmlFile(new Kml21Format(), TEST_PATH + "from21.kml");
List<KmlRoute> networkLinkRoute = readKmlFile(new Kml21Format(), TEST_PATH + "from21nwlink.kml");
assertRoutesEquals(directRoute, networkLinkRoute);
}

@Test
public void testDirectVsNetworklink22() throws Exception {
List<KmlRoute> directRoute = readKmlFile(new Kml22Format(), TEST_PATH + "from22.kml");
List<KmlRoute> networkLinkRoute = readKmlFile(new Kml22Format(), TEST_PATH + "from22nwlink.kml");
assertRoutesEquals(directRoute, networkLinkRoute);
}

@Test
public void testOnlyPlacemark() throws Exception {
List<KmlRoute> routes = readSampleKmlFile(new Kml22BetaFormat(), "Home to Corfe Castle.kml");
List<KmlRoute> routes = readKmlFile(new Kml22BetaFormat(), SAMPLE_PATH + "Home to Corfe Castle.kml");
assertNotNull(routes);
assertEquals(1, routes.size());
KmlRoute route = routes.get(0);
@@ -185,7 +199,7 @@ public void testOnlyPlacemark() throws Exception {

@Test
public void testNoKmlRoot20() throws Exception {
List<KmlRoute> routes = readSampleKmlFile(new Kml20Format(), "MIK-Tour - Nuerburgring 7.10.2007.kml");
List<KmlRoute> routes = readKmlFile(new Kml20Format(), SAMPLE_PATH + "MIK-Tour - Nuerburgring 7.10.2007.kml");
assertNotNull(routes);
assertEquals(1, routes.size());
KmlRoute route = routes.get(0);
@@ -194,9 +208,7 @@ public void testNoKmlRoot20() throws Exception {

@Test
public void testTrackExtension22() throws Exception {
ParserContext<KmlRoute> context = new ParserContextImpl<KmlRoute>();
new Kml22Format().read(new FileInputStream(new File(TEST_PATH + "from22track.kml")), null, context);
List<KmlRoute> routes = context.getRoutes();
List<KmlRoute> routes = readKmlFile(new Kml22Format(), TEST_PATH + "from22track.kml");
assertNotNull(routes);
assertEquals(1, routes.size());
KmlRoute route = routes.get(0);
@@ -206,9 +218,7 @@ public void testTrackExtension22() throws Exception {

@Test
public void testFlytoExtension22() throws Exception {
ParserContext<KmlRoute> context = new ParserContextImpl<KmlRoute>();
new Kml22Format().read(new FileInputStream(new File(TEST_PATH + "from22flyto.kml")), null, context);
List<KmlRoute> routes = context.getRoutes();
List<KmlRoute> routes = readKmlFile(new Kml22Format(), TEST_PATH + "from22flyto.kml");
assertNotNull(routes);
assertEquals(1, routes.size());
KmlRoute route = routes.get(0);