Issue 130. Add waypoint to GPX

This commit is contained in:
Victor Shcherb 2011-04-27 09:39:19 +02:00
parent bd6cfaa30c
commit 576dbb98e5
6 changed files with 219 additions and 132 deletions

View file

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="add_waypoint_dialog_added">Точка \'\'{0}\'\' была успешно добавлена</string>
<string name="add_waypoint_dialog_title">Добавить точку к записи GPX трека</string>
<string name="context_menu_item_add_waypoint">Добавить точку к треку</string>
<string name="amenity_type_administrative">Административное</string>
<string name="amenity_type_barrier">Препятствие</string>
<string name="amenity_type_education">Образование</string>

View file

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources>
<string name="add_waypoint_dialog_added">Waypoint \'\'{0}\'\' was successfully added</string>
<string name="add_waypoint_dialog_title">Add waypoint to recorded GPX track</string>
<string name="context_menu_item_add_waypoint">Add Gpx waypoint</string>
<string name="amenity_type_administrative">Administrative</string>
<string name="amenity_type_barrier">Barrier</string>
<string name="amenity_type_education">Education</string>
@ -42,7 +44,7 @@
<string name="version_index_is_big_for_memory">The index \'\'{0}\'\' did not fit into memory</string>
<string name="version_index_is_not_supported">The version of index \'\'{0}\'\' is not supported</string>
<string name="use_osmand_routing_service">OsmAnd offline routing</string>
<string name="use_osmand_routing_service">OsmAnd routing</string>
<string name="use_osmand_routing_service_descr">Use offline routing for long distances (experimental)</string>
<string name="osmand_routing_experimental">OsmAnd offline routing is experimental feature and it doesn\'t work for distance more than 20 km.\n Routing service is automatically switched to online Cloudmade.</string>
<string name="specified_dir_doesnt_exist">Can not find specified directory.</string>

View file

