add osmdroid overlays + bonuspack
This commit is contained in:
159
src/org/oscim/overlay/DefaultResourceProxyImpl.java
Normal file
159
src/org/oscim/overlay/DefaultResourceProxyImpl.java
Normal file
@@ -0,0 +1,159 @@
|
||||
package org.oscim.overlay;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
public class DefaultResourceProxyImpl implements ResourceProxy, MapViewConstants {
|
||||
// private static final String TAG = DefaultResourceProxyImpl.class.getSimpleName();
|
||||
|
||||
private DisplayMetrics mDisplayMetrics;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param pContext
|
||||
* Used to get the display metrics that are used for scaling the
|
||||
* bitmaps returned by {@@link getBitmap}. Can be null,
|
||||
* in which case the bitmaps are not scaled.
|
||||
*/
|
||||
public DefaultResourceProxyImpl(final Context pContext) {
|
||||
if (pContext != null) {
|
||||
mDisplayMetrics = pContext.getResources().getDisplayMetrics();
|
||||
// if (DEBUGMODE) {
|
||||
// logger.debug("mDisplayMetrics=" + mDisplayMetrics);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(final string pResId) {
|
||||
switch (pResId) {
|
||||
case mapnik:
|
||||
return "Mapnik";
|
||||
case cyclemap:
|
||||
return "Cycle Map";
|
||||
case public_transport:
|
||||
return "Public transport";
|
||||
case base:
|
||||
return "OSM base layer";
|
||||
case topo:
|
||||
return "Topographic";
|
||||
case hills:
|
||||
return "Hills";
|
||||
case cloudmade_standard:
|
||||
return "CloudMade (Standard tiles)";
|
||||
case cloudmade_small:
|
||||
return "CloudMade (small tiles)";
|
||||
case mapquest_osm:
|
||||
return "Mapquest";
|
||||
case mapquest_aerial:
|
||||
return "Mapquest Aerial";
|
||||
case bing:
|
||||
return "Bing";
|
||||
case fiets_nl:
|
||||
return "OpenFietsKaart overlay";
|
||||
case base_nl:
|
||||
return "Netherlands base overlay";
|
||||
case roads_nl:
|
||||
return "Netherlands roads overlay";
|
||||
case unknown:
|
||||
return "Unknown";
|
||||
case format_distance_meters:
|
||||
return "%s m";
|
||||
case format_distance_kilometers:
|
||||
return "%s km";
|
||||
case format_distance_miles:
|
||||
return "%s mi";
|
||||
case format_distance_nautical_miles:
|
||||
return "%s nm";
|
||||
case format_distance_feet:
|
||||
return "%s ft";
|
||||
case online_mode:
|
||||
return "Online mode";
|
||||
case offline_mode:
|
||||
return "Offline mode";
|
||||
case my_location:
|
||||
return "My location";
|
||||
case compass:
|
||||
return "Compass";
|
||||
case map_mode:
|
||||
return "Map mode";
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(final string pResId, final Object... formatArgs) {
|
||||
return String.format(getString(pResId), formatArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap(final bitmap pResId) {
|
||||
InputStream is = null;
|
||||
try {
|
||||
final String resName = pResId.name() + ".png";
|
||||
is = getClass().getResourceAsStream(resName);
|
||||
if (is == null) {
|
||||
throw new IllegalArgumentException("Resource not found: " + resName);
|
||||
}
|
||||
BitmapFactory.Options options = null;
|
||||
if (mDisplayMetrics != null) {
|
||||
options = getBitmapOptions();
|
||||
}
|
||||
return BitmapFactory.decodeStream(is, null, options);
|
||||
} catch (final OutOfMemoryError e) {
|
||||
// logger.error("OutOfMemoryError getting bitmap resource: " +
|
||||
// pResId);
|
||||
System.gc();
|
||||
// there's not much we can do here
|
||||
// - when we load a bitmap from resources we expect it to be found
|
||||
throw e;
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (final IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BitmapFactory.Options getBitmapOptions() {
|
||||
try {
|
||||
final Field density = DisplayMetrics.class.getDeclaredField("DENSITY_DEFAULT");
|
||||
final Field inDensity = BitmapFactory.Options.class.getDeclaredField("inDensity");
|
||||
final Field inTargetDensity = BitmapFactory.Options.class
|
||||
.getDeclaredField("inTargetDensity");
|
||||
final Field targetDensity = DisplayMetrics.class.getDeclaredField("densityDpi");
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
inDensity.setInt(options, density.getInt(null));
|
||||
inTargetDensity.setInt(options, targetDensity.getInt(mDisplayMetrics));
|
||||
return options;
|
||||
} catch (final IllegalAccessException ex) {
|
||||
// ignore
|
||||
} catch (final NoSuchFieldException ex) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getDrawable(final bitmap pResId) {
|
||||
return new BitmapDrawable(getBitmap(pResId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDisplayMetricsDensity() {
|
||||
return mDisplayMetrics.density;
|
||||
}
|
||||
|
||||
}
|
||||
31
src/org/oscim/overlay/GenericOverlay.java
Normal file
31
src/org/oscim/overlay/GenericOverlay.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2012 Hannes Janetzek
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.overlay;
|
||||
|
||||
import org.oscim.renderer.overlays.RenderOverlay;
|
||||
import org.oscim.view.MapView;
|
||||
|
||||
public class GenericOverlay extends Overlay {
|
||||
/**
|
||||
* @param mapView
|
||||
* ...
|
||||
* @param renderer
|
||||
* ...
|
||||
*/
|
||||
public GenericOverlay(MapView mapView, RenderOverlay renderer) {
|
||||
super();
|
||||
mLayer = renderer;
|
||||
}
|
||||
}
|
||||
278
src/org/oscim/overlay/ItemizedIconOverlay.java
Normal file
278
src/org/oscim/overlay/ItemizedIconOverlay.java
Normal file
@@ -0,0 +1,278 @@
|
||||
package org.oscim.overlay;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.oscim.core.MercatorProjection;
|
||||
import org.oscim.overlay.ResourceProxy.bitmap;
|
||||
import org.oscim.view.MapView;
|
||||
import org.oscim.view.MapViewPosition;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.FloatMath;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class ItemizedIconOverlay<Item extends OverlayItem> extends ItemizedOverlay<Item> {
|
||||
private static final String TAG = ItemizedIconOverlay.class.getSimpleName();
|
||||
|
||||
protected final List<Item> mItemList;
|
||||
protected OnItemGestureListener<Item> mOnItemGestureListener;
|
||||
private int mDrawnItemsLimit = Integer.MAX_VALUE;
|
||||
private final Point mTouchScreenPoint = new Point();
|
||||
|
||||
private final Point mItemPoint = new Point();
|
||||
|
||||
public ItemizedIconOverlay(
|
||||
final MapView mapView,
|
||||
final List<Item> pList,
|
||||
final Drawable pDefaultMarker,
|
||||
final ItemizedIconOverlay.OnItemGestureListener<Item> pOnItemGestureListener,
|
||||
final ResourceProxy pResourceProxy) {
|
||||
|
||||
super(mapView, pDefaultMarker, pResourceProxy);
|
||||
|
||||
this.mItemList = pList;
|
||||
this.mOnItemGestureListener = pOnItemGestureListener;
|
||||
populate();
|
||||
}
|
||||
|
||||
public ItemizedIconOverlay(
|
||||
final MapView mapView,
|
||||
final List<Item> pList,
|
||||
final ItemizedIconOverlay.OnItemGestureListener<Item> pOnItemGestureListener,
|
||||
final ResourceProxy pResourceProxy) {
|
||||
|
||||
this(mapView, pList, pResourceProxy.getDrawable(bitmap.marker_default),
|
||||
pOnItemGestureListener,
|
||||
pResourceProxy);
|
||||
}
|
||||
|
||||
public ItemizedIconOverlay(
|
||||
final MapView mapView,
|
||||
final Context pContext,
|
||||
final List<Item> pList,
|
||||
final ItemizedIconOverlay.OnItemGestureListener<Item> pOnItemGestureListener) {
|
||||
this(mapView, pList, new DefaultResourceProxyImpl(pContext)
|
||||
.getDrawable(bitmap.marker_default),
|
||||
pOnItemGestureListener, new DefaultResourceProxyImpl(pContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSnapToItem(final int pX, final int pY, final Point pSnapPoint,
|
||||
final MapView pMapView) {
|
||||
// TODO Implement this!
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Item createItem(final int index) {
|
||||
return mItemList.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Math.min(mItemList.size(), mDrawnItemsLimit);
|
||||
}
|
||||
|
||||
public boolean addItem(final Item item) {
|
||||
final boolean result = mItemList.add(item);
|
||||
populate();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addItem(final int location, final Item item) {
|
||||
mItemList.add(location, item);
|
||||
}
|
||||
|
||||
public boolean addItems(final List<Item> items) {
|
||||
final boolean result = mItemList.addAll(items);
|
||||
populate();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void removeAllItems() {
|
||||
removeAllItems(true);
|
||||
}
|
||||
|
||||
public void removeAllItems(final boolean withPopulate) {
|
||||
mItemList.clear();
|
||||
if (withPopulate) {
|
||||
populate();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeItem(final Item item) {
|
||||
final boolean result = mItemList.remove(item);
|
||||
populate();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Item removeItem(final int position) {
|
||||
final Item result = mItemList.remove(position);
|
||||
populate();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each of these methods performs a item sensitive check. If the item is
|
||||
* located its corresponding method is called. The result of the call is
|
||||
* returned. Helper methods are provided so that child classes may more
|
||||
* easily override behavior without resorting to overriding the
|
||||
* ItemGestureListener methods.
|
||||
*/
|
||||
@Override
|
||||
public boolean onSingleTapUp(final MotionEvent event, final MapView mapView) {
|
||||
return (activateSelectedItems(event, mapView, new ActiveItem() {
|
||||
@Override
|
||||
public boolean run(final int index) {
|
||||
final ItemizedIconOverlay<Item> that = ItemizedIconOverlay.this;
|
||||
if (that.mOnItemGestureListener == null) {
|
||||
return false;
|
||||
}
|
||||
return onSingleTapUpHelper(index, that.mItemList.get(index), mapView);
|
||||
}
|
||||
})) || super.onSingleTapUp(event, mapView);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* ...
|
||||
* @param item
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
protected boolean onSingleTapUpHelper(final int index, final Item item, final MapView mapView) {
|
||||
return this.mOnItemGestureListener.onItemSingleTapUp(index, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongPress(final MotionEvent event, final MapView mapView) {
|
||||
|
||||
Log.d(TAG, "onLongPress");
|
||||
|
||||
return (activateSelectedItems(event, mapView, new ActiveItem() {
|
||||
@Override
|
||||
public boolean run(final int index) {
|
||||
final ItemizedIconOverlay<Item> that = ItemizedIconOverlay.this;
|
||||
if (that.mOnItemGestureListener == null) {
|
||||
return false;
|
||||
}
|
||||
return onLongPressHelper(index, getItem(index));
|
||||
}
|
||||
})) || super.onLongPress(event, mapView);
|
||||
}
|
||||
|
||||
protected boolean onLongPressHelper(final int index, final Item item) {
|
||||
return this.mOnItemGestureListener.onItemLongPress(index, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a content sensitive action is performed the content item needs to be
|
||||
* identified. This method does that and then performs the assigned task on
|
||||
* that item.
|
||||
*
|
||||
* @param event
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @param task
|
||||
* ..
|
||||
* @return true if event is handled false otherwise
|
||||
*/
|
||||
private boolean activateSelectedItems(final MotionEvent event, final MapView mapView,
|
||||
final ActiveItem task) {
|
||||
|
||||
// final Projection pj = mapView.getProjection();
|
||||
final int eventX = (int) event.getX();
|
||||
final int eventY = (int) event.getY();
|
||||
|
||||
// Log.d("...", "test items " + eventX + " " + eventY);
|
||||
|
||||
/* These objects are created to avoid construct new ones every cycle. */
|
||||
// pj.fromMapPixels(eventX, eventY, mTouchScreenPoint);
|
||||
|
||||
MapViewPosition mapViewPosition = mMapView.getMapViewPosition();
|
||||
|
||||
byte z = mapViewPosition.getMapPosition().zoomLevel;
|
||||
|
||||
mapViewPosition.getScreenPointOnMap(eventX, eventY, mTouchScreenPoint);
|
||||
|
||||
int nearest = -1;
|
||||
float dist = Float.MAX_VALUE;
|
||||
|
||||
// TODO use intermediate projection and bounding box test
|
||||
|
||||
for (int i = 0; i < this.mItemList.size(); ++i) {
|
||||
final Item item = getItem(i);
|
||||
|
||||
// final Drawable marker = (item.getMarker(0) == null) ? this.mDefaultMarker : item
|
||||
// .getMarker(0);
|
||||
|
||||
// int x = (int) MercatorProjection.longitudeToPixelX(item.getPoint().getLongitude(), z);
|
||||
// int y = (int) MercatorProjection.latitudeToPixelY(item.getPoint().getLatitude(), z);
|
||||
MercatorProjection.projectPoint(item.getPoint(), z, mItemPoint);
|
||||
|
||||
// pj.toPixels(item.getPoint(), mItemPoint);
|
||||
// Log.d("...", (x - mTouchScreenPoint.x) + " " + (y - mTouchScreenPoint.y));
|
||||
|
||||
float dx = mItemPoint.x - mTouchScreenPoint.x;
|
||||
float dy = mItemPoint.y - mTouchScreenPoint.y;
|
||||
float d = FloatMath.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (d < 50) {
|
||||
// Log.d("...", "HIT! " + (x - mTouchScreenPoint.x) + " " + (y - mTouchScreenPoint.y));
|
||||
if (d < dist) {
|
||||
dist = d;
|
||||
nearest = i;
|
||||
}
|
||||
// if (hitTest(item, marker, mTouchScreenPoint.x - mItemPoint.x, mTouchScreenPoint.y
|
||||
// - mItemPoint.y)) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest >= 0 && task.run(nearest)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
||||
public int getDrawnItemsLimit() {
|
||||
return this.mDrawnItemsLimit;
|
||||
}
|
||||
|
||||
public void setDrawnItemsLimit(final int aLimit) {
|
||||
this.mDrawnItemsLimit = aLimit;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
|
||||
/**
|
||||
* When the item is touched one of these methods may be invoked depending on
|
||||
* the type of touch. Each of them returns true if the event was completely
|
||||
* handled.
|
||||
*
|
||||
* @param <T>
|
||||
* ....
|
||||
*/
|
||||
public static interface OnItemGestureListener<T> {
|
||||
public boolean onItemSingleTapUp(final int index, final T item);
|
||||
|
||||
public boolean onItemLongPress(final int index, final T item);
|
||||
}
|
||||
|
||||
public static interface ActiveItem {
|
||||
public boolean run(final int aIndex);
|
||||
}
|
||||
}
|
||||
484
src/org/oscim/overlay/ItemizedOverlay.java
Normal file
484
src/org/oscim/overlay/ItemizedOverlay.java
Normal file
@@ -0,0 +1,484 @@
|
||||
// Created by plusminus on 23:18:23 - 02.10.2008
|
||||
package org.oscim.overlay;
|
||||
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.core.MercatorProjection;
|
||||
import org.oscim.overlay.OverlayItem.HotspotPlace;
|
||||
import org.oscim.renderer.layer.SymbolLayer;
|
||||
import org.oscim.renderer.overlays.RenderOverlay;
|
||||
import org.oscim.view.MapView;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.opengl.Matrix;
|
||||
|
||||
/**
|
||||
* Draws a list of {@link OverlayItem} as markers to a map. The item with the
|
||||
* lowest index is drawn as last and therefore the 'topmost' marker. It also
|
||||
* gets checked for onTap first. This class is generic, because you then you get
|
||||
* your custom item-class passed back in onTap().
|
||||
* @author Marc Kurtz
|
||||
* @author Nicolas Gramlich
|
||||
* @author Theodore Hong
|
||||
* @author Fred Eisele
|
||||
* @author Hannes Janetzek
|
||||
* @param <Item>
|
||||
* ...
|
||||
*/
|
||||
public abstract class ItemizedOverlay<Item extends OverlayItem> extends Overlay implements
|
||||
Overlay.Snappable {
|
||||
|
||||
protected final Drawable mDefaultMarker;
|
||||
protected boolean mDrawFocusedItem = true;
|
||||
protected MapView mMapView;
|
||||
|
||||
class InternalItem {
|
||||
InternalItem next;
|
||||
|
||||
Item item;
|
||||
boolean visible;
|
||||
boolean changes;
|
||||
int x, y, px, py;
|
||||
}
|
||||
|
||||
/* package */InternalItem mItems;
|
||||
/* package */Object lock = new Object();
|
||||
// /* package */final ArrayList<Item> mInternalItemList;
|
||||
private final Rect mRect = new Rect();
|
||||
/* package */Item mFocusedItem;
|
||||
/* package */boolean mUpdate;
|
||||
|
||||
private int mSize;
|
||||
|
||||
// pre-projected points to zoomlovel 20
|
||||
private static final byte MAX_ZOOM = 20;
|
||||
|
||||
class ItemOverlay extends RenderOverlay {
|
||||
|
||||
private SymbolLayer mSymbolLayer;
|
||||
private float[] mMvp = new float[16];
|
||||
private float[] mVec = new float[4];
|
||||
|
||||
public ItemOverlay(MapView mapView) {
|
||||
super(mapView);
|
||||
mSymbolLayer = new SymbolLayer();
|
||||
}
|
||||
|
||||
// note: this is called from GL-Thread. so check your syncs!
|
||||
@Override
|
||||
public synchronized void update(MapPosition curPos, boolean positionChanged,
|
||||
boolean tilesChanged) {
|
||||
|
||||
if (!tilesChanged && !mUpdate)
|
||||
return;
|
||||
|
||||
mUpdate = false;
|
||||
|
||||
int diff = MAX_ZOOM - curPos.zoomLevel;
|
||||
int mx = (int) curPos.x;
|
||||
int my = (int) curPos.y;
|
||||
|
||||
// TODO could pass mvp as param
|
||||
mMapView.getMapViewPosition().getMVP(mMvp);
|
||||
|
||||
float[] matrix = mMvp;
|
||||
float[] vec = mVec;
|
||||
|
||||
// limit could be 1 if we update on every position change
|
||||
float limit = 1.5f;
|
||||
|
||||
// no need to project these
|
||||
int max = (1 << 11);
|
||||
|
||||
int changesInvisible = 0;
|
||||
int changedVisible = 0;
|
||||
int numVisible = 0;
|
||||
|
||||
synchronized (lock) {
|
||||
|
||||
// check changes
|
||||
for (InternalItem it = mItems; it != null; it = it.next) {
|
||||
it.x = (it.px >> diff) - mx;
|
||||
it.y = (it.py >> diff) - my;
|
||||
|
||||
if (it.x > max || it.x < -max || it.y > max || it.y < -max) {
|
||||
if (it.visible) {
|
||||
it.changes = true;
|
||||
changesInvisible++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// map points to screen
|
||||
vec[0] = it.x;
|
||||
vec[1] = it.y;
|
||||
vec[2] = 0;
|
||||
vec[3] = 1;
|
||||
Matrix.multiplyMV(vec, 0, matrix, 0, vec, 0);
|
||||
float sx = vec[0] / vec[3];
|
||||
float sy = vec[1] / vec[3];
|
||||
|
||||
// check if it is visible
|
||||
if (sx < -limit || sx > limit || sy < -limit || sy > limit) {
|
||||
// Log.d("..", "outside " + it.x + " " + it.y + " -> " + sx + " " + sy);
|
||||
if (it.visible) {
|
||||
it.changes = true;
|
||||
changesInvisible++;
|
||||
}
|
||||
} else {
|
||||
if (!it.visible) {
|
||||
it.visible = true;
|
||||
changedVisible++;
|
||||
}
|
||||
it.changes = false;
|
||||
numVisible++;
|
||||
}
|
||||
}
|
||||
|
||||
// only update when zoomlevel changed, new items are visible
|
||||
// or more than 10 of the current items became invisible
|
||||
if (((curPos.zoomLevel == mMapPosition.zoomLevel || numVisible == 0)) &&
|
||||
(changedVisible == 0 && changesInvisible < 10))
|
||||
return;
|
||||
|
||||
// keep position for current state
|
||||
// updateMapPosition();
|
||||
// TODO add copy utility function
|
||||
mMapPosition.x = curPos.x;
|
||||
mMapPosition.y = curPos.y;
|
||||
mMapPosition.zoomLevel = curPos.zoomLevel;
|
||||
mMapPosition.scale = curPos.scale;
|
||||
mMapPosition.angle = curPos.angle;
|
||||
|
||||
// items are placed relative to scale == 1
|
||||
mMapPosition.scale = 1;
|
||||
|
||||
layers.clear();
|
||||
|
||||
for (InternalItem it = mItems; it != null; it = it.next) {
|
||||
if (!it.visible)
|
||||
continue;
|
||||
|
||||
if (it.changes) {
|
||||
it.visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
Item item = it.item; //mInternalItemList.get(i);
|
||||
|
||||
int state = 0;
|
||||
if (mDrawFocusedItem && (mFocusedItem == item))
|
||||
state = OverlayItem.ITEM_STATE_FOCUSED_MASK;
|
||||
|
||||
Drawable marker = item.getDrawable();
|
||||
if (marker == null)
|
||||
marker = mDefaultMarker;
|
||||
|
||||
// if (item.getMarker(state) == null) {
|
||||
// OverlayItem.setState(mDefaultMarker, state);
|
||||
// marker = mDefaultMarker;
|
||||
// } else
|
||||
// marker = item.getMarker(state);
|
||||
|
||||
boundToHotspot(marker, item.getMarkerHotspot());
|
||||
|
||||
mSymbolLayer.addDrawable(marker, state, it.x, it.y);
|
||||
}
|
||||
|
||||
}
|
||||
// Log.d("...", "changed " + changedVisible + " " + changesInvisible);
|
||||
mSymbolLayer.prepare();
|
||||
layers.textureLayers = mSymbolLayer;
|
||||
newData = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method by which subclasses create the actual Items. This will only be
|
||||
* called from populate() we'll cache them for later use.
|
||||
* @param i
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
protected abstract Item createItem(int i);
|
||||
|
||||
/**
|
||||
* The number of items in this overlay.
|
||||
* @return ...
|
||||
*/
|
||||
public abstract int size();
|
||||
|
||||
public ItemizedOverlay(MapView mapView, final Drawable pDefaultMarker, final ResourceProxy
|
||||
pResourceProxy) {
|
||||
|
||||
super(pResourceProxy);
|
||||
|
||||
if (pDefaultMarker == null) {
|
||||
throw new IllegalArgumentException("You must pass a default marker to ItemizedOverlay.");
|
||||
}
|
||||
|
||||
this.mDefaultMarker = pDefaultMarker;
|
||||
|
||||
// mInternalItemList = new ArrayList<Item>();
|
||||
|
||||
mMapView = mapView;
|
||||
mLayer = new ItemOverlay(mapView);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to perform all processing on a new ItemizedOverlay.
|
||||
* Subclasses provide Items through the createItem(int) method. The subclass
|
||||
* should call this as soon as it has data, before anything else gets
|
||||
* called.
|
||||
*/
|
||||
protected final void populate() {
|
||||
synchronized (lock) {
|
||||
final int size = size();
|
||||
mSize = size;
|
||||
|
||||
// reuse previous items
|
||||
InternalItem pool = mItems;
|
||||
mItems = null;
|
||||
|
||||
// flip order to draw in backward cycle, so the items
|
||||
// with the least index are on the front.
|
||||
for (int a = 0; a < size; a++) {
|
||||
InternalItem it;
|
||||
if (pool != null) {
|
||||
it = pool;
|
||||
it.visible = false;
|
||||
it.changes = false;
|
||||
pool = pool.next;
|
||||
} else {
|
||||
it = new InternalItem();
|
||||
}
|
||||
it.next = mItems;
|
||||
mItems = it;
|
||||
|
||||
it.item = createItem(a);
|
||||
|
||||
// pre-project points
|
||||
GeoPoint p = it.item.mGeoPoint;
|
||||
it.px = (int) MercatorProjection.longitudeToPixelX(p.getLongitude(), MAX_ZOOM);
|
||||
it.py = (int) MercatorProjection.latitudeToPixelY(p.getLatitude(), MAX_ZOOM);
|
||||
}
|
||||
mUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Item at the given index.
|
||||
* @param position
|
||||
* the position of the item to return
|
||||
* @return the Item of the given index.
|
||||
*/
|
||||
public final Item getItem(final int position) {
|
||||
synchronized (lock) {
|
||||
InternalItem item = mItems;
|
||||
for (int i = mSize - position - 1; i > 0 && item != null; i--)
|
||||
item = item.next;
|
||||
|
||||
if (item != null)
|
||||
return item.item;
|
||||
|
||||
return null;
|
||||
}
|
||||
// return mInternalItemList.get(position);
|
||||
}
|
||||
|
||||
// private Drawable getDefaultMarker(final int state) {
|
||||
// OverlayItem.setState(mDefaultMarker, state);
|
||||
// return mDefaultMarker;
|
||||
// }
|
||||
|
||||
/**
|
||||
* See if a given hit point is within the bounds of an item's marker.
|
||||
* Override to modify the way an item is hit tested. The hit point is
|
||||
* relative to the marker's bounds. The default implementation just checks
|
||||
* to see if the hit point is within the touchable bounds of the marker.
|
||||
* @param item
|
||||
* the item to hit test
|
||||
* @param marker
|
||||
* the item's marker
|
||||
* @param hitX
|
||||
* x coordinate of point to check
|
||||
* @param hitY
|
||||
* y coordinate of point to check
|
||||
* @return true if the hit point is within the marker
|
||||
*/
|
||||
protected boolean hitTest(final Item item, final android.graphics.drawable.Drawable marker,
|
||||
final int hitX,
|
||||
final int hitY) {
|
||||
return marker.getBounds().contains(hitX, hitY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to draw the focused item. The default is to draw it,
|
||||
* but some clients may prefer to draw the focused item themselves.
|
||||
* @param drawFocusedItem
|
||||
* ...
|
||||
*/
|
||||
public void setDrawFocusedItem(final boolean drawFocusedItem) {
|
||||
mDrawFocusedItem = drawFocusedItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given Item is found in the overlay, force it to be the current
|
||||
* focus-bearer. Any registered {@@link
|
||||
* ItemizedOverlay#OnFocusChangeListener} will be notified. This does not
|
||||
* move the map, so if the Item isn't already centered, the user may get
|
||||
* confused. If the Item is not found, this is a no-op. You can also pass
|
||||
* null to remove focus.
|
||||
* @param item
|
||||
* ...
|
||||
*/
|
||||
public void setFocus(final Item item) {
|
||||
mFocusedItem = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently-focused item, or null if no item is currently
|
||||
* focused.
|
||||
*/
|
||||
public Item getFocus() {
|
||||
return mFocusedItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts a drawable's bounds so that (0,0) is a pixel in the location
|
||||
* described by the hotspot parameter. Useful for "pin"-like graphics. For
|
||||
* convenience, returns the same drawable that was passed in.
|
||||
* @param marker
|
||||
* the drawable to adjust
|
||||
* @param hotspot
|
||||
* the hotspot for the drawable
|
||||
* @return the same drawable that was passed in.
|
||||
*/
|
||||
protected synchronized Drawable boundToHotspot(final Drawable marker, HotspotPlace hotspot) {
|
||||
final int markerWidth = marker.getIntrinsicWidth();
|
||||
final int markerHeight = marker.getIntrinsicHeight();
|
||||
|
||||
mRect.set(0, 0, 0 + markerWidth, 0 + markerHeight);
|
||||
|
||||
if (hotspot == null) {
|
||||
hotspot = HotspotPlace.BOTTOM_CENTER;
|
||||
}
|
||||
|
||||
switch (hotspot) {
|
||||
default:
|
||||
case NONE:
|
||||
break;
|
||||
case CENTER:
|
||||
mRect.offset(-markerWidth / 2, -markerHeight / 2);
|
||||
break;
|
||||
case BOTTOM_CENTER:
|
||||
mRect.offset(-markerWidth / 2, -markerHeight);
|
||||
break;
|
||||
case TOP_CENTER:
|
||||
mRect.offset(-markerWidth / 2, 0);
|
||||
break;
|
||||
case RIGHT_CENTER:
|
||||
mRect.offset(-markerWidth, -markerHeight / 2);
|
||||
break;
|
||||
case LEFT_CENTER:
|
||||
mRect.offset(0, -markerHeight / 2);
|
||||
break;
|
||||
case UPPER_RIGHT_CORNER:
|
||||
mRect.offset(-markerWidth, 0);
|
||||
break;
|
||||
case LOWER_RIGHT_CORNER:
|
||||
mRect.offset(-markerWidth, -markerHeight);
|
||||
break;
|
||||
case UPPER_LEFT_CORNER:
|
||||
mRect.offset(0, 0);
|
||||
break;
|
||||
case LOWER_LEFT_CORNER:
|
||||
mRect.offset(0, -markerHeight);
|
||||
break;
|
||||
}
|
||||
marker.setBounds(mRect);
|
||||
return marker;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Draw a marker on each of our items. populate() must have been called
|
||||
// * first.<br/>
|
||||
// * <br/>
|
||||
// * The marker will be drawn twice for each Item in the Overlay--once in the
|
||||
// * shadow phase, skewed and darkened, then again in the non-shadow phase.
|
||||
// * The bottom-center of the marker will be aligned with the geographical
|
||||
// * coordinates of the Item.<br/>
|
||||
// * <br/>
|
||||
// * The order of drawing may be changed by overriding the getIndexToDraw(int)
|
||||
// * method. An item may provide an alternate marker via its
|
||||
// * OverlayItem.getMarker(int) method. If that method returns null, the
|
||||
// * default marker is used.<br/>
|
||||
// * <br/>
|
||||
// * The focused item is always drawn last, which puts it visually on top of
|
||||
// * the other items.<br/>
|
||||
// *
|
||||
// * @param canvas
|
||||
// * the Canvas upon which to draw. Note that this may already have
|
||||
// * a transformation applied, so be sure to leave it the way you
|
||||
// * found it
|
||||
// * @param mapView
|
||||
// * the MapView that requested the draw. Use
|
||||
// * MapView.getProjection() to convert between on-screen pixels
|
||||
// * and latitude/longitude pairs
|
||||
// * @param shadow
|
||||
// * if true, draw the shadow layer. If false, draw the overlay
|
||||
// * contents.
|
||||
// */
|
||||
// @Override
|
||||
// public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
|
||||
//
|
||||
// if (shadow) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final Projection pj = mapView.getProjection();
|
||||
// final int size = this.mInternalItemList.size() - 1;
|
||||
//
|
||||
// /*
|
||||
// * Draw in backward cycle, so the items with the least index are on the
|
||||
// * front.
|
||||
// */
|
||||
// for (int i = size; i >= 0; i--) {
|
||||
// final Item item = getItem(i);
|
||||
// pj.toMapPixels(item.mGeoPoint, mCurScreenCoords);
|
||||
//
|
||||
// onDrawItem(canvas, item, mCurScreenCoords);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Draws an item located at the provided screen coordinates to the canvas.
|
||||
// *
|
||||
// * @param canvas
|
||||
// * what the item is drawn upon
|
||||
// * @param item
|
||||
// * the item to be drawn
|
||||
// * @param curScreenCoords
|
||||
// * the screen coordinates of the item
|
||||
// */
|
||||
// protected void onDrawItem(final Canvas canvas, final Item item, final Point curScreenCoords) {
|
||||
// int state = 0;
|
||||
//
|
||||
// if (mDrawFocusedItem && (mFocusedItem == item))
|
||||
// state = OverlayItem.ITEM_STATE_FOCUSED_MASK;
|
||||
//
|
||||
// Drawable marker;
|
||||
//
|
||||
// if (item.getMarker(state) == null)
|
||||
// marker = getDefaultMarker(state);
|
||||
// else
|
||||
// marker = item.getMarker(state);
|
||||
//
|
||||
// boundToHotspot(marker, item.getMarkerHotspot());
|
||||
//
|
||||
// // draw it
|
||||
// Overlay.drawAt(canvas, marker, curScreenCoords.x, curScreenCoords.y, false);
|
||||
// }
|
||||
}
|
||||
33
src/org/oscim/overlay/LabelingOverlay.java
Normal file
33
src/org/oscim/overlay/LabelingOverlay.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012 Hannes Janetzek
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.overlay;
|
||||
|
||||
import org.oscim.renderer.overlays.OverlayText;
|
||||
import org.oscim.view.MapView;
|
||||
|
||||
public class LabelingOverlay extends Overlay {
|
||||
|
||||
// private OverlayText mLayer;
|
||||
|
||||
// @Override
|
||||
// public org.oscim.renderer.overlays.RenderOverlay getLayer() {
|
||||
// return mLayer;
|
||||
// }
|
||||
|
||||
public LabelingOverlay(MapView mapView) {
|
||||
super();
|
||||
mLayer = new OverlayText(mapView);
|
||||
}
|
||||
}
|
||||
36
src/org/oscim/overlay/MapViewConstants.java
Normal file
36
src/org/oscim/overlay/MapViewConstants.java
Normal file
@@ -0,0 +1,36 @@
|
||||
// Created by plusminus on 18:00:24 - 25.09.2008
|
||||
package org.oscim.overlay;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class contains constants used by the map view.
|
||||
*
|
||||
* @author Nicolas Gramlich
|
||||
*
|
||||
*/
|
||||
public interface MapViewConstants {
|
||||
// ===========================================================
|
||||
// Final Fields
|
||||
// ===========================================================
|
||||
|
||||
public static final boolean DEBUGMODE = false;
|
||||
|
||||
public static final int NOT_SET = Integer.MIN_VALUE;
|
||||
|
||||
public static final int ANIMATION_SMOOTHNESS_LOW = 4;
|
||||
public static final int ANIMATION_SMOOTHNESS_DEFAULT = 10;
|
||||
public static final int ANIMATION_SMOOTHNESS_HIGH = 20;
|
||||
|
||||
public static final int ANIMATION_DURATION_SHORT = 500;
|
||||
public static final int ANIMATION_DURATION_DEFAULT = 1000;
|
||||
public static final int ANIMATION_DURATION_LONG = 2000;
|
||||
|
||||
/** Minimum Zoom Level */
|
||||
public static final int MINIMUM_ZOOMLEVEL = 0;
|
||||
|
||||
/**
|
||||
* Maximum Zoom Level - we use Integers to store zoom levels so overflow happens at 2^32 - 1,
|
||||
* but we also have a tile size that is typically 2^8, so (32-1)-8-1 = 22
|
||||
*/
|
||||
public static final int MAXIMUM_ZOOMLEVEL = 22;
|
||||
}
|
||||
450
src/org/oscim/overlay/Overlay.java
Normal file
450
src/org/oscim/overlay/Overlay.java
Normal file
@@ -0,0 +1,450 @@
|
||||
// Created by plusminus on 20:32:01 - 27.09.2008
|
||||
package org.oscim.overlay;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.renderer.overlays.RenderOverlay;
|
||||
import org.oscim.view.MapView;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* Base class representing an overlay which may be displayed on top of a
|
||||
* {@link MapView}. To add an overlay, subclass this class, create an instance,
|
||||
* and add it to the list obtained from getOverlays() of {@link MapView}. This
|
||||
* class implements a form of Gesture Handling similar to
|
||||
* {@link android.view.GestureDetector.SimpleOnGestureListener} and
|
||||
* GestureDetector.OnGestureListener. The difference is there is an additional
|
||||
* argument for the item.
|
||||
*
|
||||
* @author Nicolas Gramlich
|
||||
*/
|
||||
public abstract class Overlay implements OverlayConstants {
|
||||
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
|
||||
private static AtomicInteger sOrdinal = new AtomicInteger();
|
||||
|
||||
// From Google Maps API
|
||||
protected static final float SHADOW_X_SKEW = -0.8999999761581421f;
|
||||
protected static final float SHADOW_Y_SCALE = 0.5f;
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
|
||||
protected final ResourceProxy mResourceProxy;
|
||||
protected final float mScale;
|
||||
|
||||
// private static final Rect mRect = new Rect();
|
||||
private boolean mEnabled = true;
|
||||
|
||||
protected RenderOverlay mLayer;
|
||||
|
||||
public RenderOverlay getLayer() {
|
||||
return mLayer;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
|
||||
public Overlay() {
|
||||
mResourceProxy = null;
|
||||
mScale = 1;
|
||||
// mResourceProxy = new DefaultResourceProxyImpl(ctx);
|
||||
// mScale = ctx.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public Overlay(final Context ctx) {
|
||||
mResourceProxy = new DefaultResourceProxyImpl(ctx);
|
||||
mScale = ctx.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public Overlay(final ResourceProxy pResourceProxy) {
|
||||
mResourceProxy = pResourceProxy;
|
||||
mScale = mResourceProxy.getDisplayMetricsDensity();
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
|
||||
/**
|
||||
* Sets whether the Overlay is marked to be enabled. This setting does
|
||||
* nothing by default, but should be checked before calling draw().
|
||||
*
|
||||
* @param pEnabled
|
||||
* ...
|
||||
*/
|
||||
public void setEnabled(final boolean pEnabled) {
|
||||
this.mEnabled = pEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the Overlay is marked to be enabled. This should be checked
|
||||
* before calling draw().
|
||||
*
|
||||
* @return true if the Overlay is marked enabled, false otherwise
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return this.mEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the menu-chain will pass through several independent Overlays, menu
|
||||
* IDs cannot be fixed at compile time. Overlays should use this method to
|
||||
* obtain and store a menu id for each menu item at construction time. This
|
||||
* will ensure that two overlays don't use the same id.
|
||||
*
|
||||
* @return an integer suitable to be used as a menu identifier
|
||||
*/
|
||||
protected final static int getSafeMenuId() {
|
||||
return sOrdinal.getAndIncrement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to <see cref="getSafeMenuId" />, except this reserves a sequence
|
||||
* of IDs of length <param name="count" />. The returned number is the
|
||||
* starting index of that sequential list.
|
||||
*
|
||||
* @param count
|
||||
* ....
|
||||
* @return an integer suitable to be used as a menu identifier
|
||||
*/
|
||||
protected final static int getSafeMenuIdSequence(final int count) {
|
||||
return sOrdinal.getAndAdd(count);
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Methods for SuperClass/Interfaces
|
||||
// ===========================================================
|
||||
|
||||
// /**
|
||||
// * Draw the overlay over the map. This will be called on all active overlays
|
||||
// * with shadow=true, to lay down the shadow layer, and then again on all
|
||||
// * overlays with shadow=false. Callers should check isEnabled() before
|
||||
// * calling draw(). By default, draws nothing.
|
||||
// *
|
||||
// * @param c
|
||||
// * ...
|
||||
// * @param osmv
|
||||
// * ...
|
||||
// * @param shadow
|
||||
// * ...
|
||||
// */
|
||||
// protected abstract void draw(final Canvas c, final MapView osmv, final boolean shadow);
|
||||
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
|
||||
/**
|
||||
* Override to perform clean up of resources before shutdown. By default
|
||||
* does nothing.
|
||||
*
|
||||
* @param mapView
|
||||
* ...
|
||||
*/
|
||||
public void onDetach(final MapView mapView) {
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param keyCode
|
||||
* ...
|
||||
* @param event
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onKeyDown(final int keyCode, final KeyEvent event, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param keyCode
|
||||
* ...
|
||||
* @param event
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onKeyUp(final int keyCode, final KeyEvent event, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>You can prevent all(!) other Touch-related events from happening!</b><br />
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param e
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onTouchEvent(final MotionEvent e, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param e
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onTrackballEvent(final MotionEvent e, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** GestureDetector.OnDoubleTapListener **/
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param e
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onDoubleTap(final MotionEvent e, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param e
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onDoubleTapEvent(final MotionEvent e, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param e
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onSingleTapConfirmed(final MotionEvent e, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** OnGestureListener **/
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param e
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onDown(final MotionEvent e, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param pEvent1
|
||||
* ...
|
||||
* @param pEvent2
|
||||
* ...
|
||||
* @param pVelocityX
|
||||
* ...
|
||||
* @param pVelocityY
|
||||
* ...
|
||||
* @param pMapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onFling(final MotionEvent pEvent1, final MotionEvent pEvent2,
|
||||
final float pVelocityX, final float pVelocityY, final MapView pMapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param e
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onLongPress(final MotionEvent e, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param pEvent1
|
||||
* ...
|
||||
* @param pEvent2
|
||||
* ...
|
||||
* @param pDistanceX
|
||||
* ...
|
||||
* @param pDistanceY
|
||||
* ...
|
||||
* @param pMapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onScroll(final MotionEvent pEvent1, final MotionEvent pEvent2,
|
||||
final float pDistanceX, final float pDistanceY, final MapView pMapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pEvent
|
||||
* ...
|
||||
* @param pMapView
|
||||
* ...
|
||||
*/
|
||||
public void onShowPress(final MotionEvent pEvent, final MapView pMapView) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default does nothing (<code>return false</code>). If you handled the
|
||||
* Event, return <code>true</code>, otherwise return <code>false</code>. If
|
||||
* you returned <code>true</code> none of the following Overlays or the
|
||||
* underlying {@link MapView} has the chance to handle this event.
|
||||
*
|
||||
* @param e
|
||||
* ...
|
||||
* @param mapView
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public boolean onSingleTapUp(final MotionEvent e, final MapView mapView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mapPosition
|
||||
* current MapPosition
|
||||
*/
|
||||
public void onUpdate(MapPosition mapPosition) {
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Convenience method to draw a Drawable at an offset. x and y are pixel
|
||||
// * coordinates. You can find appropriate coordinates from latitude/longitude
|
||||
// * using the MapView.getProjection() method on the MapView passed to you in
|
||||
// * draw(Canvas, MapView, boolean).
|
||||
// *
|
||||
// * @param canvas
|
||||
// * ...
|
||||
// * @param drawable
|
||||
// * ...
|
||||
// * @param x
|
||||
// * ...
|
||||
// * @param y
|
||||
// * ...
|
||||
// * @param shadow
|
||||
// * If true, draw only the drawable's shadow. Otherwise, draw the
|
||||
// * drawable itself.
|
||||
// */
|
||||
// protected synchronized static void drawAt(final android.graphics.Canvas canvas,
|
||||
// final android.graphics.drawable.Drawable drawable, final int x, final int y,
|
||||
// final boolean shadow) {
|
||||
// drawable.copyBounds(mRect);
|
||||
// drawable.setBounds(mRect.left + x, mRect.top + y, mRect.right + x, mRect.bottom + y);
|
||||
// drawable.draw(canvas);
|
||||
// drawable.setBounds(mRect);
|
||||
// }
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
|
||||
/**
|
||||
* Interface definition for overlays that contain items that can be snapped
|
||||
* to (for example, when the user invokes a zoom, this could be called
|
||||
* allowing the user to snap the zoom to an interesting point.)
|
||||
*/
|
||||
public interface Snappable {
|
||||
|
||||
/**
|
||||
* Checks to see if the given x and y are close enough to an item
|
||||
* resulting in snapping the current action (e.g. zoom) to the item.
|
||||
*
|
||||
* @param x
|
||||
* The x in screen coordinates.
|
||||
* @param y
|
||||
* The y in screen coordinates.
|
||||
* @param snapPoint
|
||||
* To be filled with the the interesting point (in screen
|
||||
* coordinates) that is closest to the given x and y. Can be
|
||||
* untouched if not snapping.
|
||||
* @param mapView
|
||||
* The {@link MapView} that is requesting the snap. Use
|
||||
* MapView.getProjection() to convert between on-screen
|
||||
* pixels and latitude/longitude pairs.
|
||||
* @return Whether or not to snap to the interesting point.
|
||||
*/
|
||||
boolean onSnapToItem(int x, int y, Point snapPoint, MapView mapView);
|
||||
}
|
||||
|
||||
}
|
||||
16
src/org/oscim/overlay/OverlayConstants.java
Normal file
16
src/org/oscim/overlay/OverlayConstants.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package org.oscim.overlay;
|
||||
|
||||
/**
|
||||
* This class contains constants used by the overlays.
|
||||
*/
|
||||
public interface OverlayConstants {
|
||||
// ===========================================================
|
||||
// Final Fields
|
||||
// ===========================================================
|
||||
|
||||
public static final boolean DEBUGMODE = false;
|
||||
|
||||
public static final int NOT_SET = Integer.MIN_VALUE;
|
||||
|
||||
public static final int DEFAULT_ZOOMLEVEL_MINIMAP_DIFFERENCE = 3;
|
||||
}
|
||||
157
src/org/oscim/overlay/OverlayItem.java
Normal file
157
src/org/oscim/overlay/OverlayItem.java
Normal file
@@ -0,0 +1,157 @@
|
||||
// Created by plusminus on 00:02:58 - 03.10.2008
|
||||
package org.oscim.overlay;
|
||||
|
||||
import org.oscim.core.GeoPoint;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
/** Immutable class describing a GeoPoint with a Title and a Description.
|
||||
* @author Nicolas Gramlich
|
||||
* @author Theodore Hong
|
||||
* @author Fred Eisele */
|
||||
public class OverlayItem {
|
||||
|
||||
// ===========================================================
|
||||
// Constants
|
||||
// ===========================================================
|
||||
public static final int ITEM_STATE_FOCUSED_MASK = 4;
|
||||
public static final int ITEM_STATE_PRESSED_MASK = 1;
|
||||
public static final int ITEM_STATE_SELECTED_MASK = 2;
|
||||
|
||||
protected static final Point DEFAULT_MARKER_SIZE = new Point(26, 94);
|
||||
|
||||
/** Indicates a hotspot for an area. This is where the origin (0,0) of a
|
||||
* point will be located relative to the area. In otherwords this acts as an
|
||||
* offset. NONE indicates that no adjustment should be made. */
|
||||
public enum HotspotPlace {
|
||||
NONE, CENTER, BOTTOM_CENTER, TOP_CENTER, RIGHT_CENTER, LEFT_CENTER, UPPER_RIGHT_CORNER, LOWER_RIGHT_CORNER, UPPER_LEFT_CORNER, LOWER_LEFT_CORNER
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Fields
|
||||
// ===========================================================
|
||||
|
||||
public final String mUid;
|
||||
public final String mTitle;
|
||||
public final String mDescription;
|
||||
public final GeoPoint mGeoPoint;
|
||||
protected Drawable mMarker;
|
||||
protected HotspotPlace mHotspotPlace;
|
||||
|
||||
// ===========================================================
|
||||
// Constructors
|
||||
// ===========================================================
|
||||
|
||||
/** @param aTitle
|
||||
* this should be <b>singleLine</b> (no <code>'\n'</code> )
|
||||
* @param aDescription
|
||||
* a <b>multiLine</b> description ( <code>'\n'</code> possible)
|
||||
* @param aGeoPoint
|
||||
* ... */
|
||||
public OverlayItem(final String aTitle, final String aDescription, final GeoPoint aGeoPoint) {
|
||||
this(null, aTitle, aDescription, aGeoPoint);
|
||||
}
|
||||
|
||||
public OverlayItem(final String aUid, final String aTitle, final String aDescription,
|
||||
final GeoPoint aGeoPoint) {
|
||||
this.mTitle = aTitle;
|
||||
this.mDescription = aDescription;
|
||||
this.mGeoPoint = aGeoPoint;
|
||||
this.mUid = aUid;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Getter & Setter
|
||||
// ===========================================================
|
||||
public String getUid() {
|
||||
return mUid;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public String getSnippet() {
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
public GeoPoint getPoint() {
|
||||
return mGeoPoint;
|
||||
}
|
||||
|
||||
/* (copied from Google API docs) Returns the marker that should be used when
|
||||
* drawing this item on the map. A null value means that the default marker
|
||||
* should be drawn. Different markers can be returned for different states.
|
||||
* The different markers can have different bounds. The default behavior is
|
||||
* to call {@link setState(android.graphics.drawable.Drawable, int)} on the
|
||||
* overlay item's marker, if it exists, and then return it.
|
||||
* @param stateBitset The current state.
|
||||
* @return The marker for the current state, or null if the default marker
|
||||
* for the overlay should be used. */
|
||||
public Drawable getMarker(final int stateBitset) {
|
||||
// marker not specified
|
||||
if (mMarker == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// set marker state appropriately
|
||||
setState(mMarker, stateBitset);
|
||||
return mMarker;
|
||||
}
|
||||
|
||||
public void setMarker(final Drawable marker) {
|
||||
this.mMarker = marker;
|
||||
}
|
||||
|
||||
public void setMarkerHotspot(final HotspotPlace place) {
|
||||
this.mHotspotPlace = (place == null) ? HotspotPlace.BOTTOM_CENTER : place;
|
||||
}
|
||||
|
||||
public HotspotPlace getMarkerHotspot() {
|
||||
return this.mHotspotPlace;
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Methods from SuperClass/Interfaces
|
||||
// ===========================================================
|
||||
|
||||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
/* (copied from the Google API docs) Sets the state of a drawable to match a
|
||||
* given state bitset. This is done by converting the state bitset bits
|
||||
* into
|
||||
* a state set of R.attr.state_pressed, R.attr.state_selected and
|
||||
* R.attr.state_focused attributes, and then calling {@link
|
||||
* Drawable.setState(int[])}. */
|
||||
public static void setState(final Drawable drawable, final int stateBitset) {
|
||||
final int[] states = new int[3];
|
||||
int index = 0;
|
||||
if ((stateBitset & ITEM_STATE_PRESSED_MASK) > 0)
|
||||
states[index++] = android.R.attr.state_pressed;
|
||||
if ((stateBitset & ITEM_STATE_SELECTED_MASK) > 0)
|
||||
states[index++] = android.R.attr.state_selected;
|
||||
if ((stateBitset & ITEM_STATE_FOCUSED_MASK) > 0)
|
||||
states[index++] = android.R.attr.state_focused;
|
||||
|
||||
drawable.setState(states);
|
||||
}
|
||||
|
||||
public Drawable getDrawable() {
|
||||
return this.mMarker;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return this.mMarker.getIntrinsicWidth();
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return this.mMarker.getIntrinsicHeight();
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// Inner and Anonymous Classes
|
||||
// ===========================================================
|
||||
|
||||
}
|
||||
390
src/org/oscim/overlay/OverlayManager.java
Normal file
390
src/org/oscim/overlay/OverlayManager.java
Normal file
@@ -0,0 +1,390 @@
|
||||
package org.oscim.overlay;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.overlay.Overlay.Snappable;
|
||||
import org.oscim.renderer.overlays.RenderOverlay;
|
||||
import org.oscim.view.MapView;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class OverlayManager extends AbstractList<Overlay> {
|
||||
|
||||
// private TilesOverlay mTilesOverlay;
|
||||
|
||||
/* package */final CopyOnWriteArrayList<Overlay> mOverlayList;
|
||||
|
||||
public OverlayManager() {
|
||||
// final TilesOverlay tilesOverlay) {
|
||||
// setTilesOverlay(tilesOverlay);
|
||||
mOverlayList = new CopyOnWriteArrayList<Overlay>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Overlay get(final int pIndex) {
|
||||
return mOverlayList.get(pIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mOverlayList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(final int pIndex, final Overlay pElement) {
|
||||
mOverlayList.add(pIndex, pElement);
|
||||
mUpdateLayers = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Overlay remove(final int pIndex) {
|
||||
mUpdateLayers = true;
|
||||
return mOverlayList.remove(pIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Overlay set(final int pIndex, final Overlay pElement) {
|
||||
mUpdateLayers = true;
|
||||
return mOverlayList.set(pIndex, pElement);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Gets the optional TilesOverlay class.
|
||||
// *
|
||||
// * @return the tilesOverlay
|
||||
// */
|
||||
// public TilesOverlay getTilesOverlay() {
|
||||
// return mTilesOverlay;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Sets the optional TilesOverlay class. If set, this overlay will be
|
||||
// drawn before all other
|
||||
// * overlays and will not be included in the editable list of overlays and
|
||||
// can't be cleared
|
||||
// * except by a subsequent call to setTilesOverlay().
|
||||
// *
|
||||
// * @param tilesOverlay
|
||||
// * the tilesOverlay to set
|
||||
// */
|
||||
// public void setTilesOverlay(final TilesOverlay tilesOverlay) {
|
||||
// mTilesOverlay = tilesOverlay;
|
||||
// }
|
||||
|
||||
public Iterable<Overlay> overlaysReversed() {
|
||||
return new Iterable<Overlay>() {
|
||||
@Override
|
||||
public Iterator<Overlay> iterator() {
|
||||
final ListIterator<Overlay> i = mOverlayList.listIterator(mOverlayList.size());
|
||||
|
||||
return new Iterator<Overlay>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i.hasPrevious();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Overlay next() {
|
||||
return i.previous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
i.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean mUpdateLayers;
|
||||
private List<RenderOverlay> mDrawLayers = new ArrayList<RenderOverlay>();
|
||||
|
||||
public List<RenderOverlay> getRenderLayers() {
|
||||
if (mUpdateLayers) {
|
||||
synchronized (this) {
|
||||
|
||||
mUpdateLayers = false;
|
||||
mDrawLayers.clear();
|
||||
|
||||
for (Overlay o : mOverlayList) {
|
||||
RenderOverlay l = o.getLayer();
|
||||
if (l != null)
|
||||
mDrawLayers.add(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mDrawLayers;
|
||||
}
|
||||
|
||||
// public void onDraw(final Canvas c, final MapView pMapView) {
|
||||
// // if ((mTilesOverlay != null) && mTilesOverlay.isEnabled()) {
|
||||
// // mTilesOverlay.draw(c, pMapView, true);
|
||||
// // }
|
||||
// //
|
||||
// // if ((mTilesOverlay != null) && mTilesOverlay.isEnabled()) {
|
||||
// // mTilesOverlay.draw(c, pMapView, false);
|
||||
// // }
|
||||
//
|
||||
// for (final Overlay overlay : mOverlayList) {
|
||||
// if (overlay.isEnabled()) {
|
||||
// overlay.draw(c, pMapView, true);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (final Overlay overlay : mOverlayList) {
|
||||
// if (overlay.isEnabled()) {
|
||||
// overlay.draw(c, pMapView, false);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
public void onDetach(final MapView pMapView) {
|
||||
// if (mTilesOverlay != null) {
|
||||
// mTilesOverlay.onDetach(pMapView);
|
||||
// }
|
||||
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
overlay.onDetach(pMapView);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onKeyDown(final int keyCode, final KeyEvent event, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onKeyDown(keyCode, event, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onKeyUp(final int keyCode, final KeyEvent event, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onKeyUp(keyCode, event, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(final MotionEvent event, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onTouchEvent(event, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onTrackballEvent(final MotionEvent event, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onTrackballEvent(event, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onSnapToItem(final int x, final int y, final Point snapPoint,
|
||||
final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay instanceof Snappable) {
|
||||
if (((Snappable) overlay).onSnapToItem(x, y, snapPoint, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* GestureDetector.OnDoubleTapListener */
|
||||
|
||||
public boolean onDoubleTap(final MotionEvent e, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onDoubleTap(e, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onDoubleTapEvent(final MotionEvent e, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onDoubleTapEvent(e, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onSingleTapConfirmed(final MotionEvent e, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onSingleTapConfirmed(e, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* OnGestureListener */
|
||||
|
||||
public boolean onDown(final MotionEvent pEvent, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onDown(pEvent, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onFling(final MotionEvent pEvent1, final MotionEvent pEvent2,
|
||||
final float pVelocityX, final float pVelocityY, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onFling(pEvent1, pEvent2, pVelocityX, pVelocityY, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onLongPress(final MotionEvent pEvent, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onLongPress(pEvent, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onScroll(final MotionEvent pEvent1, final MotionEvent pEvent2,
|
||||
final float pDistanceX, final float pDistanceY, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onScroll(pEvent1, pEvent2, pDistanceX, pDistanceY, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onShowPress(final MotionEvent pEvent, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
overlay.onShowPress(pEvent, pMapView);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onSingleTapUp(final MotionEvent pEvent, final MapView pMapView) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
if (overlay.onSingleTapUp(pEvent, pMapView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onUpdate(MapPosition mapPosition) {
|
||||
for (final Overlay overlay : this.overlaysReversed()) {
|
||||
overlay.onUpdate(mapPosition);
|
||||
}
|
||||
}
|
||||
|
||||
// ** Options Menu **//
|
||||
|
||||
// public void setOptionsMenusEnabled(final boolean pEnabled) {
|
||||
// for (final Overlay overlay : mOverlayList) {
|
||||
// if ((overlay instanceof IOverlayMenuProvider)
|
||||
// && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) {
|
||||
// ((IOverlayMenuProvider) overlay).setOptionsMenuEnabled(pEnabled);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public boolean onCreateOptionsMenu(final Menu pMenu, final int
|
||||
// menuIdOffset,
|
||||
// final MapView mapView) {
|
||||
// boolean result = true;
|
||||
// for (final Overlay overlay : this.overlaysReversed()) {
|
||||
// if ((overlay instanceof IOverlayMenuProvider)
|
||||
// && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) {
|
||||
// result &= ((IOverlayMenuProvider) overlay).onCreateOptionsMenu(pMenu,
|
||||
// menuIdOffset,
|
||||
// mapView);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ((mTilesOverlay != null) && (mTilesOverlay instanceof
|
||||
// IOverlayMenuProvider)
|
||||
// && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled()) {
|
||||
// result &= mTilesOverlay.onCreateOptionsMenu(pMenu, menuIdOffset,
|
||||
// mapView);
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// public boolean onPrepareOptionsMenu(final Menu pMenu, final int
|
||||
// menuIdOffset,
|
||||
// final MapView mapView) {
|
||||
// for (final Overlay overlay : this.overlaysReversed()) {
|
||||
// if ((overlay instanceof IOverlayMenuProvider)
|
||||
// && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) {
|
||||
// ((IOverlayMenuProvider) overlay).onPrepareOptionsMenu(pMenu,
|
||||
// menuIdOffset, mapView);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ((mTilesOverlay != null) && (mTilesOverlay instanceof
|
||||
// IOverlayMenuProvider)
|
||||
// && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled()) {
|
||||
// mTilesOverlay.onPrepareOptionsMenu(pMenu, menuIdOffset, mapView);
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// public boolean onOptionsItemSelected(final MenuItem item, final int
|
||||
// menuIdOffset,
|
||||
// final MapView mapView) {
|
||||
// for (final Overlay overlay : this.overlaysReversed()) {
|
||||
// if ((overlay instanceof IOverlayMenuProvider)
|
||||
// && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()
|
||||
// && ((IOverlayMenuProvider) overlay).onOptionsItemSelected(item,
|
||||
// menuIdOffset,
|
||||
// mapView)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ((mTilesOverlay != null)
|
||||
// && (mTilesOverlay instanceof IOverlayMenuProvider)
|
||||
// && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled()
|
||||
// && ((IOverlayMenuProvider) mTilesOverlay).onOptionsItemSelected(item,
|
||||
// menuIdOffset,
|
||||
// mapView)) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
}
|
||||
280
src/org/oscim/overlay/PathOverlay.java
Normal file
280
src/org/oscim/overlay/PathOverlay.java
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright 2012, osmdroid: Viesturs Zarins, Martin Pearman
|
||||
* Copyright 2012, Hannes Janetzek
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oscim.overlay;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.oscim.core.GeoPoint;
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.core.MercatorProjection;
|
||||
import org.oscim.renderer.layer.Layer;
|
||||
import org.oscim.renderer.layer.LineLayer;
|
||||
import org.oscim.renderer.overlays.RenderOverlay;
|
||||
import org.oscim.theme.renderinstruction.Line;
|
||||
import org.oscim.view.MapView;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Cap;
|
||||
|
||||
/** This class draws a path line in given color. */
|
||||
public class PathOverlay extends Overlay {
|
||||
|
||||
/** Stores points, converted to the map projection. */
|
||||
/* package */final ArrayList<GeoPoint> mPoints;
|
||||
/* package */boolean mUpdatePoints;
|
||||
|
||||
/** Paint settings. */
|
||||
protected Paint mPaint = new Paint();
|
||||
|
||||
class RenderPath extends RenderOverlay {
|
||||
|
||||
private static final byte MAX_ZOOM = 20;
|
||||
|
||||
// pre-projected points to zoomlovel 20
|
||||
private int[] mPreprojected;
|
||||
|
||||
// projected points
|
||||
private float[] mPPoints;
|
||||
private short[] mIndex;
|
||||
private int mSize;
|
||||
|
||||
private Line mLine;
|
||||
|
||||
// limit coords
|
||||
private final int max = 2048;
|
||||
|
||||
public RenderPath(MapView mapView) {
|
||||
super(mapView);
|
||||
mLine = new Line(Color.BLUE, 3.0f, Cap.BUTT);
|
||||
mIndex = new short[1];
|
||||
mPPoints = new float[1];
|
||||
}
|
||||
|
||||
// note: this is called from GL-Thread. so check your syncs!
|
||||
// TODO use an Overlay-Thread to build up layers (like for Labeling)
|
||||
@Override
|
||||
public synchronized void update(MapPosition curPos, boolean positionChanged,
|
||||
boolean tilesChanged) {
|
||||
|
||||
if (!tilesChanged && !mUpdatePoints)
|
||||
return;
|
||||
|
||||
float[] projected = mPPoints;
|
||||
|
||||
if (mUpdatePoints) {
|
||||
// pre-project point on zoomlelvel 20
|
||||
synchronized (mPoints) {
|
||||
mUpdatePoints = false;
|
||||
|
||||
ArrayList<GeoPoint> geopoints = mPoints;
|
||||
int size = geopoints.size();
|
||||
int[] points = mPreprojected;
|
||||
mSize = size * 2;
|
||||
|
||||
if (mSize > projected.length) {
|
||||
points = mPreprojected = new int[mSize];
|
||||
projected = mPPoints = new float[mSize];
|
||||
}
|
||||
|
||||
for (int i = 0, j = 0; i < size; i++, j += 2) {
|
||||
GeoPoint p = geopoints.get(i);
|
||||
points[j + 0] = (int) MercatorProjection.longitudeToPixelX(
|
||||
p.getLongitude(), MAX_ZOOM);
|
||||
points[j + 1] = (int) MercatorProjection.latitudeToPixelY(
|
||||
p.getLatitude(), MAX_ZOOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int size = mSize;
|
||||
|
||||
// keep position to render relative to current state
|
||||
updateMapPosition();
|
||||
|
||||
// items are placed relative to scale == 1
|
||||
mMapPosition.scale = 1;
|
||||
|
||||
// layers.clear();
|
||||
LineLayer ll = (LineLayer) layers.getLayer(1, Layer.LINE);
|
||||
// reset verticesCnt to reuse layer
|
||||
ll.verticesCnt = 0;
|
||||
ll.line = mLine;
|
||||
ll.width = 2.5f;
|
||||
|
||||
int x, y, px = 0, py = 0;
|
||||
int i = 0;
|
||||
|
||||
int diff = MAX_ZOOM - mMapPosition.zoomLevel;
|
||||
int mx = (int) mMapPosition.x;
|
||||
int my = (int) mMapPosition.y;
|
||||
|
||||
for (int j = 0; j < size; j += 2) {
|
||||
// TODO translate mapPosition and do this after clipping
|
||||
x = (mPreprojected[j + 0] >> diff) - mx;
|
||||
y = (mPreprojected[j + 1] >> diff) - my;
|
||||
|
||||
// TODO use line clipping, this doesnt work with 'GreatCircle'
|
||||
// TODO clip to view bounding box
|
||||
if (x > max || x < -max || y > max || y < -max) {
|
||||
if (i > 2) {
|
||||
mIndex[0] = (short) i;
|
||||
ll.addLine(projected, mIndex, false);
|
||||
}
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip too near points
|
||||
int dx = x - px;
|
||||
int dy = y - py;
|
||||
if ((i == 0) || dx > 2 || dx < -2 || dy > 2 || dy < -2) {
|
||||
projected[i + 0] = px = x;
|
||||
projected[i + 1] = py = y;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
mIndex[0] = (short) i;
|
||||
ll.addLine(projected, mIndex, false);
|
||||
|
||||
newData = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public PathOverlay(MapView mapView, final int color, final Context ctx) {
|
||||
super(ctx);
|
||||
this.mPaint.setColor(color);
|
||||
this.mPaint.setStrokeWidth(2.0f);
|
||||
this.mPaint.setStyle(Paint.Style.STROKE);
|
||||
|
||||
this.mPoints = new ArrayList<GeoPoint>();
|
||||
|
||||
mLayer = new RenderPath(mapView);
|
||||
}
|
||||
|
||||
public void setColor(final int color) {
|
||||
this.mPaint.setColor(color);
|
||||
}
|
||||
|
||||
public void setAlpha(final int a) {
|
||||
this.mPaint.setAlpha(a);
|
||||
}
|
||||
|
||||
public Paint getPaint() {
|
||||
return mPaint;
|
||||
}
|
||||
|
||||
public void setPaint(final Paint pPaint) {
|
||||
if (pPaint == null) {
|
||||
throw new IllegalArgumentException("pPaint argument cannot be null");
|
||||
}
|
||||
mPaint = pPaint;
|
||||
}
|
||||
|
||||
/** Draw a great circle. Calculate a point for every 100km along the path.
|
||||
* @param startPoint
|
||||
* start point of the great circle
|
||||
* @param endPoint
|
||||
* end point of the great circle */
|
||||
public void addGreatCircle(final GeoPoint startPoint, final GeoPoint endPoint) {
|
||||
synchronized (mPoints) {
|
||||
|
||||
// get the great circle path length in meters
|
||||
final int greatCircleLength = startPoint.distanceTo(endPoint);
|
||||
|
||||
// add one point for every 100kms of the great circle path
|
||||
final int numberOfPoints = greatCircleLength / 100000;
|
||||
|
||||
addGreatCircle(startPoint, endPoint, numberOfPoints);
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw a great circle.
|
||||
* @param startPoint
|
||||
* start point of the great circle
|
||||
* @param endPoint
|
||||
* end point of the great circle
|
||||
* @param numberOfPoints
|
||||
* number of points to calculate along the path */
|
||||
public void addGreatCircle(final GeoPoint startPoint, final GeoPoint endPoint,
|
||||
final int numberOfPoints) {
|
||||
// adapted from page
|
||||
// http://compastic.blogspot.co.uk/2011/07/how-to-draw-great-circle-on-map-in.html
|
||||
// which was adapted from page http://maps.forum.nu/gm_flight_path.html
|
||||
|
||||
// convert to radians
|
||||
final double lat1 = startPoint.getLatitude() * Math.PI / 180;
|
||||
final double lon1 = startPoint.getLongitude() * Math.PI / 180;
|
||||
final double lat2 = endPoint.getLatitude() * Math.PI / 180;
|
||||
final double lon2 = endPoint.getLongitude() * Math.PI / 180;
|
||||
|
||||
final double d = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin((lat1 - lat2) / 2), 2)
|
||||
+ Math.cos(lat1) * Math.cos(lat2)
|
||||
* Math.pow(Math.sin((lon1 - lon2) / 2), 2)));
|
||||
double bearing = Math.atan2(
|
||||
Math.sin(lon1 - lon2) * Math.cos(lat2),
|
||||
Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2)
|
||||
* Math.cos(lon1 - lon2))
|
||||
/ -(Math.PI / 180);
|
||||
bearing = bearing < 0 ? 360 + bearing : bearing;
|
||||
|
||||
for (int i = 0, j = numberOfPoints + 1; i < j; i++) {
|
||||
final double f = 1.0 / numberOfPoints * i;
|
||||
final double A = Math.sin((1 - f) * d) / Math.sin(d);
|
||||
final double B = Math.sin(f * d) / Math.sin(d);
|
||||
final double x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2)
|
||||
* Math.cos(lon2);
|
||||
final double y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2)
|
||||
* Math.sin(lon2);
|
||||
final double z = A * Math.sin(lat1) + B * Math.sin(lat2);
|
||||
|
||||
final double latN = Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
|
||||
final double lonN = Math.atan2(y, x);
|
||||
addPoint((int) (latN / (Math.PI / 180) * 1E6), (int) (lonN / (Math.PI / 180) * 1E6));
|
||||
}
|
||||
}
|
||||
|
||||
public void clearPath() {
|
||||
synchronized (mPoints) {
|
||||
mPoints.clear();
|
||||
mUpdatePoints = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void addPoint(final GeoPoint pt) {
|
||||
synchronized (mPoints) {
|
||||
this.mPoints.add(pt);
|
||||
mUpdatePoints = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void addPoint(final int latitudeE6, final int longitudeE6) {
|
||||
synchronized (mPoints) {
|
||||
this.mPoints.add(new GeoPoint(latitudeE6, longitudeE6));
|
||||
mUpdatePoints = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int getNumberOfPoints() {
|
||||
return this.mPoints.size();
|
||||
}
|
||||
}
|
||||
67
src/org/oscim/overlay/ResourceProxy.java
Normal file
67
src/org/oscim/overlay/ResourceProxy.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package org.oscim.overlay;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
public interface ResourceProxy {
|
||||
|
||||
public static enum string {
|
||||
|
||||
// tile sources
|
||||
mapnik, cyclemap, public_transport, base, topo, hills, cloudmade_small, cloudmade_standard, mapquest_osm, mapquest_aerial, bing,
|
||||
|
||||
// overlays
|
||||
fiets_nl, base_nl, roads_nl,
|
||||
|
||||
// other stuff
|
||||
unknown, format_distance_meters, format_distance_kilometers, format_distance_miles, format_distance_nautical_miles, format_distance_feet, online_mode, offline_mode, my_location, compass, map_mode,
|
||||
|
||||
}
|
||||
|
||||
public static enum bitmap {
|
||||
|
||||
/**
|
||||
* For testing - the image doesn't exist.
|
||||
*/
|
||||
unknown,
|
||||
|
||||
center, direction_arrow, marker_default, marker_default_focused_base, navto_small, next, previous, person,
|
||||
|
||||
/**
|
||||
* Menu icons
|
||||
*/
|
||||
ic_menu_offline, ic_menu_mylocation, ic_menu_compass, ic_menu_mapmode
|
||||
}
|
||||
|
||||
String getString(string pResId);
|
||||
|
||||
/**
|
||||
* Use a string resource as a format definition, and format using the
|
||||
* supplied format arguments.
|
||||
*
|
||||
* @param pResId
|
||||
* ...
|
||||
* @param formatArgs
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
String getString(string pResId, Object... formatArgs);
|
||||
|
||||
Bitmap getBitmap(bitmap pResId);
|
||||
|
||||
/**
|
||||
* Get a bitmap as a {@link Drawable}
|
||||
*
|
||||
* @param pResId
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
Drawable getDrawable(bitmap pResId);
|
||||
|
||||
/**
|
||||
* Gets the density from the current screen's DisplayMetrics
|
||||
*
|
||||
* @return the screen's density
|
||||
*/
|
||||
float getDisplayMetricsDensity();
|
||||
}
|
||||
BIN
src/org/oscim/overlay/marker_default.png
Normal file
BIN
src/org/oscim/overlay/marker_default.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/org/oscim/overlay/marker_default_focused_base.png
Normal file
BIN
src/org/oscim/overlay/marker_default_focused_base.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 664 B |
Reference in New Issue
Block a user