commit
f931eb6389
8 changed files with 181 additions and 17 deletions
158
GPX.md
Normal file
158
GPX.md
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
The OsmAnd's GPX file format conforms to GPX 1.1 specification with additional data written as extensions. There are few sections of such data:
|
||||||
|
|
||||||
|
## Track appearance
|
||||||
|
These parameters are used to customize the appearance of a track on the map. Used inside "gpx" tag and applies to all tracks inside gpx.
|
||||||
|
#### Parameters
|
||||||
|
* **show_arrows** [*true, false*] - show / hide arrows along the path line.
|
||||||
|
* **width** [*thin, medium, bold, 1-24*] - width of a track line on the map. The thin, medium and bold are style depended values (should be defined as currentTrackWidth attribute).
|
||||||
|
* **color** [*#AARRGGBB, #RRGGBB*] - color of a track line on the map. Hex values.
|
||||||
|
* **split_type** [*no_split, distance, time*] - split type for a track.
|
||||||
|
* **split_interval** [*double*] - split interval for a track. Distance (meters), time (seconds).
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
```xml
|
||||||
|
<gpx version="1.1" creator="OsmAndRouterV2" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
|
||||||
|
...
|
||||||
|
<extensions>
|
||||||
|
<show_arrows>true</show_arrows>
|
||||||
|
<color>#4e4eff</color>
|
||||||
|
<split_type>distance</split_type>
|
||||||
|
<split_interval>2000.0</split_interval>
|
||||||
|
<width>bold</width>
|
||||||
|
</extensions>
|
||||||
|
</gpx>
|
||||||
|
```
|
||||||
|
## Details of a track point (trkpt)
|
||||||
|
Written to a gpx file while recording a track.
|
||||||
|
* **speed** (meters per second)
|
||||||
|
* **heading** (0-359 degrees)
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
```xml
|
||||||
|
<trkpt lat="52.397799" lon="4.575998">
|
||||||
|
<ele>203</ele>
|
||||||
|
<time>2019-05-08T10:36:43Z</time>
|
||||||
|
<hdop>3</hdop>
|
||||||
|
<extensions>
|
||||||
|
<heading>273</heading>
|
||||||
|
<speed>5.02</speed>
|
||||||
|
</extensions>
|
||||||
|
</trkpt>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Calculated route(s)
|
||||||
|
This data contains information about a route built with **OsmAnd** (route segments, turns, road names and types, restrictions, etc.). With their help, route can be restored completely as if it had just been built even without the currently installed offline maps.
|
||||||
|
|
||||||
|
There can be several routes in one gpx file. Each of them is contained in a specific segment (**trkseg** / **extensions**). In this form, a gpx file is saved when exporting a constructed route or when saving a track that consists of several separate segments via the **Plan route**.
|
||||||
|
When using the **Plan route** tool, route key points (**rtept**) are additionally written to the gpx file. There can also be several **rte** blocks (according to a number of separate segments / tracks in a gpx file).
|
||||||
|
|
||||||
|
#### Gpx structure:
|
||||||
|
```xml
|
||||||
|
<trk>
|
||||||
|
<trkseg>
|
||||||
|
<!-- List of segment points. The order of the points corresponds to the order and length of the route segments (<route><segment length="x" ... />). -->
|
||||||
|
<!-- The value of the "length" attribute corresponds to the number of points in this segment of the route. -->
|
||||||
|
<trkpt ... ></trkpt>
|
||||||
|
<extensions>
|
||||||
|
<!-- List of route segments -->
|
||||||
|
<route>
|
||||||
|
<segment ... />
|
||||||
|
</route>
|
||||||
|
<!-- Properties of segments included in the route. -->
|
||||||
|
<!-- This data is taken from offline maps during the initial construction of a route. -->
|
||||||
|
<types>
|
||||||
|
<type ... />
|
||||||
|
</types>
|
||||||
|
</extensions>
|
||||||
|
</trkseg>
|
||||||
|
</trk>
|
||||||
|
|
||||||
|
<!-- List of intermediate route points. If there are multiple routes, the order of the rte list matches the order of the route segments. -->
|
||||||
|
<rte>
|
||||||
|
<rtept ... />
|
||||||
|
<!-- For routes built with the "Plan route", the parameters of key points are saved. -->
|
||||||
|
<extensions>
|
||||||
|
<!-- Route profile type for next segment (car, bicycle, pedestrian, etc.). -->
|
||||||
|
<profile>...</profile>
|
||||||
|
<!-- The index of the point in the gpx segment that corresponds to the first point of the calculated route for this segment. -->
|
||||||
|
<trkpt_idx>...</trkpt_idx>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
</rte>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
```xml
|
||||||
|
<gpx version="1.1" creator="OsmAndRouterV2" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
|
||||||
|
<metadata>
|
||||||
|
<name>Fri 06 Nov 2020</name>
|
||||||
|
</metadata>
|
||||||
|
<trk>
|
||||||
|
<name>Fri 06 Nov 2020</name>
|
||||||
|
<trkseg>
|
||||||
|
<trkpt lat="52.3639849" lon="4.8900533">
|
||||||
|
<ele>0.801</ele>
|
||||||
|
</trkpt>
|
||||||
|
<trkpt lat="52.3636917" lon="4.8922849">
|
||||||
|
<ele>0.998</ele>
|
||||||
|
</trkpt>
|
||||||
|
<trkpt lat="52.3636885" lon="4.892309">
|
||||||
|
<ele>1</ele>
|
||||||
|
</trkpt>
|
||||||
|
<trkpt lat="52.3636426" lon="4.8922902">
|
||||||
|
<ele>0.963</ele>
|
||||||
|
</trkpt>
|
||||||
|
<trkpt lat="52.363564" lon="4.8922607">
|
||||||
|
<ele>0.899</ele>
|
||||||
|
</trkpt>
|
||||||
|
|
||||||
|
....
|
||||||
|
|
||||||
|
<extensions>
|
||||||
|
<route>
|
||||||
|
<segment id="7372058" length="3" segmentTime="178.44" speed="1.11" turnType="C" types="0,1,2,3,4,5,6" names="57" />
|
||||||
|
<segment id="334164679" length="5" segmentTime="86.11" speed="1.11" turnType="TR" turnAngle="91.88" types="7,8,0,9,10,11,12,13,6" pointTypes=";;14,15;16,17,18;" names="58" />
|
||||||
|
<segment id="334603581" length="6" segmentTime="75.5" speed="1.11" types="19,20,21,7,8,0,22,9,10,11,12,13,23,6" pointTypes=";14;16,24;16,24;14;" names="58" />
|
||||||
|
<segment id="446707354" length="3" segmentTime="8.32" speed="1.11" turnType="TSLL" turnAngle="-25.44" types="19,25,21,7,8,22,9,1,11,12,13,6" names="58" />
|
||||||
|
...
|
||||||
|
</route>
|
||||||
|
<types>
|
||||||
|
<type t="lit" v="yes" />
|
||||||
|
<type t="oneway" v="yes" />
|
||||||
|
<type t="highway" v="unclassified" />
|
||||||
|
<type t="surface" v="paving_stones" />
|
||||||
|
<type t="maxspeed" v="30" />
|
||||||
|
...
|
||||||
|
</types>
|
||||||
|
</extensions>
|
||||||
|
</trkseg>
|
||||||
|
</trk>
|
||||||
|
|
||||||
|
<rte>
|
||||||
|
<rtept lat="52.3639945" lon="4.8900532">
|
||||||
|
<extensions>
|
||||||
|
<profile>pedestrian</profile>
|
||||||
|
<trkpt_idx>0</trkpt_idx>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
<rtept lat="52.3612797" lon="4.8911677">
|
||||||
|
<extensions>
|
||||||
|
<profile>pedestrian</profile>
|
||||||
|
<trkpt_idx>24</trkpt_idx>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
<rtept lat="52.356996" lon="4.8912071">
|
||||||
|
<extensions>
|
||||||
|
<profile>pedestrian</profile>
|
||||||
|
<trkpt_idx>89</trkpt_idx>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
<rtept lat="52.3542374" lon="4.8947024">
|
||||||
|
<extensions>
|
||||||
|
<profile>pedestrian</profile>
|
||||||
|
<trkpt_idx>121</trkpt_idx>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
</rte>
|
||||||
|
</gpx>
|
||||||
|
```
|
|
@ -13,6 +13,7 @@ import net.osmand.data.PointDescription;
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.data.QuadTree;
|
import net.osmand.data.QuadTree;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording;
|
import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording;
|
||||||
|
@ -69,8 +70,9 @@ public class AudioNotesLayer extends OsmandMapLayer implements
|
||||||
@Override
|
@Override
|
||||||
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
if (tileBox.getZoom() >= startZoom) {
|
if (tileBox.getZoom() >= startZoom) {
|
||||||
float textScale = activity.getMyApplication().getSettings().TEXT_SCALE.get();
|
OsmandApplication app = activity.getMyApplication();
|
||||||
float iconSize = getIconSize(activity) * 3 / 2.5f * textScale;
|
float textScale = app.getSettings().TEXT_SCALE.get();
|
||||||
|
float iconSize = getIconSize(app);
|
||||||
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
||||||
|
|
||||||
DataTileManager<Recording> recs = plugin.getRecordings();
|
DataTileManager<Recording> recs = plugin.getRecordings();
|
||||||
|
|
|
@ -104,20 +104,21 @@ public class OsmBugsLayer extends OsmandMapLayer implements IContextMenuProvider
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
startZoom = activity.getMyApplication().getSettings().SHOW_OSM_BUGS_MIN_ZOOM.get();
|
OsmandApplication app = activity.getMyApplication();
|
||||||
|
startZoom = app.getSettings().SHOW_OSM_BUGS_MIN_ZOOM.get();
|
||||||
if (tileBox.getZoom() >= startZoom) {
|
if (tileBox.getZoom() >= startZoom) {
|
||||||
// request to load
|
// request to load
|
||||||
data.queryNewData(tileBox);
|
data.queryNewData(tileBox);
|
||||||
List<OpenStreetNote> objects = data.getResults();
|
List<OpenStreetNote> objects = data.getResults();
|
||||||
|
|
||||||
if (objects != null) {
|
if (objects != null) {
|
||||||
float textScale = activity.getMyApplication().getSettings().TEXT_SCALE.get();
|
float textScale = app.getSettings().TEXT_SCALE.get();
|
||||||
float iconSize = getIconSize(activity) * 3 / 2.5f * textScale;
|
float iconSize = getIconSize(app);
|
||||||
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
||||||
List<OpenStreetNote> fullObjects = new ArrayList<>();
|
List<OpenStreetNote> fullObjects = new ArrayList<>();
|
||||||
List<LatLon> fullObjectsLatLon = new ArrayList<>();
|
List<LatLon> fullObjectsLatLon = new ArrayList<>();
|
||||||
List<LatLon> smallObjectsLatLon = new ArrayList<>();
|
List<LatLon> smallObjectsLatLon = new ArrayList<>();
|
||||||
boolean showClosed = activity.getMyApplication().getSettings().SHOW_CLOSED_OSM_BUGS.get();
|
boolean showClosed = app.getSettings().SHOW_CLOSED_OSM_BUGS.get();
|
||||||
for (OpenStreetNote o : objects) {
|
for (OpenStreetNote o : objects) {
|
||||||
if (!o.isOpened() && !showClosed) {
|
if (!o.isOpened() && !showClosed) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package net.osmand.plus.views;
|
package net.osmand.plus.views;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter;
|
||||||
|
@ -44,6 +43,7 @@ import java.util.Map;
|
||||||
|
|
||||||
public abstract class OsmandMapLayer {
|
public abstract class OsmandMapLayer {
|
||||||
|
|
||||||
|
public static final float ICON_VISIBLE_PART_RATIO = 0.45f;
|
||||||
protected List<LatLon> fullObjectsLatLon;
|
protected List<LatLon> fullObjectsLatLon;
|
||||||
protected List<LatLon> smallObjectsLatLon;
|
protected List<LatLon> smallObjectsLatLon;
|
||||||
|
|
||||||
|
@ -235,8 +235,8 @@ public abstract class OsmandMapLayer {
|
||||||
return (int) (r * tb.getDensity());
|
return (int) (r * tb.getDensity());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getIconSize(Context ctx) {
|
protected float getIconSize(OsmandApplication app) {
|
||||||
return ctx.getResources().getDimensionPixelSize(R.dimen.favorites_icon_outline_size);
|
return app.getResources().getDimensionPixelSize(R.dimen.favorites_icon_outline_size) * ICON_VISIBLE_PART_RATIO * app.getSettings().TEXT_SCALE.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect getIconDestinationRect(float x, float y, int width, int height, float scale) {
|
public Rect getIconDestinationRect(float x, float y, int width, int height, float scale) {
|
||||||
|
|
|
@ -95,7 +95,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
|
||||||
if (this.settings.SHOW_FAVORITES.get() && favorites.isFavoritesLoaded()) {
|
if (this.settings.SHOW_FAVORITES.get() && favorites.isFavoritesLoaded()) {
|
||||||
if (tileBox.getZoom() >= startZoom) {
|
if (tileBox.getZoom() >= startZoom) {
|
||||||
float textScale = this.settings.TEXT_SCALE.get();
|
float textScale = this.settings.TEXT_SCALE.get();
|
||||||
float iconSize = getIconSize(view.getContext()) * 3 / 2.5f * textScale;
|
float iconSize = getIconSize(view.getApplication());
|
||||||
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
||||||
|
|
||||||
// request to load
|
// request to load
|
||||||
|
|
|
@ -494,7 +494,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
|
||||||
private void drawSelectedFilesPoints(Canvas canvas, RotatedTileBox tileBox, List<SelectedGpxFile> selectedGPXFiles) {
|
private void drawSelectedFilesPoints(Canvas canvas, RotatedTileBox tileBox, List<SelectedGpxFile> selectedGPXFiles) {
|
||||||
if (tileBox.getZoom() >= START_ZOOM) {
|
if (tileBox.getZoom() >= START_ZOOM) {
|
||||||
float textScale = view.getSettings().TEXT_SCALE.get();
|
float textScale = view.getSettings().TEXT_SCALE.get();
|
||||||
float iconSize = getIconSize(view.getContext()) * 3 / 2.5f * textScale;
|
float iconSize = getIconSize(view.getApplication());
|
||||||
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
||||||
|
|
||||||
List<LatLon> fullObjectsLatLon = new ArrayList<>();
|
List<LatLon> fullObjectsLatLon = new ArrayList<>();
|
||||||
|
|
|
@ -200,7 +200,7 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
||||||
objects = data.getResults();
|
objects = data.getResults();
|
||||||
if (objects != null) {
|
if (objects != null) {
|
||||||
float textScale = app.getSettings().TEXT_SCALE.get();
|
float textScale = app.getSettings().TEXT_SCALE.get();
|
||||||
float iconSize = getIconSize(app) * 1.5f * textScale;
|
float iconSize = getIconSize(app);
|
||||||
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tileBox);
|
||||||
WaypointHelper wph = app.getWaypointHelper();
|
WaypointHelper wph = app.getWaypointHelper();
|
||||||
PointImageDrawable pointImageDrawable = PointImageDrawable.getOrCreate(view.getContext(),
|
PointImageDrawable pointImageDrawable = PointImageDrawable.getOrCreate(view.getContext(),
|
||||||
|
@ -394,7 +394,8 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
||||||
public int getTextShift(Amenity amenity, RotatedTileBox rb) {
|
public int getTextShift(Amenity amenity, RotatedTileBox rb) {
|
||||||
int radiusPoi = getRadiusPoi(rb);
|
int radiusPoi = getRadiusPoi(rb);
|
||||||
if (isPresentInFullObjects(amenity.getLocation())) {
|
if (isPresentInFullObjects(amenity.getLocation())) {
|
||||||
radiusPoi += (getIconSize(app) - app.getResources().getDimensionPixelSize(R.dimen.favorites_icon_size_small)) / 2;
|
radiusPoi += (app.getResources().getDimensionPixelSize(R.dimen.favorites_icon_outline_size)
|
||||||
|
- app.getResources().getDimensionPixelSize(R.dimen.favorites_icon_size_small)) / 2;
|
||||||
}
|
}
|
||||||
return radiusPoi;
|
return radiusPoi;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import net.osmand.data.RotatedTileBox;
|
||||||
import net.osmand.data.TransportStop;
|
import net.osmand.data.TransportStop;
|
||||||
import net.osmand.osm.edit.Node;
|
import net.osmand.osm.edit.Node;
|
||||||
import net.osmand.osm.edit.Way;
|
import net.osmand.osm.edit.Way;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.base.PointImageDrawable;
|
import net.osmand.plus.base.PointImageDrawable;
|
||||||
import net.osmand.plus.settings.backend.CommonPreference;
|
import net.osmand.plus.settings.backend.CommonPreference;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
@ -181,10 +182,11 @@ public class TransportStopsLayer extends OsmandMapLayer implements ContextMenuLa
|
||||||
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tb, DrawSettings settings) {
|
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tb, DrawSettings settings) {
|
||||||
List<TransportStop> objects = null;
|
List<TransportStop> objects = null;
|
||||||
boolean nightMode = settings.isNightMode();
|
boolean nightMode = settings.isNightMode();
|
||||||
|
OsmandApplication app = mapActivity.getMyApplication();
|
||||||
if (tb.getZoom() >= startZoomRoute) {
|
if (tb.getZoom() >= startZoomRoute) {
|
||||||
if (stopRoute != null) {
|
if (stopRoute != null) {
|
||||||
objects = stopRoute.route.getForwardStops();
|
objects = stopRoute.route.getForwardStops();
|
||||||
int color = stopRoute.getColor(mapActivity.getMyApplication(), nightMode);
|
int color = stopRoute.getColor(app, nightMode);
|
||||||
attrs.paint.setColor(color);
|
attrs.paint.setColor(color);
|
||||||
attrs.updatePaints(view.getApplication(), settings, tb);
|
attrs.updatePaints(view.getApplication(), settings, tb);
|
||||||
try {
|
try {
|
||||||
|
@ -217,8 +219,8 @@ public class TransportStopsLayer extends OsmandMapLayer implements ContextMenuLa
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objects != null) {
|
if (objects != null) {
|
||||||
float textScale = mapActivity.getMyApplication().getSettings().TEXT_SCALE.get();
|
float textScale = app.getSettings().TEXT_SCALE.get();
|
||||||
float iconSize = getIconSize(mapActivity) * 3 / 2.5f * textScale;
|
float iconSize = getIconSize(app);
|
||||||
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tb);
|
QuadTree<QuadRect> boundIntersections = initBoundIntersections(tb);
|
||||||
List<TransportStop> fullObjects = new ArrayList<>();
|
List<TransportStop> fullObjects = new ArrayList<>();
|
||||||
for (TransportStop o : objects) {
|
for (TransportStop o : objects) {
|
||||||
|
@ -228,7 +230,7 @@ public class TransportStopsLayer extends OsmandMapLayer implements ContextMenuLa
|
||||||
if (intersects(boundIntersections, x, y, iconSize, iconSize)) {
|
if (intersects(boundIntersections, x, y, iconSize, iconSize)) {
|
||||||
PointImageDrawable pointImageDrawable = PointImageDrawable.getOrCreate(mapActivity,
|
PointImageDrawable pointImageDrawable = PointImageDrawable.getOrCreate(mapActivity,
|
||||||
ContextCompat.getColor(mapActivity, R.color.transport_stop_icon_background),
|
ContextCompat.getColor(mapActivity, R.color.transport_stop_icon_background),
|
||||||
true,false ,0, BackgroundType.SQUARE);
|
true, false, 0, BackgroundType.SQUARE);
|
||||||
pointImageDrawable.setAlpha(0.9f);
|
pointImageDrawable.setAlpha(0.9f);
|
||||||
pointImageDrawable.drawSmallPoint(canvas, x, y, textScale);
|
pointImageDrawable.drawSmallPoint(canvas, x, y, textScale);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue