implement route information draw some route icons, small bug fix

git-svn-id: https://osmand.googlecode.com/svn/trunk@205 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-06-26 09:22:41 +00:00
parent 497bd6bf3e
commit 451f061330
16 changed files with 542 additions and 85 deletions

View file

@ -13,14 +13,22 @@ public class ToDoConstants {
*/
public int DESCRIBE_ABOUT_AUTHORS = 8;
// TODO ANDROID
// 42. Revise UI (icons/layouts). Support different devices. Add inactive/focus(!) icon versions.
// Some icons are not fine (as back menu from map - it is blured).
// TODO: draw EXIT!!!, YOURS (calc turn/angle/time). [other done]
// 56. Add usage of CloudMade API for calculating route (show next turn & distance to it instead of mini map).
// 57. Implement routing information about expected time arriving
// 58. Implement difference about show route/follow route (show travel time/arrival time, show mini map/next turn, etc)
// 59. Show route information (directions/time, ....). Could be shown in context menu route.
// 46. Implement downloading strategy for tiles : select max zoom to download [16,15,14,...]
// That means you can save internet because from [16 -> zoom -> 18], [14 -> zoom -> 16 - suitable for speed > 40], ...
// 58. Upload/Download zip-index from site & unzip them on phone
// 50. Invent opening hours editor in order to edit POI hours better on device
// 53. Add progress bars : to internet communication activities [editing/commiting/deleting poi], do not hide edit poi dialog if operation failed

View file

@ -15,6 +15,7 @@
<activity android:name=".activities.search.SearchActivity" android:label="@string/search_activity" ></activity>
<activity android:name=".activities.NavigatePointActivity"></activity>
<activity android:name=".activities.DownloadIndexActivity"></activity>
<activity android:name=".activities.ShowRouteInfoActivity"></activity>
<activity android:name=".activities.FavouritesActivity" android:label="@string/favourites_activity"></activity>
<activity android:name=".activities.search.SearchPOIActivity" android:label="@string/searchpoi_activity"></activity>
@ -26,6 +27,7 @@
<activity android:name=".activities.search.SearchStreet2ByNameActivity"></activity>
<activity android:name=".activities.search.SearchBuildingByNameActivity"></activity>
<activity android:name=".activities.EditPOIFilterActivity"></activity>
</application>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView android:id="@+id/direction" android:layout_width="32dp" android:layout_height="32dp"></ImageView>
<TextView android:text="@+id/TextView01" android:id="@+id/distance" android:layout_marginLeft ="5dp"
android:layout_width="50dp" android:layout_height="wrap_content"></TextView>
<TextView android:text="@+id/TextView02" android:id="@+id/description" android:layout_weight="1"
android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:text="@+id/TextView02" android:id="@+id/time" android:layout_marginLeft ="5dp"
android:layout_width="45dp" android:layout_height="wrap_content"></TextView>
</LinearLayout>

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="route_about">О маршруте</string>
<string name="route_general_information">Общая протяженность = {0}, время в пути = ''{1}''.</string>
<string name="router_service_descr">Выберите сервис для прокладки маршрута</string>
<string name="router_service">Прокладка маршрута</string>
<string name="download_sd_dir_not_accessible">Директория на SD карточка не доступна для сохранения</string>
<string name="download_question">Вы хотите загрузить {0} - {1} ?</string>
<string name="address">Адрес</string>

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="route_about">About route</string>
<string name="route_general_information">Overall distance = {0}, travelling time = ''{1}''.</string>
<string name="router_service_descr">Choose routing service</string>
<string name="router_service">Routing</string>
<string name="download_sd_dir_not_accessible">Directory on SD card to save index is not accessible</string>
<string name="download_question">Do you want to download {0} - {1} ?</string>
<string name="address">Address</string>

View file

@ -18,6 +18,7 @@
<CheckBoxPreference android:summary="@string/use_english_names_descr" android:title="@string/use_english_names" android:key="use_english_names"></CheckBoxPreference>
<Preference android:title="@string/reload_indexes" android:key="reload_indexes" android:summary="@string/reload_indexes_descr"></Preference>
<Preference android:title="@string/download_indexes" android:key="download_indexes" android:summary="@string/download_indexes_descr"></Preference>
<ListPreference android:title="@string/router_service" android:key="router_service" android:summary="@string/router_service_descr"></ListPreference>
</PreferenceScreen>
<PreferenceScreen android:title="@string/monitor_preferences" android:summary="@string/monitor_preferences_descr">

View file

@ -6,6 +6,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import com.osmand.activities.RouteProvider.RouteService;
import com.osmand.map.ITileSource;
import com.osmand.map.TileSourceManager;
import com.osmand.map.TileSourceManager.TileSourceTemplate;
@ -111,6 +112,24 @@ public class OsmandSettings {
return prefs.edit().putString(APPLICATION_MODE, p.name()).commit();
}
// this value string is synchronized with settings_pref.xml preference name
public static final String ROUTER_SERVICE = "router_service"; //$NON-NLS-1$
public static RouteService getRouterService(Context ctx) {
SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
int ord = prefs.getInt(ROUTER_SERVICE, RouteService.CLOUDMADE.ordinal());
if(ord < RouteService.values().length){
return RouteService.values()[ord];
} else {
return RouteService.CLOUDMADE;
}
}
public static boolean setRouterService(Context ctx, RouteService p) {
SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
return prefs.edit().putInt(ROUTER_SERVICE, p.ordinal()).commit();
}
// this value string is synchronized with settings_pref.xml preference name
public static final String SAVE_CURRENT_TRACK = "save_current_track"; //$NON-NLS-1$
public static final String RELOAD_INDEXES = "reload_indexes"; //$NON-NLS-1$

View file

@ -176,6 +176,8 @@ public class EditPOIFilterActivity extends ListActivity {
}
if (subCategories.size() == accepted.size()) {
filter.selectSubTypesToAccept(amenity, null);
} else if(accepted.size() == 0){
filter.setTypeToAccept(amenity, false);
} else {
filter.selectSubTypesToAccept(amenity, accepted);
}

View file

@ -38,7 +38,6 @@ import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
/**
* @author Maxim Frolov
*
*/
public class FavouritesActivity extends ListActivity {

View file

@ -94,7 +94,6 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
private SavingTrackHelper savingTrackHelper;
private RoutingHelper routingHelper;
private boolean calculateRouteOnGps = false;
private WakeLock wakeLock;
@ -171,7 +170,11 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
routingHelper.setAppMode(OsmandSettings.getApplicationMode(this));
if(!Algoritms.objectEquals(routingHelper.getFinalLocation(), pointToNavigate)){
// there is no way how to clear mode. Only user can do : clear point to navigate, exit from app & set up new point.
// that case help to not calculate route at all.
routingHelper.setFollowingMode(false);
routingHelper.setFinalAndCurrentLocation(pointToNavigate, null);
}
navigationLayer.setPointToNavigate(pointToNavigate);
@ -354,7 +357,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
updateSpeedBearing(location);
locationLayer.setLastKnownLocation(location);
if(calculateRouteOnGps){
if(routingHelper.isFollowingMode()){
routingHelper.setCurrentLocation(location);
}
if (location != null) {
@ -405,7 +408,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
}
routingHelper.setFinalAndCurrentLocation(point, null);
if(point == null){
calculateRouteOnGps = false;
routingHelper.setFollowingMode(false);
}
navigationLayer.setPointToNavigate(point);
updateNavigateToPointMenu();
@ -507,6 +510,8 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
@Override
protected void onResume() {
super.onResume();
// routing helper with current activity
routingHelper = RoutingHelper.getInstance(this);
if(mapView.getMap() != OsmandSettings.getMapTileSource(this)){
mapView.setMap(OsmandSettings.getMapTileSource(this));
}
@ -672,10 +677,18 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
Location map = new Location("map"); //$NON-NLS-1$
map.setLatitude(lat);
map.setLongitude(lon);
calculateRouteOnGps = true;
routingHelper.setFollowingMode(true);
routingHelper.setFinalAndCurrentLocation(navigationLayer.getPointToNavigate(), map);
}
});
if(routingHelper.isRouterEnabled()){
builder.setNeutralButton(R.string.route_about, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(new Intent(MapActivity.this, ShowRouteInfoActivity.class));
}
});
}
builder.setNegativeButton(R.string.only_show, new DialogInterface.OnClickListener(){
@Override
@ -684,11 +697,12 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
Location map = new Location("map"); //$NON-NLS-1$
map.setLatitude(lat);
map.setLongitude(lon);
calculateRouteOnGps = false;
routingHelper.setFollowingMode(false);
routingHelper.setFinalAndCurrentLocation(navigationLayer.getPointToNavigate(), map);
}
});
builder.show();
}
protected void reloadTile(final int zoom, final double latitude, final double longitude){

View file

@ -32,6 +32,17 @@ import com.osmand.osm.LatLon;
public class RouteProvider {
private static final org.apache.commons.logging.Log log = LogUtil.getLog(RouteProvider.class);
public enum RouteService {
CLOUDMADE("CloudMade"), YOURS("YOURS"); //$NON-NLS-1$ //$NON-NLS-2$
private final String name;
private RouteService(String name){
this.name = name;
}
public String getName() {
return name;
}
}
public RouteProvider(){
}
@ -80,6 +91,10 @@ public class RouteProvider {
for (int i = directions.size() - 1; i >= 0; i--) {
directions.get(i).afterLeftTime = sum;
sum += directions.get(i).expectedTime;
directions.get(i).distance = listDistance[directions.get(i).routePointOffset];
if(i < directions.size() - 1){
directions.get(i).distance -=listDistance[directions.get(i + 1).routePointOffset];
}
}
}
}
@ -93,15 +108,19 @@ public class RouteProvider {
}
public RouteCalculationResult calculateRouteImpl(Location start, LatLon end, ApplicationMode mode){
public RouteCalculationResult calculateRouteImpl(Location start, LatLon end, ApplicationMode mode, RouteService type){
long time = System.currentTimeMillis();
if (start != null && end != null) {
if(log.isInfoEnabled()){
log.info("Start finding route from " + start + " to " + end); //$NON-NLS-1$ //$NON-NLS-2$
log.info("Start finding route from " + start + " to " + end +" using " + type.getName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
try {
// RouteCalculationResult res = findYOURSRoute(start, end, mode);
RouteCalculationResult res = findCloudMadeRoute(start, end, mode);
RouteCalculationResult res;
if (type == RouteService.YOURS) {
res = findYOURSRoute(start, end, mode);
} else {
res = findCloudMadeRoute(start, end, mode);
}
if(log.isInfoEnabled() && res.locations != null){
log.info("Finding route contained " + res.locations.size() + " points for " + (System.currentTimeMillis() - time) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@ -221,6 +240,7 @@ public class RouteProvider {
if(list.getLength() > 0){
directions = new ArrayList<RouteDirectionInfo>();
}
RouteDirectionInfo previous = null;
for (int i = 0; i < list.getLength(); i++) {
Element item = (Element) list.item(i);
try {
@ -242,13 +262,50 @@ public class RouteProvider {
}
int offset = Integer.parseInt(getContentFromNode(item, "offset")); //$NON-NLS-1$
dirInfo.routePointOffset = offset;
if(previous != null && previous.turnType != TurnType.C && previous.turnType != null){
// calculate angle
if(previous.routePointOffset > 0){
float paz = res.get(previous.routePointOffset - 1).bearingTo(res.get(previous.routePointOffset));
float caz;
if(previous.turnType.isExit() && dirInfo.routePointOffset < res.size() - 1){
caz = res.get(dirInfo.routePointOffset).bearingTo(res.get(dirInfo.routePointOffset + 1));
} else {
caz = res.get(dirInfo.routePointOffset - 1).bearingTo(res.get(dirInfo.routePointOffset));
}
float angle = caz - paz;
if(angle < 0){
angle += 360;
}
if(previous.turnAngle == 0f){
previous.turnAngle = angle;
}
}
}
directions.add(dirInfo);
previous = dirInfo;
} catch (NumberFormatException e) {
log.info("Exception", e); //$NON-NLS-1$
} catch (IllegalArgumentException e) {
log.info("Exception", e); //$NON-NLS-1$
}
}
if(previous != null && previous.turnType != TurnType.C && previous.turnType != null){
// calculate angle
if(previous.routePointOffset > 0 && previous.routePointOffset < res.size() - 1){
float paz = res.get(previous.routePointOffset - 1).bearingTo(res.get(previous.routePointOffset));
float caz = res.get(previous.routePointOffset).bearingTo(res.get(res.size() -1));
float angle = caz - paz;
if(angle < 0){
angle += 360;
}
if(previous.turnAngle == 0f){
previous.turnAngle = angle;
}
}
}

View file

@ -1,16 +1,20 @@
package com.osmand.activities;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.app.Activity;
import android.location.Location;
import android.util.FloatMath;
import android.widget.Toast;
import com.osmand.LogUtil;
import com.osmand.OsmandSettings;
import com.osmand.R;
import com.osmand.OsmandSettings.ApplicationMode;
import com.osmand.activities.RouteProvider.RouteCalculationResult;
import com.osmand.activities.RouteProvider.RouteService;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
@ -19,7 +23,9 @@ public class RoutingHelper {
private static final org.apache.commons.logging.Log log = LogUtil.getLog(RoutingHelper.class);
// activity to show messages & refresh map when route is calculated
private MapActivity activity;
private Activity activity;
private boolean isFollowingMode = false;
// instead of this properties RouteCalculationResult could be used
private List<Location> routeNodes = new ArrayList<Location>();
@ -63,13 +69,20 @@ public class RoutingHelper {
}
private static RoutingHelper INSTANCE = new RoutingHelper();
public static RoutingHelper getInstance(MapActivity activity){
INSTANCE.activity = activity;
public static RoutingHelper getInstance(Activity ctx){
INSTANCE.activity = ctx;
return INSTANCE;
}
public boolean isFollowingMode() {
return isFollowingMode;
}
public void setFollowingMode(boolean isFollowingMode) {
this.isFollowingMode = isFollowingMode;
}
public synchronized void setFinalAndCurrentLocation(LatLon finalLocation, Location currentLocation){
this.finalLocation = finalLocation;
@ -107,9 +120,7 @@ public class RoutingHelper {
Location lastPoint = routeNodes.get(routeNodes.size() - 1);
if(currentRoute > routeNodes.size() - 3 && currentLocation.distanceTo(lastPoint) < 60){
if(lastFixedLocation != null && lastFixedLocation.distanceTo(lastPoint) < 60){
if(activity != null){
showMessage(activity.getString(R.string.arrived_at_destination));
}
updateCurrentRoute(routeNodes.size() - 1);
// clear final location to prevent all time showing message
finalLocation = null;
@ -231,16 +242,26 @@ public class RoutingHelper {
currentRoute = 0;
}
public synchronized int getDistance(double lat, double lon){
public synchronized int getLeftDistance(){
if(listDistance != null && currentRoute < listDistance.length){
int dist = listDistance[currentRoute];
Location l = routeNodes.get(currentRoute);
dist += MapUtils.getDistance(lat, lon, l.getLatitude(), l.getLongitude());
if(lastFixedLocation != null){
dist += lastFixedLocation.distanceTo(l);
}
return dist;
}
return 0;
}
public Location getLocationFromRouteDirection(RouteDirectionInfo i){
if(i.routePointOffset < routeNodes.size()){
return routeNodes.get(i.routePointOffset);
}
return null;
}
public RouteDirectionInfo getNextRouteDirectionInfo(){
if(directionInfo != null && currentDirectionInfo < directionInfo.size() - 1){
return directionInfo.get(currentDirectionInfo + 1);
@ -248,6 +269,13 @@ public class RoutingHelper {
return null;
}
public List<RouteDirectionInfo> getRouteDirections(){
if(directionInfo != null && currentDirectionInfo < directionInfo.size()){
return directionInfo.subList(currentDirectionInfo, directionInfo.size());
}
return Collections.emptyList();
}
public int getDistanceToNextRouteDirection() {
if (directionInfo != null && currentDirectionInfo < directionInfo.size()) {
int dist = listDistance[currentRoute];
@ -282,6 +310,7 @@ public class RoutingHelper {
}
public void calculateRoute(final Location start, final LatLon end){
final RouteService service = OsmandSettings.getRouterService(activity);
if(currentRunningJob == null){
// do not evaluate very often
if (System.currentTimeMillis() - lastTimeEvaluatedRoute > evalWaitInterval) {
@ -289,7 +318,7 @@ public class RoutingHelper {
currentRunningJob = new Thread(new Runnable() {
@Override
public void run() {
RouteCalculationResult res = provider.calculateRouteImpl(start, end, mode);
RouteCalculationResult res = provider.calculateRouteImpl(start, end, mode, service);
synchronized (RoutingHelper.this) {
if (res.isCalculated()) {
setNewRoute(res);
@ -303,13 +332,15 @@ public class RoutingHelper {
}
currentRunningJob = null;
}
if (activity != null) {
if (res.isCalculated()) {
int[] dist = res.getListDistance();
int l = dist != null && dist.length > 0 ? dist[0] : 0;
showMessage(activity.getString(R.string.new_route_calculated_dist) + MapUtils.getFormattedDistance(l));
if (activity instanceof MapActivity) {
// be aware that is non ui thread
activity.getMapView().refreshMap();
((MapActivity) activity).getMapView().refreshMap();
}
} else {
if (res.getErrorMessage() != null) {
showMessage(activity.getString(R.string.error_calculating_route) + res.getErrorMessage());
@ -319,7 +350,6 @@ public class RoutingHelper {
showMessage(activity.getString(R.string.empty_route_calculated));
}
}
}
lastTimeEvaluatedRoute = System.currentTimeMillis();
}
}, "Calculating route"); //$NON-NLS-1$
@ -382,26 +412,63 @@ public class RoutingHelper {
public static enum TurnType {
C , // continue (go straight)
TL, // turn left
TSLL, // turn slight left
TSHL, // turn sharp left
TR, // turn right
TSLR, // turn slight right
TSHR, // turn sharp right
TU, // U-turn
public static class TurnType {
public static final TurnType C = new TurnType("C"); // continue (go straight) //$NON-NLS-1$
public static final TurnType TL = new TurnType("TL"); // turn left //$NON-NLS-1$
public static final TurnType TSLL = new TurnType("TSLL"); // turn slight left //$NON-NLS-1$
public static final TurnType TSHL = new TurnType("TSHL"); // turn sharp left //$NON-NLS-1$
public static final TurnType TR = new TurnType("TR"); // turn right //$NON-NLS-1$
public static final TurnType TSLR = new TurnType("TSLR"); // turn slight right //$NON-NLS-1$
public static final TurnType TSHR = new TurnType("TSHR"); // turn sharp right //$NON-NLS-1$
public static final TurnType TU = new TurnType("TU"); // U-turn //$NON-NLS-1$
public static TurnType[] vals = new TurnType[] {C, TL, TSLL, TSHL, TR, TSLR, TSHR, TU};
// TODO Exit3...
public static TurnType valueOf(String s){
for(TurnType v : vals){
if(v.getValue().equals(s)){
return v;
}
}
if(s!= null && s.startsWith("EXIT")){ //$NON-NLS-1$
return getExitTurn(Integer.parseInt(s.substring(4)));
}
return null;
}
private final String value;
private int exitOut;
public static TurnType getExitTurn(int out){
return new TurnType("EXIT", out); //$NON-NLS-1$
}
private TurnType(String value, int exitOut){
this.value = value;
this.exitOut = exitOut;
}
private TurnType(String value){
this.value = value;
}
public String getValue() {
return value;
}
public int getExitOut() {
return exitOut;
}
public boolean isExit(){
return value.equals("EXIT"); //$NON-NLS-1$
}
}
public static class RouteDirectionInfo {
public String descriptionRoute;
public String descriptionRoute = ""; //$NON-NLS-1$
public int expectedTime;
public float turnAngle;
public float turnAngle; // calculated CW head rotation if previous direction to NORTH
public TurnType turnType;
public int routePointOffset;
// calculated vars
public int afterLeftTime;
public int distance;
}

View file

@ -24,6 +24,7 @@ import com.osmand.ProgressDialogImplementation;
import com.osmand.R;
import com.osmand.ResourceManager;
import com.osmand.OsmandSettings.ApplicationMode;
import com.osmand.activities.RouteProvider.RouteService;
import com.osmand.map.TileSourceManager;
import com.osmand.map.TileSourceManager.TileSourceTemplate;
@ -46,6 +47,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
private EditTextPreference userPassword;
private Preference reloadIndexes;
private Preference downloadIndexes;
private ListPreference routerPreference;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -93,6 +95,8 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
positionOnMap.setOnPreferenceChangeListener(this);
tileSourcePreference =(ListPreference) screen.findPreference(OsmandSettings.MAP_TILE_SOURCES);
tileSourcePreference.setOnPreferenceChangeListener(this);
routerPreference =(ListPreference) screen.findPreference(OsmandSettings.ROUTER_SERVICE);
routerPreference.setOnPreferenceChangeListener(this);
}
@ -143,8 +147,18 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
applicationMode.setValue(OsmandSettings.getApplicationMode(this).name());
String[] entries = new String[RouteService.values().length];
String entry = OsmandSettings.getRouterService(this).getName();
for(int i=0; i<entries.length; i++){
entries[i] = RouteService.values()[i].getName();
}
routerPreference.setEntries(entries);
routerPreference.setEntryValues(entries);
routerPreference.setValue(entry);
List<TileSourceTemplate> list = TileSourceManager.getKnownSourceTemplates();
String[] entries = new String[list.size()];
entries = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
entries[i] = list.get(i).getName();
}
@ -206,6 +220,18 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
} else if(preference == positionOnMap){
edit.putInt(OsmandSettings.POSITION_ON_MAP, positionOnMap.findIndexOfValue((String) newValue));
edit.commit();
} else if (preference == routerPreference) {
RouteService s = null;
for(RouteService r : RouteService.values()){
if(r.getName().equals(newValue)){
s = r;
break;
}
}
if(s != null){
edit.putInt(OsmandSettings.ROUTER_SERVICE, s.ordinal());
}
edit.commit();
} else if (preference == tileSourcePreference) {
edit.putString(OsmandSettings.MAP_TILE_SOURCES, (String) newValue);
edit.commit();

View file

@ -0,0 +1,148 @@
/**
*
*/
package com.osmand.activities;
import java.text.MessageFormat;
import java.util.List;
import android.app.ListActivity;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.osmand.OsmandSettings;
import com.osmand.R;
import com.osmand.activities.RoutingHelper.RouteDirectionInfo;
import com.osmand.activities.RoutingHelper.TurnType;
import com.osmand.osm.MapUtils;
import com.osmand.views.MapInfoLayer;
/**
*
*/
public class ShowRouteInfoActivity extends ListActivity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
ListView lv = new ListView(this);
lv.setId(android.R.id.list);
TextView header = new TextView(this);
RoutingHelper helper = RoutingHelper.getInstance(this);
int time = helper.getLeftTime()* 1000;
int dist = helper.getLeftDistance();
header.setText(MessageFormat.format(getString(R.string.route_general_information), MapUtils.getFormattedDistance(dist),
DateFormat.format("kk:mm", time))); //$NON-NLS-1$
lv.addHeaderView(header);
setContentView(lv);
setListAdapter(new RouteInfoAdapter(RoutingHelper.getInstance(this).getRouteDirections()));
}
public void onListItemClick(ListView parent, View v, int position, long id) {
RouteDirectionInfo item = ((RouteInfoAdapter)getListAdapter()).getItem(position);
RoutingHelper inst = RoutingHelper.getInstance(this);
Location loc = inst.getLocationFromRouteDirection(item);
if(loc != null){
OsmandSettings.setMapLocationToShow(this, loc.getLatitude(),loc.getLongitude());
startActivity(new Intent(this, MapActivity.class));
}
}
class RouteDrawable extends Drawable {
Paint paintRouteDirection;
Path p = new Path();
Matrix m = new Matrix();
public RouteDrawable(){
m.setScale(0.33f, 0.33f);
paintRouteDirection = new Paint();
paintRouteDirection.setStyle(Style.FILL_AND_STROKE);
paintRouteDirection.setColor(Color.rgb(100, 0, 255));
paintRouteDirection.setAntiAlias(true);
}
public void setRouteType(TurnType t){
MapInfoLayer.calcTurnPath(p, t, m);
}
@Override
public void draw(Canvas canvas) {
canvas.drawPath(p, paintRouteDirection);
}
@Override
public int getOpacity() {
return 0;
}
@Override
public void setAlpha(int alpha) {
paintRouteDirection.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
paintRouteDirection.setColorFilter(cf);
}
}
class RouteInfoAdapter extends ArrayAdapter<RouteDirectionInfo> {
RouteInfoAdapter(List<RouteDirectionInfo> list) {
super(ShowRouteInfoActivity.this, R.layout.route_info_list_item, list);
this.setNotifyOnChange(false);
}
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.route_info_list_item, parent, false);
}
RouteDirectionInfo model = (RouteDirectionInfo) getItem(position);
TextView label = (TextView) row.findViewById(R.id.description);
TextView distanceLabel = (TextView) row.findViewById(R.id.distance);
TextView timeLabel = (TextView) row.findViewById(R.id.time);
ImageView icon = (ImageView) row.findViewById(R.id.direction);
if(!(icon.getDrawable() instanceof RouteDrawable)){
icon.setImageDrawable(new RouteDrawable());
}
((RouteDrawable) icon.getDrawable()).setRouteType(model.turnType);
distanceLabel.setText(MapUtils.getFormattedDistance(model.distance));
label.setText(model.descriptionRoute);
if(model.expectedTime < 3600){
timeLabel.setText(DateFormat.format("mm:ss", model.expectedTime * 1000)); //$NON-NLS-1$
} else {
timeLabel.setText(DateFormat.format("k:mm:ss", model.expectedTime * 1000)); //$NON-NLS-1$
}
return row;
}
}
}

View file

@ -2,6 +2,7 @@ package com.osmand.views;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
@ -10,6 +11,7 @@ import android.graphics.Paint.Style;
import android.location.Location;
import android.text.format.DateFormat;
import com.osmand.Algoritms;
import com.osmand.Messages;
import com.osmand.activities.MapActivity;
import com.osmand.activities.RoutingHelper.RouteDirectionInfo;
@ -58,6 +60,8 @@ public class MapInfoLayer implements OsmandMapLayer {
private int centerMiniRouteY;
private int centerMiniRouteX;
private float scaleMiniRoute;
private Matrix pathTransform;
private TurnType cachedTurnType;
public MapInfoLayer(MapActivity map, RouteLayer layer){
@ -105,6 +109,7 @@ public class MapInfoLayer implements OsmandMapLayer {
boundsForZoom = new RectF(0, 32, 35, 64);
boundsForSpeed = new RectF(35, 32, 110, 64);
boundsForMiniRoute = new RectF(0, 64, 96, 196);
boundsForLeftTime = new RectF(0, 0, 75, 32);
@ -125,6 +130,8 @@ public class MapInfoLayer implements OsmandMapLayer {
pathForCompass2.lineTo(9, 15);
pathForTurn = new Path();
pathTransform = new Matrix();
pathTransform.setTranslate(boundsForMiniRoute.left, boundsForMiniRoute.top);
}
public boolean distChanged(int oldDist, int dist){
@ -139,7 +146,7 @@ public class MapInfoLayer implements OsmandMapLayer {
if(map.getPointToNavigate() != null){
int d = 0;
if(map.getRoutingHelper().isRouterEnabled()){
d = map.getRoutingHelper().getDistance(view.getLatitude(), view.getLongitude());
d = map.getRoutingHelper().getLeftDistance();
}
if (d == 0) {
Location.distanceBetween(view.getLatitude(), view.getLongitude(), map.getPointToNavigate().getLatitude(), map
@ -209,24 +216,10 @@ public class MapInfoLayer implements OsmandMapLayer {
}
private void calcTurnPath(TurnType turnType){
pathForTurn.reset();
// if(turnType == TurnType.C){
int c = (int) ((boundsForMiniRoute.right - boundsForMiniRoute.left) /2 + boundsForMiniRoute.left);
pathForTurn.moveTo(c + 8, boundsForMiniRoute.bottom - 32);
pathForTurn.lineTo(c + 8, boundsForMiniRoute.top + 32);
pathForTurn.lineTo(c + 20, boundsForMiniRoute.top + 32);
pathForTurn.lineTo(c, boundsForMiniRoute.top + 5);
pathForTurn.lineTo(c - 20, boundsForMiniRoute.top + 32);
pathForTurn.lineTo(c - 8, boundsForMiniRoute.top + 32);
pathForTurn.lineTo(c - 8, boundsForMiniRoute.bottom - 32);
pathForTurn.close();
// }
}
private void drawRouteInfo(Canvas canvas) {
if(routeLayer != null && routeLayer.getHelper().isRouterEnabled()){
if (showMiniMap) {
if(routeLayer != null && routeLayer.getHelper().isRouterEnabled() && !routeLayer.getHelper().isFollowingMode() ){
int d = routeLayer.getHelper().getDistanceToNextRouteDirection();
if (showMiniMap || d == 0) {
if (!routeLayer.getPath().isEmpty()) {
canvas.save();
canvas.clipRect(boundsForMiniRoute);
@ -240,39 +233,34 @@ public class MapInfoLayer implements OsmandMapLayer {
canvas.restore();
}
} else {
int d = routeLayer.getHelper().getDistanceToNextRouteDirection();
if(d > 0){
canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintAlphaGray);
canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintBlack);
RouteDirectionInfo next = routeLayer.getHelper().getNextRouteDirectionInfo();
if (next != null) {
calcTurnPath(next.turnType);
if (!Algoritms.objectEquals(cachedTurnType, next.turnType)) {
cachedTurnType = next.turnType;
calcTurnPath(pathForTurn, cachedTurnType, pathTransform);
}
canvas.drawPath(pathForTurn, paintRouteDirection);
canvas.drawPath(pathForTurn, paintBlack);
canvas.drawText(MapUtils.getFormattedDistance(d),
boundsForMiniRoute.left + 10, boundsForMiniRoute.bottom - 9, paintBlack);
}
} else {
// TEST
// canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintAlphaGray);
// canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintBlack);
// calcTurnPath(TurnType.C);
// canvas.drawPath(pathForTurn, paintRouteDirection);
// canvas.drawPath(pathForTurn, paintBlack);
// canvas.drawText(MapUtils.getFormattedDistance(300),
// boundsForMiniRoute.left + 10, boundsForMiniRoute.bottom - 9, paintBlack);
canvas.drawText(MapUtils.getFormattedDistance(d), boundsForMiniRoute.left + 10, boundsForMiniRoute.bottom - 9,
paintBlack);
}
}
boolean followingMode = routeLayer.getHelper().isFollowingMode();
int time = routeLayer.getHelper().getLeftTime() * 1000;
if(time == 0){
cachedLeftTime = 0;
cachedLeftTimeString = null;
} else {
if(Math.abs(System.currentTimeMillis() + time - cachedLeftTime) > 30000){
cachedLeftTime = System.currentTimeMillis() + time;
cachedLeftTimeString = DateFormat.format("k:mm", cachedLeftTime).toString(); //$NON-NLS-1$
long toFindTime = time;
if(followingMode){
toFindTime += System.currentTimeMillis();
}
if(Math.abs(toFindTime - cachedLeftTime) > 30000){
cachedLeftTime = toFindTime;
cachedLeftTimeString = DateFormat.format("kk:mm", cachedLeftTime).toString(); //$NON-NLS-1$
}
}
if(cachedLeftTimeString != null) {
@ -284,9 +272,110 @@ public class MapInfoLayer implements OsmandMapLayer {
canvas.drawText(cachedLeftTimeString, boundsForLeftTime.left + 5, boundsForLeftTime.bottom - 9, paintBlack);
}
} else {
// TEST
// TODO remove
// canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintAlphaGray);
// canvas.drawRoundRect(boundsForMiniRoute, 3, 3, paintBlack);
// canvas.drawPath(pathForTurn, paintRouteDirection);
// canvas.drawPath(pathForTurn, paintBlack);
// canvas.drawText(MapUtils.getFormattedDistance(300),
// boundsForMiniRoute.left + 15, boundsForMiniRoute.bottom - 9, paintBlack);
}
}
public static void calcTurnPath(Path pathForTurn, TurnType turnType, Matrix transform) {
pathForTurn.reset();
// draw path 96x96
int c = 48;
int w = 16;
pathForTurn.moveTo(c, 94);
float sarrowL = 30; // side of arrow
float harrowL = (float) Math.sqrt(2) * sarrowL; // hypotenuse of arrow
float spartArrowL = (float) ((sarrowL - w / Math.sqrt(2)) / 2);
float hpartArrowL = (float) (harrowL - w) / 2;
if (turnType == TurnType.C) {
int h = 65;
pathForTurn.rMoveTo(w / 2, 0);
pathForTurn.rLineTo(0, -h);
pathForTurn.rLineTo(hpartArrowL, 0);
pathForTurn.rLineTo(-harrowL / 2, -harrowL / 2); // center
pathForTurn.rLineTo(-harrowL / 2, harrowL / 2);
pathForTurn.rLineTo(hpartArrowL, 0);
pathForTurn.rLineTo(0, h);
} else if (turnType == TurnType.TR || turnType == TurnType.TL) {
int b = turnType == TurnType.TR ? 1 : -1;
int h = 36;
float quadShiftX = 22;
float quadShiftY = 22;
pathForTurn.rMoveTo(-b * 8, 0);
pathForTurn.rLineTo(0, -h);
pathForTurn.rQuadTo(0, -quadShiftY, b * quadShiftX, -quadShiftY);
pathForTurn.rLineTo(0, hpartArrowL);
pathForTurn.rLineTo(b * harrowL / 2, -harrowL / 2); // center
pathForTurn.rLineTo(-b * harrowL / 2, -harrowL / 2);
pathForTurn.rLineTo(0, hpartArrowL);
pathForTurn.rQuadTo(-b * (quadShiftX + w), 0, -b * (quadShiftX + w), quadShiftY + w);
pathForTurn.rLineTo(0, h);
} else if (turnType == TurnType.TSLR || turnType == TurnType.TSLL) {
int b = turnType == TurnType.TSLR ? 1 : -1;
int h = 40;
int quadShiftY = 22;
float quadShiftX = (float) (quadShiftY / (1 + Math.sqrt(2)));
float nQuadShiftX = (sarrowL - 2 * spartArrowL) - quadShiftX - w;
float nQuadShifty = quadShiftY + (sarrowL - 2 * spartArrowL);
pathForTurn.rMoveTo(-b * 4, 0);
pathForTurn.rLineTo(0, -h /* + partArrowL */);
pathForTurn.rQuadTo(0, -quadShiftY + quadShiftX /*- partArrowL*/, b * quadShiftX, -quadShiftY /*- partArrowL*/);
pathForTurn.rLineTo(b * spartArrowL, spartArrowL);
pathForTurn.rLineTo(0, -sarrowL); // center
pathForTurn.rLineTo(-b * sarrowL, 0);
pathForTurn.rLineTo(b * spartArrowL, spartArrowL);
pathForTurn.rQuadTo(b * nQuadShiftX, -nQuadShiftX, b * nQuadShiftX, nQuadShifty);
pathForTurn.rLineTo(0, h);
} else if (turnType == TurnType.TSHR || turnType == TurnType.TSHL) {
int b = turnType == TurnType.TSHR ? 1 : -1;
int h = 45;
float quadShiftX = 22;
float quadShiftY = -(float) (quadShiftX / (1 + Math.sqrt(2)));
float nQuadShiftX = -(sarrowL - 2 * spartArrowL) - quadShiftX - w;
float nQuadShiftY = -quadShiftY + (sarrowL - 2 * spartArrowL);
pathForTurn.rMoveTo(-b * 8, 0);
pathForTurn.rLineTo(0, -h);
pathForTurn.rQuadTo(0, -(quadShiftX - quadShiftY), b * quadShiftX, quadShiftY);
pathForTurn.rLineTo(-b * spartArrowL, spartArrowL);
pathForTurn.rLineTo(b * sarrowL, 0); // center
pathForTurn.rLineTo(0, -sarrowL);
pathForTurn.rLineTo(-b * spartArrowL, spartArrowL);
pathForTurn.rCubicTo(b * nQuadShiftX / 2, nQuadShiftX / 2, b * nQuadShiftX, nQuadShiftX / 2, b * nQuadShiftX, nQuadShiftY);
pathForTurn.rLineTo(0, h);
} else if(turnType == TurnType.TU){
int h = 54;
float quadShiftX = 13;
float quadShiftY = 13;
pathForTurn.rMoveTo(28, 0);
pathForTurn.rLineTo(0, -h);
pathForTurn.rQuadTo(0, -(quadShiftY+w), -(quadShiftX+w), -(quadShiftY+w));
pathForTurn.rQuadTo(-(quadShiftX+w), 0, -(quadShiftX+w), (quadShiftY+w));
pathForTurn.rLineTo(-hpartArrowL, 0);
pathForTurn.rLineTo(harrowL/2, harrowL/2); // center
pathForTurn.rLineTo(harrowL/2, -harrowL/2);
pathForTurn.rLineTo(-hpartArrowL, 0);
pathForTurn.rQuadTo(0, -quadShiftX, quadShiftX, -quadShiftY);
pathForTurn.rQuadTo(quadShiftX, 0, quadShiftX, quadShiftY);
pathForTurn.rLineTo(0, h);
} else if(turnType != null && turnType.isExit()){
// TODO !!! & check how it works
}
pathForTurn.close();
pathForTurn.transform(transform);
}
@Override
public void destroyLayer() {

View file

@ -66,7 +66,7 @@ public class RouteLayer implements OsmandMapLayer {
view.isPointOnTheRotatedMap(helper.getCurrentLocation().getLatitude(), helper.getCurrentLocation().getLongitude())){
boundsRect = new Rect(-w / 2, -h, 3 * w / 2, h);
} else {
boundsRect = new Rect(0, -h, w, h);
boundsRect = new Rect(0, 0, w, h);
}
view.calculateTileRectangle(boundsRect, view.getCenterPointX(), view.getCenterPointY(), view.getXTile(), view.getYTile(),
tileRect);