org.osmdroid.views.overlay.PathOverlay Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of osmdroid-android Show documentation
Show all versions of osmdroid-android Show documentation
An Android library to display OpenStreetMap views.
package org.osmdroid.views.overlay;
import java.util.ArrayList;
import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.MapView.Projection;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
/**
*
* @author Viesturs Zarins
*
* This class draws a path line in given color.
*/
public class PathOverlay extends Overlay {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
/**
* Stores points, converted to the map projection.
*/
private ArrayList mPoints;
/**
* Number of points that have precomputed values.
*/
private int mPointsPrecomputed;
/**
* Paint settings.
*/
protected Paint mPaint = new Paint();
private final Path mPath = new Path();
private final Point mTempPoint1 = new Point();
private final Point mTempPoint2 = new Point();
// bounding rectangle for the current line segment.
private final Rect mLineBounds = new Rect();
// ===========================================================
// Constructors
// ===========================================================
public PathOverlay(final int color, final Context ctx) {
this(color, new DefaultResourceProxyImpl(ctx));
}
public PathOverlay(final int color, final ResourceProxy pResourceProxy) {
super(pResourceProxy);
this.mPaint.setColor(color);
this.mPaint.setStrokeWidth(2.0f);
this.mPaint.setStyle(Paint.Style.STROKE);
this.clearPath();
}
// ===========================================================
// Getter & Setter
// ===========================================================
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(Paint pPaint) {
if (pPaint == null)
throw new IllegalArgumentException("pPaint argument cannot be null");
mPaint = pPaint;
}
public void clearPath() {
this.mPoints = new ArrayList();
this.mPointsPrecomputed = 0;
}
public void addPoint(final GeoPoint pt) {
this.addPoint(pt.getLatitudeE6(), pt.getLongitudeE6());
}
public void addPoint(final int latitudeE6, final int longitudeE6) {
this.mPoints.add(new Point(latitudeE6, longitudeE6));
}
public int getNumberOfPoints() {
return this.mPoints.size();
}
/**
* This method draws the line. Note - highly optimized to handle long paths, proceed with care.
* Should be fine up to 10K points.
*/
@Override
protected void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
if (shadow) {
return;
}
if (this.mPoints.size() < 2) {
// nothing to paint
return;
}
final Projection pj = mapView.getProjection();
// precompute new points to the intermediate projection.
final int size = this.mPoints.size();
while (this.mPointsPrecomputed < size) {
final Point pt = this.mPoints.get(this.mPointsPrecomputed);
pj.toMapPixelsProjected(pt.x, pt.y, pt);
this.mPointsPrecomputed++;
}
Point screenPoint0 = null; // points on screen
Point screenPoint1 = null;
Point projectedPoint0; // points from the points list
Point projectedPoint1;
// clipping rectangle in the intermediate projection, to avoid performing projection.
final Rect clipBounds = pj.fromPixelsToProjected(pj.getScreenRect());
mPath.rewind();
projectedPoint0 = this.mPoints.get(size - 1);
mLineBounds.set(projectedPoint0.x, projectedPoint0.y, projectedPoint0.x, projectedPoint0.y);
for (int i = size - 2; i >= 0; i--) {
// compute next points
projectedPoint1 = this.mPoints.get(i);
mLineBounds.union(projectedPoint1.x, projectedPoint1.y);
if (!Rect.intersects(clipBounds, mLineBounds)) {
// skip this line, move to next point
projectedPoint0 = projectedPoint1;
screenPoint0 = null;
continue;
}
// the starting point may be not calculated, because previous segment was out of clip
// bounds
if (screenPoint0 == null) {
screenPoint0 = pj.toMapPixelsTranslated(projectedPoint0, this.mTempPoint1);
mPath.moveTo(screenPoint0.x, screenPoint0.y);
}
screenPoint1 = pj.toMapPixelsTranslated(projectedPoint1, this.mTempPoint2);
// skip this point, too close to previous point
if (Math.abs(screenPoint1.x - screenPoint0.x)
+ Math.abs(screenPoint1.y - screenPoint0.y) <= 1) {
continue;
}
mPath.lineTo(screenPoint1.x, screenPoint1.y);
// update starting point to next position
projectedPoint0 = projectedPoint1;
screenPoint0.x = screenPoint1.x;
screenPoint0.y = screenPoint1.y;
mLineBounds.set(projectedPoint0.x, projectedPoint0.y, projectedPoint0.x,
projectedPoint0.y);
}
canvas.drawPath(mPath, this.mPaint);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy