zeja
Erfahrenes Mitglied
Ganz zufrieden bin ich nicht aber naja.... es läuft zumindest 

Java:
package de.tutorials.quiz10;
import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author zeja
*/
public class WorldTour {
/**
* Liste eine Datei mit den Koordinaten für die Weltreise ein.
*
* @param pointList
* @return
*/
public static List<WorldCoordinates> read(final File pointList) {
final List<WorldCoordinates> coordinateList = new ArrayList<WorldCoordinates>( );
try {
final BufferedReader br = new BufferedReader(new FileReader(
pointList));
try {
String line = null;
while ((line = br.readLine( )) != null) {
// Auskommentieren mit #
if (!line.trim( ).equals("") && !line.startsWith("#")) {
try {
final WorldCoordinates coordinates = parseLine(line);
coordinateList.add(coordinates);
}
catch (ParseException e) {
e.printStackTrace( );
}
}
}
}
finally {
br.close( );
}
}
catch (IOException e) {
e.printStackTrace( );
}
return coordinateList;
}
/**
* Breite Länge Ortsname<br>
* G°M'S"<br>
* G°M'<br>
* G°<br>
* z.B: 40°43'N 74°W New York
*
* @param line
* @throws ParseException
* Wenn Koordinatenpaar nicht geparst werden kann.
*/
private static WorldCoordinates parseLine(final String line)
throws ParseException {
// Splitten bei Mindestens einem Whitespace
final String[] parts = line.split("\\s+");
if (parts != null) {
if (parts.length > 2) {
// Breitengrad
final String latitudeString = parts[0].trim( );
// Längengrad
final String longitudeString = parts[1].trim( );
// Ortsname zusammenbauen
String cityName = parts[2];
for (int i = 3; i < parts.length; i++) {
cityName += " " + parts[i];
}
// Längengrad und Breitengrad parsen
final Coordinate latitude = CoordinateParser
.parseLatitude(latitudeString);
final Coordinate longitude = CoordinateParser
.parseLongitude(longitudeString);
return new WorldCoordinates(latitude, longitude, cityName
.trim( ));
}
else if (parts.length >= 1) {
// Ortsname zusammenbauen
String cityName = parts[0];
for (int i = 1; i < parts.length; i++) {
cityName += " " + parts[i];
}
// Nur die Stadt angegeben
return WorldCoordinates.getCoordinatesForCityName(cityName);
}
else {
throw new ParseException("Keine Koordinaten angegeben", -1);
}
}
else {
throw new ParseException("Koordinaten sind fehlerhaft.", -1);
}
}
/**
* Erstellt aus den Wegpunkten eine Liste in Dezimaler Darstellung
* zum einzeichnen in das SVG
*
* @param from
* @param to
* @param svg
*/
private static void waypoints2Polylist(final WorldCoordinates from,
final WorldCoordinates to, final SVGEmitter svg) {
List<Point2D.Double> polyList = new ArrayList<Point2D.Double>( );
// Wegpunkte im Abstand von 100km erstellen
final List<WorldCoordinates> calc = from.calculateWaypoints(to, 100);
double lastLongitude = 0;
for (WorldCoordinates coord : calc) {
double longitude = coord.getLongitude( ).asDecimalDegree( );
double latitude = -coord.getLatitude( ).asDecimalDegree( );
if (longitude < -180) {
longitude = 360 + longitude;
}
// Vorzeichenwechsel beachten die nicht im Bereich um 0
// stattfinden
// Liste wechseln, damit kein Strich quer über die Karte
// gezeichnet
// wird.
if (((longitude < -1 && lastLongitude > 1) || (lastLongitude < -1 && longitude > 1))
&& Math.signum(longitude) + Math.signum(lastLongitude) == 0) {
svg.addPolyList(polyList);
polyList = new ArrayList<Point2D.Double>( );
}
polyList.add(new Point2D.Double(longitude, latitude));
lastLongitude = longitude;
}
svg.addPolyList(polyList);
}
/**
* Berechnen die Fakultät für den angegebenen Wert.
*
* @param value
* n
* @return n!
*/
private static int fakultät(int value) {
if (value == 0 || value == 1) {
return value;
}
return value * fakultät(value - 1);
}
private static List<WorldCoordinates> getShortestRoute(
final WorldCoordinates src, final WorldCoordinates target,
final Set<List<WorldCoordinates>> permutationSet) {
List<WorldCoordinates> bestList = null;
double shortestDistance = -1;
for (List<WorldCoordinates> currentList : permutationSet) {
double distance = src.distanceTo(currentList.get(0));
for (int j = 0; j < currentList.size( ) - 1; j++) {
final WorldCoordinates first = currentList.get(j);
final WorldCoordinates second = currentList.get(j + 1);
distance += first.distanceTo(second);
}
distance += currentList.get(currentList.size( ) - 1).distanceTo(
target);
if (shortestDistance == -1 || distance < shortestDistance) {
shortestDistance = distance;
bestList = currentList;
}
}
return bestList;
}
private static Set<List<WorldCoordinates>> createPermutations(
final List<WorldCoordinates> list) {
final List<WorldCoordinates> permutationList = new ArrayList<WorldCoordinates>(
list.subList(2, list.size( )));
// Alle Permutationen erstellen
final Set<List<WorldCoordinates>> permutationSet = new HashSet<List<WorldCoordinates>>( );
int destSize = fakultät(permutationList.size( ));
// Eigentlich müßte hier ein ordentlicher Algorithmus rein ;)
while (permutationSet.size( ) < destSize) {
Collections.shuffle(permutationList);
permutationSet
.add(new ArrayList<WorldCoordinates>(permutationList));
}
return permutationSet;
}
public static void main(String[] args) throws IOException {
final File f = new File("city.list");
final List<WorldCoordinates> list = read(f);
if (list == null || list.size( ) < 2) {
System.out
.println("Es müssen mindestens 2 Koordinaten oder Städte angegeben werden.");
}
final WorldCoordinates src = list.get(0);
final WorldCoordinates target = list.get(1);
List<WorldCoordinates> bestList = list;
// Wenn mehr als zwei Koordinaten gegeben sind,
// dann kürzeste Route ermitteln, die von den Start- zu den
// Endkoordinaten über die übrigen Koordinaten führt.
if (list.size( ) > 2) {
// Permutationen der Liste (ohne Start und Ende)
// erstellen.
final Set<List<WorldCoordinates>> permutationSet = createPermutations(list);
// Kürzeste Route ermitteln
final List<WorldCoordinates> tempList = getShortestRoute(src,
target, permutationSet);
if (tempList != null) {
// Start und Endpunkt einfügen
tempList.add(0, src);
tempList.add(target);
bestList = tempList;
}
}
SVGEmitter svg = new SVGEmitter( );
// Route in das SVG Bild einzeichnen
for (int j = 0; j < bestList.size( ) - 1; j++) {
final WorldCoordinates first = bestList.get(j);
final WorldCoordinates second = bestList.get(j + 1);
// Start und Endpunkt einzeichnen
boolean isFirst = (j == 0);
boolean isLast = (j == (bestList.size( ) - 2));
if (isFirst) {
svg.addStart(first);
}
else {
svg.addCross(first);
}
if (isLast) {
svg.addEnd(second);
}
else {
svg.addCross(second);
}
// Beste Strecke zwischen den Punkte einzeichnen
waypoints2Polylist(first, second, svg);
}
svg.save(new File("city.svg"));
}
}
Java:
package de.tutorials.quiz10;
/**
* Himmelsrichtungen.
*
* @author zeja
*/
public enum Direction {
WEST {
@Override
public String toString() {
return "W";
}
},
EAST {
@Override
public String toString() {
return "E";
}
},
NORTH {
@Override
public String toString() {
return "N";
}
},
SOUTH {
@Override
public String toString() {
return "S";
}
};
}
Java:
package de.tutorials.quiz10;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
/**
* Koordinaten auf der Erde in Dezimaler und Sexagesimaler
* Repräsentation.
*
* @author zeja
*/
public class Coordinate {
/**
* Keine Angabe für eine Komponente in Sexagesimaler Darstellung
*/
public static final int NONE = 0;
/**
* Eine halbe Sekunde in Sexagesimaler Darstellung
*/
private static final double HALF_SECOND = 1. / 7200.;
/**
* 60 als BigDecimal
*/
private static final BigDecimal SIXTY = BigDecimal.valueOf(60.0);
/**
* Maximale Genauigkeit beim Runden
*/
private static final MathContext MC = new MathContext(34,
RoundingMode.HALF_UP);
/**
* Sexagesimal Grad °
*/
private final int degree;
/**
* Sexagesimal Minuten '
*/
private final int minutes;
/**
* Sexagesimal Sekunden "
*/
private final int seconds;
/**
* Sexagesimal Richtung
*/
private final Direction direction;
/**
* Dezimale Darstellung in Grad
*/
private final double decimalDegree;
/**
* Dezimale Darstellung in Radian
*/
private final double decimalRadian;
/**
* Erstellt eine Koordinate durch Angabe der Position in Dezimaler
* Darstellung.
*
* @param decimal
* Dezimale Darstellung der Koordinaten. Für
* Breitengrade steht eine Negative Zahl für die
* Richtung West und für einen Längengrad für Süd.
* @param latitude
* <code>true</code> Wenn es sich um die Koordinaten
* für einen Breitengrad handelt.
*/
public Coordinate(double decimal, boolean latitude) {
this.decimalDegree = decimal;
if (latitude) {
if (this.decimalDegree < 0) {
this.direction = Direction.WEST;
}
else {
this.direction = Direction.EAST;
}
}
else {
if (this.decimalDegree < 0) {
this.direction = Direction.SOUTH;
}
else {
this.direction = Direction.NORTH;
}
}
// Decimal in °'" umrechnen
double d = Math.abs(this.decimalDegree);
d += HALF_SECOND; // add a second for rounding
this.degree = (int) Math.floor(d);
this.minutes = (int) Math.floor((d - this.degree) * 60.0);
this.seconds = (int) Math
.floor((d - this.degree - this.minutes / 60.0) * 3600.0);
this.decimalRadian = Math.toRadians(this.decimalDegree);
}
/**
* Erstellt Koordinaten über die Sexagesimale Darstellung.
* @param degree
* Sexagesimal Grad
* @param minutes
* Sexagesimal Minuten
* @param seconds
* Sexagesimal Sekunden
* @param direction
* Richtung (Norden, Osten, Westen, Süden)
*/
public Coordinate(int degree, int minutes, int seconds, Direction direction) {
this.degree = degree;
this.minutes = minutes;
this.seconds = seconds;
this.direction = direction;
this.decimalDegree = sexagesimalToDecimalDegree( );
this.decimalRadian = Math.toRadians(this.decimalDegree);
}
/**
* Rechnet die Sexagesimale Darstellung in die Dezimale
* Darstellung um.
*
* @return
*/
private double sexagesimalToDecimalDegree() {
BigDecimal value = BigDecimal.valueOf(seconds).divide(SIXTY, MC).add(
BigDecimal.valueOf(minutes)).divide(SIXTY, MC).add(
BigDecimal.valueOf(degree));
if (direction == Direction.WEST || direction == Direction.SOUTH) {
value = value.negate( );
}
return value.doubleValue( );
}
/**
* Gibt die Koordinaten in Dezimal als Radian zurück.
*
* @return
*/
public double asDecimalRadian() {
return this.decimalRadian;
}
/**
* Gibt die Koordinaten in Dezimal als Grad zurück.
*
* @return
*/
public double asDecimalDegree() {
return decimalDegree;
}
@Override
public String toString() {
final StringBuilder b = new StringBuilder( );
b.append(degree).append("°");
b.append(minutes).append("'");
b.append(seconds).append("\"");
b.append(direction);
return b.toString( );
}
}
Java:
package de.tutorials.quiz10;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Parser für Koordinaten (Längengrad oder Breitengrad) aus einem
* String in Sexagesimaler Darstellung.
*
* @author zeja
*/
public final class CoordinateParser {
/**
* Pattern zum parsen von Sexagesimalen Grad: 145°
*/
private static final String DEGREE_REGEX = "([0-9]*)°";
/**
* Pattern zum parsen von Sexagesimalen Minuten: 65'
*/
private static final String MINUTES_REGEX = "(?:([0-9]*)')?";
/**
* Pattern zum parsen von Sexagesimalen Sekunden: 17"
*/
private static final String SECONDS_REGEX = "(?:([0-9]*)(?:''|\"))?";
/**
* Himmelsrichtung Längengrad
*/
private static final String LONGITUDE_DIRECTION_REGEX = "([OEW])";
/**
* Himmelsrichtung Breitengrad
*/
private static final String LATITUDE_DIRECTION_REGEX = "([NS])";
/**
* Pattern zum Parsen von Breitengraden.
*/
private static final Pattern LATITUDE_PATTERN = Pattern
.compile(DEGREE_REGEX + MINUTES_REGEX + SECONDS_REGEX
+ LATITUDE_DIRECTION_REGEX);
/**
* Pattern zum Parsen von Längengraden.
*/
private static final Pattern LONGITUDE_PATTERN = Pattern
.compile(DEGREE_REGEX + MINUTES_REGEX + SECONDS_REGEX
+ LONGITUDE_DIRECTION_REGEX);
private CoordinateParser() {
throw new AssertionError( );
}
/**
* Parst einen Breitengrad der Form<br>
* G°M'S""(OEW)<br>
* Die Formen<br>
* G°(OEW)<br>
* G°M'(OEW)<br>
* sind ebenfalls erlaubt.
*
* @param strg
* @return Die geparsten Koordinaten
* @throws ParseException
* Wenn eine Fehler beim Parsen aufgetreten ist.
*/
public static Coordinate parseLatitude(final String strg)
throws ParseException {
return parseCoordinates(strg, LATITUDE_PATTERN);
}
/**
* Parst einen Längengrad der Form<br>
* G°M'S"(NS)<br>
* Die Formen<br>
* G°(NS)<br>
* G°M'(NS)<br>
* sind ebenfalls erlaubt.
*
* @param strg
* @return Die geparsten Koordinaten
* @throws ParseException
* Wenn eine Fehler beim Parsen aufgetreten ist.
*/
public static Coordinate parseLongitude(final String strg)
throws ParseException {
return parseCoordinates(strg, LONGITUDE_PATTERN);
}
private static Coordinate parseCoordinates(final String strg,
final Pattern pattern) throws ParseException {
if (strg == null) {
throw new ParseException("Keine Koordinaten gegeben.", -1);
}
final Matcher matcher = pattern.matcher(strg);
if (matcher.matches( )) {
if (matcher.groupCount( ) == 4) {
// Grad
String tmp = matcher.group(1);
int degree = Integer.parseInt(tmp);
// Optional Minuten
tmp = matcher.group(2);
int minutes = Coordinate.NONE;
if (tmp != null) {
minutes = Integer.parseInt(tmp);
}
// Optinal Sekunden
tmp = matcher.group(3);
int seconds = Coordinate.NONE;
if (tmp != null) {
seconds = Integer.parseInt(tmp);
}
// Richtung
tmp = matcher.group(4);
final Direction direction;
if (tmp.equals("N")) {
direction = Direction.NORTH;
}
else if (tmp.equals("S")) {
direction = Direction.SOUTH;
}
else if (tmp.equals("E") || tmp.equals("O")) {
direction = Direction.EAST;
}
else if (tmp.equals("W")) {
direction = Direction.WEST;
}
else {
direction = null;
}
return new Coordinate(degree, minutes, seconds, direction);
}
else {
throw new ParseException(
"Die Koordinaten-Darstellung ist fehlerhaft: " + strg,
-1);
}
}
else {
throw new ParseException(
"Die Koordinaten-Darstellung ist fehlerhaft: " + strg, -1);
}
}
}
Java:
package de.tutorials.quiz10;
import static java.lang.Math.PI;
import static java.lang.Math.asin;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.sqrt;
import static java.lang.Math.toDegrees;
import static java.lang.Math.toRadians;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
/**
* http://www.movable-type.co.uk/scripts/latlong.html
*
* @author zeja
*/
public class WorldCoordinates {
private static final double EQUATORIAL_RADIUS_KM = 6378.137;// km
private static final double TWO_PI = 2.0 * PI;
private final Coordinate latitude;
private final Coordinate longitude;
private final String city;
public WorldCoordinates(Coordinate latitude, Coordinate longitude,
String city) {
this.latitude = latitude;
this.longitude = longitude;
this.city = city;
}
public double distanceTo(WorldCoordinates other) {
final double radLat1 = getLatitude( ).asDecimalRadian( );
final double radLat2 = other.getLatitude( ).asDecimalRadian( );
final double radLong1 = getLongitude( ).asDecimalRadian( );
final double radLong2 = other.getLongitude( ).asDecimalRadian( );
final double R = EQUATORIAL_RADIUS_KM; // km
final double dLat = radLat2 - radLat1;
final double dLon = radLong2 - radLong1;
final double dLatHalf = dLat / 2;
final double dLonHalf = dLon / 2;
final double a = sin(dLatHalf) * sin(dLatHalf) + cos(radLat1)
* cos(radLat2) * sin(dLonHalf) * sin(dLonHalf);
final double c = 2 * atan2(sqrt(a), sqrt(1 - a));
final double d = R * c;
return d;
}
private double toBearing(double value) {
return (toDegrees(value) + 360) % 360;
}
private double getBearing(WorldCoordinates other) {
final double radLat1 = getLatitude( ).asDecimalRadian( );
final double radLat2 = other.getLatitude( ).asDecimalRadian( );
final double radLong1 = getLongitude( ).asDecimalRadian( );
final double radLong2 = other.getLongitude( ).asDecimalRadian( );
final double dLon = radLong2 - radLong1;
final double y = sin(dLon) * cos(radLat2);
final double x = cos(radLat1) * sin(radLat2) - sin(radLat1)
* cos(radLat2) * cos(dLon);
final double phi = toBearing(atan2(y, x));
return phi;
}
public List<WorldCoordinates> calculateWaypoints(WorldCoordinates other,
int steps) {
final List<WorldCoordinates> waypoints = new ArrayList<WorldCoordinates>( );
final double R = EQUATORIAL_RADIUS_KM;
final double radLat1 = getLatitude( ).asDecimalRadian( );
final double radLong1 = getLongitude( ).asDecimalRadian( );
final double phi = toRadians(getBearing(other));
final double d = distanceTo(other);
waypoints.add(this);
for (int i = 0; i < (int) d; i += steps) {
final double dR = i / R;
final double lat2 = asin(sin(radLat1) * cos(dR) + cos(radLat1)
* sin(dR) * cos(phi));
double lon2 = radLong1
+ atan2(sin(phi) * sin(dR) * cos(radLat1), cos(dR)
- sin(radLat1) * sin(lat2));
// normalise to -180...+180
lon2 = ((lon2 + PI) % TWO_PI) - PI;
waypoints.add(new WorldCoordinates(new Coordinate(toDegrees(lat2),
true), new Coordinate(toDegrees(lon2), false), ""));
}
waypoints.add(other);
return waypoints;
}
/**
* Name der Stadt für diese Koordinaten.
*
* @return
*/
public String getCity() {
return city;
}
/**
* Breitengrad
*
* @return
*/
public Coordinate getLatitude() {
return latitude;
}
/**
* Längengrad.
*
* @return
*/
public Coordinate getLongitude() {
return longitude;
}
/**
* Benutzt die Google Maps API um für den Namen einer Stadt die
* Koordinaten abzurufen.
*
* @param cityName
* Der Name der Stadt
* @return Die Koordinaten für die Stadt
* @throws ParseException
* Wenn die Koordinaten nicht ermittelt werden
* konnten.
*/
public static WorldCoordinates getCoordinatesForCityName(
final String cityName) throws ParseException {
final String urlString = "http://maps.google.com/maps/geo?q="
+ cityName + "&output=xml&sensor=true_or_false&key=abcdefg";
try {
final URL url = new URL(urlString);
final URLConnection urlConnection = url.openConnection( );
final InputStream in = urlConnection.getInputStream( );
final BufferedReader br = new BufferedReader(new InputStreamReader(
in));
try {
String line = null;
while ((line = br.readLine( )) != null) {
// Eigentlich mit nem XML Parser lesen. Aber so
// gehts erstmal auch.
if (line.contains("<coordinates>")) {
final int start = line.indexOf("<coordinates>");
final int end = line.indexOf("</coordinates>");
if (start != -1 && end != -1) {
// Koordinaten auslesen
final String[] split = line.substring(
start + "<coordinates>".length( ), end)
.split(",");
if (split != null && split.length > 1) {
final Coordinate longitude = new Coordinate(
Double.parseDouble(split[0]), false);
final Coordinate latitude = new Coordinate(
Double.parseDouble(split[1]), true);
return new WorldCoordinates(latitude,
longitude, cityName);
}
}
}
}
throw new ParseException("Koordinaten für die Stadt: "
+ cityName + " konnten nicht ermittelt werden.", -1);
}
finally {
br.close( );
}
}
catch (MalformedURLException e) {
throw new ParseException(e.getMessage( ), -1);
}
catch (IOException e) {
throw new ParseException(e.getMessage( ), -1);
}
}
@Override
public String toString() {
return latitude + " " + longitude + " " + city;
}
}
Java:
package de.tutorials.quiz10;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Emitter für die Erstellung von SVG-Dateien.
*
* @author zeja
*/
public class SVGEmitter {
/**
* Zeilenumbruch.
*/
private static final String LINE_SEP = System.getProperty("line.separator");
/**
* Liste von Elementen für die SVG-Datei.
*/
private final List<SVGPart> svgList = new ArrayList<SVGPart>( );
/**
* Speicher des SVG in eine Datei.
*
* @param file
* Die Datei in die gespeichert werden soll.
* @throws IOException
* Wenn ein Fehler beim Speichern auftritt.
*/
public void save(File file) throws IOException {
final FileWriter w = new FileWriter(file);
try {
w.write(createSVGContent( ));
}
finally {
w.close( );
}
}
/**
* Erstellt den Inhalt der SVG Datei.
*
* @return
*/
private String createSVGContent() {
final StringBuilder b = new StringBuilder( );
b.append("<?xml version=\"1.0\" ?>").append(LINE_SEP);
b.append("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"").append(
LINE_SEP);
b.append(" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">")
.append(LINE_SEP);
b.append("<svg version=\"1.1\"").append(LINE_SEP);
b
.append(
" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"")
.append(LINE_SEP);
b
.append(
" width=\"1024\" height=\"512\" stroke=\"red\" fill=\"none\"")
.append(LINE_SEP);
b.append(" viewBox=\"-180 -90 360 180\" stroke-width=\"0.3\">")
.append(LINE_SEP);
b.append(" ").append(LINE_SEP);
b.append(" <defs>").append(LINE_SEP);
b.append(" <g id='Kreuz'>").append(LINE_SEP);
b.append(" <line x1=\"-1\" y1=\"-1\" x2=\"1\" y2=\"1\" />")
.append(LINE_SEP);
b.append(" <line x1=\"-1\" y1=\"1\" x2=\"1\" y2=\"-1\" />")
.append(LINE_SEP);
b.append(" </g>").append(LINE_SEP);
b.append(" <g id='Start'>").append(LINE_SEP);
b
.append(
" <polygon fill=\"red\" stroke=\"red\" points=\"0 0, 0 -2, 1 -1, 0 -1\" />")
.append(LINE_SEP);
b.append(" </g>").append(LINE_SEP);
b.append(" <g id='Ende'>").append(LINE_SEP);
b
.append(
" <polygon fill=\"yellow\" stroke=\"yellow\" points=\"0 0, 0 -2, -1 -1, 0 -1\" />")
.append(LINE_SEP);
b.append(" </g>").append(LINE_SEP);
b.append(" </defs>").append(LINE_SEP);
b.append(" ").append(LINE_SEP);
b
.append(
" <image x=\"-180\" y=\"-90\" width=\"360\" height=\"180\" xlink:href=\"http://veimages.gsfc.nasa.gov/2430/land_ocean_ice_2048.jpg\" />")
.append(LINE_SEP);
b.append(" ").append(LINE_SEP);
for (SVGPart part : svgList) {
b.append(" ").append(part.emit( )).append(LINE_SEP);
}
b.append("</svg>").append(LINE_SEP);
return b.toString( );
}
/**
* Erstellt ein Kreuz an den gegebenen Koordinaten und eine
* Beschriftung.
*
* @param coordinates
*/
public void addCross(final WorldCoordinates coordinates) {
this.svgList.add(new Text(coordinates));
this.svgList.add(new Cross(coordinates));
}
/**
* Erstellt eine Startfahne an den gegebenen Koordinaten und eine
* Beschriftung.
*
* @param from
*/
public void addStart(final WorldCoordinates from) {
svgList.add(new Text(from));
svgList.add(new Start(from));
}
/**
* Erstellt eine Zielfahne an den gegebenen Koordinaten und eine
* Beschriftung.
*
* @param to
*/
public void addEnd(final WorldCoordinates to) {
svgList.add(new Text(to));
svgList.add(new Ende(to));
}
/**
* Liste von Punkten, aus denen einen Linie erstellt wird.
* @param polyList
*/
public void addPolyList(final List<Point2D.Double> polyList) {
this.svgList.add(new PolyList(polyList));
}
private static abstract class SVGPart {
public abstract String emit();
}
private static class PolyList extends SVGPart {
private final List<Point2D.Double> polyList;
public PolyList(final List<Point2D.Double> polyList) {
this.polyList = polyList;
}
public String emit() {
final StringBuilder b = new StringBuilder( );
b.append("<polyline stroke=\"red\" stroke-width=\"0.3px\" ");
b.append("points=\"");
for (final Iterator<Point2D.Double> it = polyList.iterator( ); it
.hasNext( );) {
final Double point = it.next( );
b.append(point.x).append(" ").append(point.y);
if (it.hasNext( )) {
b.append(", ");
}
}
b.append("\" />");
return b.toString( );
}
}
private static class XLink extends SVGPart {
private final WorldCoordinates coordinates;
private final String label;
public XLink(final WorldCoordinates coordinates, final String label) {
this.coordinates = coordinates;
this.label = label;
}
@Override
public String emit() {
final StringBuilder b = new StringBuilder( );
b.append("<use xlink:href=\"#").append(label).append(
"\" transform=\"translate(").append(
coordinates.getLongitude( ).asDecimalDegree( )).append(" ")
.append(-coordinates.getLatitude( ).asDecimalDegree( ))
.append(")\" />");
return b.toString( );
}
}
private static class Start extends XLink {
public Start(final WorldCoordinates coordinates) {
super(coordinates, "Start");
}
}
private static class Ende extends XLink {
public Ende(final WorldCoordinates coordinates) {
super(coordinates, "Ende");
}
}
private static class Cross extends XLink {
public Cross(final WorldCoordinates coordinates) {
super(coordinates, "Kreuz");
}
}
private static class Text extends SVGPart {
private final WorldCoordinates coordinates;
public Text(final WorldCoordinates coordinates) {
this.coordinates = coordinates;
}
@Override
public String emit() {
final StringBuilder b = new StringBuilder( );
b.append("<text x=\""
+ (coordinates.getLongitude( ).asDecimalDegree( ) - 0)
+ "\" y=\""
+ (-coordinates.getLatitude( ).asDecimalDegree( ) - 2)
+ "\"");
b.append(" font-family=\"verdana\" font-size=\"3px\">");
b.append(coordinates.getCity( ));
b.append("</text>");
return b.toString( );
}
}
}