@ -12,7 +12,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import net.osmand.plus.R;
@ -25,7 +24,6 @@ import org.xmlpull.v1.XmlSerializer;
import android.content.Context;
import android.location.Location;
import android.util.Xml;
import android.widget.Toast;
public class GPXUtilities {
public final static Log log = LogUtil.getLog(GPXUtilities.class);
@ -47,61 +45,28 @@ public class GPXUtilities {
public double lat;
public double lon;
public String name;
// by default
public long time = 0;
}
public static class TrkSegment {
public List<TrkPt> points = new ArrayList<TrkPt>();
}
public static class Track {
public List<TrkSegment> segments = new ArrayList<TrkSegment>();
}
public static class GPXFile {
public List<Track> tracks = new ArrayList<Track>();
public List<WptPt> points = new ArrayList<WptPt>();
}
public static boolean saveToXMLFiles(File fout, List<WptPt> data, Context ctx ){
public static String writeGpxFile(File fout, GPXFile file, Context ctx) {
try {
FileOutputStream output = new FileOutputStream(fout);
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(output, "UTF-8"); //$NON-NLS-1$
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); //$NON-NLS-1$
serializer.startDocument("UTF-8", true); //$NON-NLS-1$
serializer.startTag(null, "gpx"); //$NON-NLS-1$
serializer.attribute(null, "version", "1.1"); //$NON-NLS-1$ //$NON-NLS-2$
serializer.attribute(null, "creator", Version.APP_NAME_VERSION); //$NON-NLS-1$
serializer.attribute("xmlns", "xsi", "http://www.w3.org/2001/XMLSchema-instance"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
serializer.attribute("xsi", "schemaLocation", "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
serializer.attribute(null, "xmlns", "http://www.topografix.com/GPX/1/1"); //$NON-NLS-1$ //$NON-NLS-2$
for (WptPt l : data) {
serializer.startTag(null, "wpt"); //$NON-NLS-1$
serializer.attribute(null, "lat", latLonFormat.format(l.lat)); //$NON-NLS-1$
serializer.attribute(null, "lon", latLonFormat.format(l.lon)); //$NON-NLS-1$ //$NON-NLS-2$
serializer.startTag(null, "name"); //$NON-NLS-1$
serializer.text(l.name);
serializer.endTag(null, "name"); //$NON-NLS-1$
serializer.endTag(null, "wpt"); //$NON-NLS-1$
}
serializer.endTag(null, "gpx"); //$NON-NLS-1$
serializer.flush();
serializer.endDocument();
return true;
} catch (RuntimeException e) {
log.error("Error saving gpx", e); //$NON-NLS-1$
Toast.makeText(ctx, ctx.getString(R.string.error_occurred_saving_gpx), Toast.LENGTH_LONG).show();
return false;
} catch (IOException e) {
log.error("Error saving gpx", e); //$NON-NLS-1$
Toast.makeText(ctx, ctx.getString(R.string.error_occurred_saving_gpx), Toast.LENGTH_LONG).show();
return false;
}
}
public static String saveToXMLFiles(File dir, Map<String, List<List<TrkPt>>> data, Context ctx){
SimpleDateFormat format = new SimpleDateFormat(GPX_TIME_FORMAT);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
for (String f : data.keySet()) {
File fout = new File(dir, f + ".gpx"); //$NON-NLS-1$
int ind = 1;
while(fout.exists()){
fout = new File(dir, f + "_"+(++ind)+".gpx"); //$NON-NLS-1$ //$NON-NLS-2$
}
FileOutputStream output = new FileOutputStream(fout);
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(output, "UTF-8"); //$NON-NLS-1$
@ -114,10 +79,11 @@ public class GPXUtilities {
serializer.attribute("xsi", "schemaLocation", "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
serializer.attribute(null, "xmlns", "http://www.topografix.com/GPX/1/1"); //$NON-NLS-1$ //$NON-NLS-2$
for (Track track : file.tracks) {
serializer.startTag(null, "trk"); //$NON-NLS-1$
for(List<TrkPt> l : data.get(f)){
for (TrkSegment segment : track.segments) {
serializer.startTag(null, "trkseg"); //$NON-NLS-1$
for(TrkPt p : l){
for (TrkPt p : segment.points) {
serializer.startTag(null, "trkpt"); //$NON-NLS-1$
serializer.attribute(null, "lat", latLonFormat.format(p.lat)); //$NON-NLS-1$ //$NON-NLS-2$
serializer.attribute(null, "lon", latLonFormat.format(p.lon)); //$NON-NLS-1$ //$NON-NLS-2$
@ -125,7 +91,7 @@ public class GPXUtilities {
serializer.text(format.format(new Date(p.time)));
serializer.endTag(null, "time"); //$NON-NLS-1$
serializer.startTag(null, "ele"); //$NON-NLS-1$
serializer.text(p.ele+""); //$NON-NLS-1$
serializer.text(p.ele + ""); //$NON-NLS-1$
serializer.endTag(null, "ele"); //$NON-NLS-1$
if (p.speed > 0) {
serializer.startTag(null, "speed"); //$NON-NLS-1$
@ -138,12 +104,26 @@ public class GPXUtilities {
serializer.endTag(null, "trkseg"); //$NON-NLS-1$
}
serializer.endTag(null, "trk"); //$NON-NLS-1$
}
for (WptPt l : file.points) {
serializer.startTag(null, "wpt"); //$NON-NLS-1$
serializer.attribute(null, "lat", latLonFormat.format(l.lat)); //$NON-NLS-1$
serializer.attribute(null, "lon", latLonFormat.format(l.lon)); //$NON-NLS-1$ //$NON-NLS-2$
serializer.startTag(null, "name"); //$NON-NLS-1$
serializer.text(l.name);
serializer.endTag(null, "name"); //$NON-NLS-1$
if (l.time != 0) {
serializer.startTag(null, "time"); //$NON-NLS-1$
serializer.text(format.format(new Date(l.time)));
serializer.endTag(null, "time"); //$NON-NLS-1$
}
serializer.endTag(null, "wpt"); //$NON-NLS-1$
}
serializer.endTag(null, "gpx"); //$NON-NLS-1$
serializer.flush();
serializer.endDocument();
}
return null;
} catch (RuntimeException e) {
log.error("Error saving gpx", e); //$NON-NLS-1$
return ctx.getString(R.string.error_occurred_saving_gpx);
@ -151,6 +131,7 @@ public class GPXUtilities {
log.error("Error saving gpx", e); //$NON-NLS-1$
return ctx.getString(R.string.error_occurred_saving_gpx);
}
return null;
}

View file

@ -14,6 +14,7 @@ import java.util.Set;
import net.osmand.FavouritePoint;
import net.osmand.GPXUtilities;
import net.osmand.OsmAndFormatter;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXFileResult;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.osm.LatLon;
@ -200,18 +201,21 @@ public class FavouritesActivity extends ListActivity {
Toast.makeText(this, R.string.sd_dir_not_accessible, Toast.LENGTH_LONG).show();
} else {
File f = new File(appDir, FILE_TO_SAVE);
List<WptPt> wpt = new ArrayList<WptPt>();
GPXFile gpx = new GPXFile();
for (int i = 0; i < favouritesAdapter.getCount(); i++) {
FavouritePoint p = favouritesAdapter.getItem(i);
WptPt pt = new WptPt();
pt.lat = p.getLatitude();
pt.lon = p.getLongitude();
pt.name = p.getName();
wpt.add(pt);
gpx.points.add(pt);
}
if(GPXUtilities.saveToXMLFiles(f, wpt, this)){
String warning = GPXUtilities.writeGpxFile(f, gpx, this);
if(warning == null){
Toast.makeText(this, MessageFormat.format(getString(R.string.fav_saved_sucessfully), f.getAbsolutePath()),
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, warning, Toast.LENGTH_LONG).show();
}
}
} else if(item.getItemId() == IMPORT_ID){

View file

@ -1604,6 +1604,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
actions.add(resources.getString(R.string.context_menu_item_search_transport));
actions.add(resources.getString(R.string.context_menu_item_add_favorite));
actions.add(resources.getString(R.string.context_menu_item_create_poi));
actions.add(resources.getString(R.string.context_menu_item_add_waypoint));
actions.add(resources.getString(R.string.context_menu_item_open_bug));
actions.add(resources.getString(R.string.context_menu_item_update_map));
actions.add(resources.getString(R.string.context_menu_item_download_map));
@ -1637,10 +1638,12 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
EditingPOIActivity activity = new EditingPOIActivity(MapActivity.this, (OsmandApplication) getApplication(), mapView);
activity.showCreateDialog(latitude, longitude);
} else if(which == 6){
osmBugsLayer.openBug(MapActivity.this, getLayoutInflater(), mapView, latitude, longitude);
addWaypoint(latitude, longitude);
} else if(which == 7){
reloadTile(mapView.getZoom(), latitude, longitude);
osmBugsLayer.openBug(MapActivity.this, getLayoutInflater(), mapView, latitude, longitude);
} else if(which == 8){
reloadTile(mapView.getZoom(), latitude, longitude);
} else if(which == 9){
DownloadTilesDialog dlg = new DownloadTilesDialog(MapActivity.this,
(OsmandApplication) getApplication(), mapView);
dlg.openDialog();
@ -1708,6 +1711,27 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
builder.create().show();
}
protected void addWaypoint(final double latitude, final double longitude){
Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.add_waypoint_dialog_title);
final EditText editText = new EditText(this);
builder.setView(editText);
builder.setNegativeButton(R.string.default_buttons_cancel, null);
builder.setPositiveButton(R.string.default_buttons_add, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String name = editText.getText().toString();
savingTrackHelper.insertPointData(latitude, longitude, System.currentTimeMillis(), name);
Toast.makeText(MapActivity.this, MessageFormat.format(getString(R.string.add_waypoint_dialog_added), name), Toast.LENGTH_SHORT)
.show();
}
});
builder.create().show();
}
private void openChangeLocationDialog() {
NavigatePointActivity dlg = new NavigatePointActivity(this);
dlg.showDialog();

View file

@ -8,7 +8,11 @@ import java.util.Map;
import net.osmand.GPXUtilities;
import net.osmand.LogUtil;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.Track;
import net.osmand.GPXUtilities.TrkPt;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.ResourceManager;
@ -25,7 +29,7 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
public final static String TRACKS_PATH = "tracks"; //$NON-NLS-1$
public final static String DATABASE_NAME = "tracks"; //$NON-NLS-1$
public final static int DATABASE_VERSION = 1;
public final static int DATABASE_VERSION = 2;
public final static String TRACK_NAME = "track"; //$NON-NLS-1$
public final static String TRACK_COL_DATE = "date"; //$NON-NLS-1$
@ -34,12 +38,20 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
public final static String TRACK_COL_ALTITUDE = "altitude"; //$NON-NLS-1$
public final static String TRACK_COL_SPEED = "speed"; //$NON-NLS-1$
public final static String POINT_NAME = "point"; //$NON-NLS-1$
public final static String POINT_COL_DATE = "date"; //$NON-NLS-1$
public final static String POINT_COL_LAT = "lat"; //$NON-NLS-1$
public final static String POINT_COL_LON = "lon"; //$NON-NLS-1$
public final static String POINT_COL_DESCRIPTION = "description"; //$NON-NLS-1$
public final static Log log = LogUtil.getLog(SavingTrackHelper.class);
private String updateScript;
private String updatePointsScript;
private long lastTimeUpdated = 0;
private final Context ctx;
@ -47,17 +59,31 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
this.ctx = ctx;
updateScript = "INSERT INTO " + TRACK_NAME + " VALUES (?, ?, ?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$
updatePointsScript = "INSERT INTO " + POINT_NAME + " VALUES (?, ?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public void onCreate(SQLiteDatabase db) {
createTableForTrack(db);
createTableForPoints(db);
}
private void createTableForTrack(SQLiteDatabase db){
db.execSQL("CREATE TABLE " + TRACK_NAME+ " ("+TRACK_COL_LAT +" double, " + TRACK_COL_LON+" double, " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ TRACK_COL_ALTITUDE+" double, " + TRACK_COL_SPEED+" double, " //$NON-NLS-1$ //$NON-NLS-2$
+ TRACK_COL_DATE +" long )" ); //$NON-NLS-1$
}
private void createTableForPoints(SQLiteDatabase db){
db.execSQL("CREATE TABLE " + POINT_NAME+ " ("+POINT_COL_LAT +" double, " + POINT_COL_LON+" double, " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ POINT_COL_DATE+" long, " + POINT_COL_DESCRIPTION+" text)" ); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(oldVersion < 2){
createTableForPoints(db);
}
}
@ -75,21 +101,81 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
return false;
}
/**
* @return warnings
*/
public List<String> saveDataToGpx(){
SQLiteDatabase db = getReadableDatabase();
List<String> warnings = new ArrayList<String>();
File file = OsmandSettings.getExternalStorageDirectory(ctx);
if(db != null && file.canWrite()){
file = new File(file, ResourceManager.APP_DIR + TRACKS_PATH);
file.mkdirs();
if (file.exists()) {
File dir = OsmandSettings.getExternalStorageDirectory(ctx);
if(db != null && dir.canWrite()){
dir = new File(dir, ResourceManager.APP_DIR + TRACKS_PATH);
dir.mkdirs();
if (dir.exists()) {
Map<String, GPXFile> data = new LinkedHashMap<String, GPXFile>();
collectDBPoints(db, data);
collectDBTracks(db, data);
// save file
for (String f : data.keySet()) {
File fout = new File(dir, f + ".gpx"); //$NON-NLS-1$
int ind = 1;
while (fout.exists()) {
fout = new File(dir, f + "_" + (++ind) + ".gpx"); //$NON-NLS-1$ //$NON-NLS-2$
}
String warn = GPXUtilities.writeGpxFile(fout, data.get(f), ctx);
if (warn != null) {
warnings.add(warn);
return warnings;
}
}
}
}
db = getWritableDatabase();
if (db != null && warnings.isEmpty()) {
// remove all from db
db.execSQL("DELETE FROM " + TRACK_NAME + " WHERE " + TRACK_COL_DATE + " <= ?", new Object[] { System.currentTimeMillis() }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
return warnings;
}
private void collectDBPoints(SQLiteDatabase db, Map<String, GPXFile> dataTracks) {
Cursor query = db.rawQuery("SELECT " + POINT_COL_LAT + "," + POINT_COL_LON + "," + POINT_COL_DATE + "," //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ POINT_COL_DESCRIPTION + " FROM " + POINT_NAME+" ORDER BY " + TRACK_COL_DATE +" ASC", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (query.moveToFirst()) {
do {
WptPt pt = new WptPt();
pt.lat = query.getDouble(0);
pt.lon = query.getDouble(1);
long time = query.getLong(2);
pt.time = time;
pt.name = query.getString(3);
String date = DateFormat.format("yyyy-MM-dd", time).toString(); //$NON-NLS-1$
GPXFile gpx;
if (dataTracks.containsKey(date)) {
gpx = dataTracks.get(date);
} else {
gpx = new GPXFile();
dataTracks.put(date, gpx);
}
gpx.points.add(pt);
} while (query.moveToNext());
}
query.close();
}
private void collectDBTracks(SQLiteDatabase db, Map<String, GPXFile> dataTracks) {
Cursor query = db.rawQuery("SELECT " + TRACK_COL_LAT + "," + TRACK_COL_LON + "," + TRACK_COL_ALTITUDE + "," //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ TRACK_COL_SPEED + "," + TRACK_COL_DATE + " FROM " + TRACK_NAME +" ORDER BY " + TRACK_COL_DATE +" ASC", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
long previousTime = 0;
Map<String, List<List<TrkPt>>> data = new LinkedHashMap<String, List<List<TrkPt>>>();
List<TrkPt> segment = new ArrayList<TrkPt>();
List<List<TrkPt>> track = new ArrayList<List<TrkPt>>();
track.add(segment);
TrkSegment segment = null;
Track track = null;
if (query.moveToFirst()) {
do {
TrkPt pt = new TrkPt();
@ -100,54 +186,35 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
long time = query.getLong(4);
pt.time = time;
if (previousTime == 0) {
data.put(DateFormat.format("yyyy-MM-dd", time).toString(), track); //$NON-NLS-1$
segment.add(pt);
} else if (Math.abs(time - previousTime) < 60000) {
if (track != null && Math.abs(time - previousTime) < 60000) {
// 1 hour - same segment
segment.add(pt);
} else if (Math.abs(time - previousTime) < 3600000) {
// 1 hour - same track
segment = new ArrayList<TrkPt>();
segment.add(pt);
track.add(segment);
segment.points.add(pt);
} else if (track != null && Math.abs(time - previousTime) < 2 * 60000) {
// 2 hour - same track
segment = new TrkSegment();
segment.points.add(pt);
track.segments.add(segment);
} else {
// check day (possibly better create new track (not new segment)
// check if date the same - new track otherwise new file
track = new Track();
segment = new TrkSegment();
track.segments.add(segment);
segment.points.add(pt);
String date = DateFormat.format("yyyy-MM-dd", time).toString(); //$NON-NLS-1$
if (data.containsKey(date)) {
track = data.get(date);
if (dataTracks.containsKey(date)) {
GPXFile gpx = dataTracks.get(date);
gpx.tracks.add(track);
} else {
track = new ArrayList<List<TrkPt>>();
data.put(date, track);
GPXFile file = new GPXFile();
file.tracks.add(track);
dataTracks.put(date, file);
}
segment = new ArrayList<TrkPt>();
segment.add(pt);
track.add(segment);
}
previousTime = time;
} while (query.moveToNext());
}
query.close();
String w = GPXUtilities.saveToXMLFiles(file, data, ctx);
if(w != null){
warnings.add(w);
}
}
}
db = getWritableDatabase();
if(db != null){
// Calendar cal = Calendar.getInstance();
// cal.setTime(new java.util.Date());
// cal.set(Calendar.HOUR_OF_DAY, 0);
// cal.set(Calendar.MINUTE, 0);
// cal.set(Calendar.SECOND, 0);
// cal.set(Calendar.MILLISECOND, 0);
// remove all from db
db.execSQL("DELETE FROM " + TRACK_NAME+ " WHERE " + TRACK_COL_DATE + " <= ?", new Object[]{System.currentTimeMillis()}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
return warnings;
}
public void insertData(double lat, double lon, double alt, double speed, long time, SharedPreferences settings){
@ -160,5 +227,12 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
}
}
public void insertPointData(double lat, double lon, long time, String description) {
SQLiteDatabase db = getWritableDatabase();
if (db != null) {
db.execSQL(updatePointsScript, new Object[] { lat, lon, time, description });
}
}
}