001 //License: GPLv2 or later. Copyright 2007 by Raphael Mack and others 002 003 package org.openstreetmap.josm.data.gpx; 004 005 import java.io.File; 006 import java.util.Collection; 007 import java.util.LinkedList; 008 import java.util.Map; 009 010 import org.openstreetmap.josm.data.Bounds; 011 012 /** 013 * Objects of this class represent a gpx file with tracks, waypoints and routes. 014 * It uses GPX v1.1, see {@link <a href="http://www.topografix.com/GPX/1/1/">the spec</a>} 015 * for details. 016 * 017 * @author Raphael Mack <ramack@raphael-mack.de> 018 */ 019 public class GpxData extends WithAttributes { 020 021 public static final String META_PREFIX = "meta."; 022 public static final String META_AUTHOR_NAME = META_PREFIX + "author.name"; 023 public static final String META_AUTHOR_EMAIL = META_PREFIX + "author.email"; 024 public static final String META_AUTHOR_LINK = META_PREFIX + "author.link"; 025 public static final String META_COPYRIGHT_AUTHOR = META_PREFIX + "copyright.author"; 026 public static final String META_COPYRIGHT_LICENSE = META_PREFIX + "copyright.license"; 027 public static final String META_COPYRIGHT_YEAR = META_PREFIX + "copyright.year"; 028 public static final String META_DESC = META_PREFIX + "desc"; 029 public static final String META_KEYWORDS = META_PREFIX + "keywords"; 030 public static final String META_LINKS = META_PREFIX + "links"; 031 public static final String META_NAME = META_PREFIX + "name"; 032 public static final String META_TIME = META_PREFIX + "time"; 033 034 public File storageFile; 035 public boolean fromServer; 036 037 public String creator; 038 039 public final Collection<GpxTrack> tracks = new LinkedList<GpxTrack>(); 040 public final Collection<GpxRoute> routes = new LinkedList<GpxRoute>(); 041 public final Collection<WayPoint> waypoints = new LinkedList<WayPoint>(); 042 043 @SuppressWarnings("unchecked") 044 public void mergeFrom(GpxData other) { 045 if (storageFile == null && other.storageFile != null) { 046 storageFile = other.storageFile; 047 } 048 fromServer = fromServer && other.fromServer; 049 050 for (Map.Entry<String, Object> ent : other.attr.entrySet()) { 051 // TODO: Detect conflicts. 052 String k = ent.getKey(); 053 if (k.equals(META_LINKS) && attr.containsKey(META_LINKS)) { 054 ((Collection<GpxLink>) attr.get(META_LINKS)).addAll( 055 (Collection<GpxLink>) ent.getValue()); 056 } else { 057 attr.put(k, ent.getValue()); 058 } 059 } 060 tracks.addAll(other.tracks); 061 routes.addAll(other.routes); 062 waypoints.addAll(other.waypoints); 063 } 064 065 public boolean hasTrackPoints() { 066 for (GpxTrack trk : tracks) { 067 for (GpxTrackSegment trkseg : trk.getSegments()) { 068 if (!trkseg.getWayPoints().isEmpty()) 069 return true; 070 } 071 } 072 return false; 073 } 074 075 public boolean hasRoutePoints() { 076 for (GpxRoute rte : routes) { 077 if (!rte.routePoints.isEmpty()) 078 return true; 079 } 080 return false; 081 } 082 083 public boolean isEmpty() { 084 return !hasRoutePoints() && !hasTrackPoints() && waypoints.isEmpty(); 085 } 086 087 /** 088 * calculates the bounding box of available data and returns it. 089 * The bounds are not stored internally, but recalculated every time 090 * this function is called. 091 * 092 * FIXME might perhaps use visitor pattern? 093 */ 094 public Bounds recalculateBounds() { 095 Bounds bounds = null; 096 for (WayPoint wpt : waypoints) { 097 if (bounds == null) { 098 bounds = new Bounds(wpt.getCoor()); 099 } else { 100 bounds.extend(wpt.getCoor()); 101 } 102 } 103 for (GpxRoute rte : routes) { 104 for (WayPoint wpt : rte.routePoints) { 105 if (bounds == null) { 106 bounds = new Bounds(wpt.getCoor()); 107 } else { 108 bounds.extend(wpt.getCoor()); 109 } 110 } 111 } 112 for (GpxTrack trk : tracks) { 113 Bounds trkBounds = trk.getBounds(); 114 if (trkBounds != null) { 115 if (bounds == null) { 116 bounds = new Bounds(trkBounds); 117 } else { 118 bounds.extend(trkBounds); 119 } 120 } 121 } 122 return bounds; 123 } 124 125 /** 126 * calculates the sum of the lengths of all track segments 127 */ 128 public double length(){ 129 double result = 0.0; // in meters 130 131 for (GpxTrack trk : tracks) { 132 result += trk.length(); 133 } 134 135 return result; 136 } 137 }