/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* 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.mapsforge.android.maps.overlay;
import org.mapsforge.android.maps.Projection;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
/**
* WayOverlay is an abstract base class to display {@link OverlayWay OverlayWays}. The class defines some methods to
* access the backing data structure of deriving subclasses.
* <p>
* The overlay may be used to show additional ways such as calculated routes. Closed polygons, for example buildings or
* areas, are also supported. A way node sequence is considered as a closed polygon if the first and the last way node
* are equal.
*
* @param <Way>
* the type of ways handled by this overlay.
*/
public abstract class WayOverlay<Way extends OverlayWay> extends Overlay {
private static final String THREAD_NAME = "WayOverlay";
private final Paint defaultPaintFill;
private final Paint defaultPaintOutline;
private final Path path;
/**
* @param defaultPaintFill
* the default paint which will be used to fill the ways (may be null).
* @param defaultPaintOutline
* the default paint which will be used to draw the way outlines (may be null).
*/
public WayOverlay(Paint defaultPaintFill, Paint defaultPaintOutline) {
super();
this.defaultPaintFill = defaultPaintFill;
this.defaultPaintOutline = defaultPaintOutline;
this.path = new Path();
this.path.setFillType(Path.FillType.EVEN_ODD);
}
/**
* @return the numbers of ways in this overlay.
*/
public abstract int size();
private void assemblePath(Point drawPosition, Way overlayWay) {
this.path.reset();
for (int i = 0; i < overlayWay.cachedWayPositions.length; ++i) {
this.path.moveTo(overlayWay.cachedWayPositions[i][0].x - drawPosition.x,
overlayWay.cachedWayPositions[i][0].y - drawPosition.y);
for (int j = 1; j < overlayWay.cachedWayPositions[i].length; ++j) {
this.path.lineTo(overlayWay.cachedWayPositions[i][j].x - drawPosition.x,
overlayWay.cachedWayPositions[i][j].y - drawPosition.y);
}
}
}
private void drawPathOnCanvas(Canvas canvas, Way overlayWay) {
if (overlayWay.hasPaint) {
// use the paints from the current way
if (overlayWay.paintOutline != null) {
canvas.drawPath(this.path, overlayWay.paintOutline);
}
if (overlayWay.paintFill != null) {
canvas.drawPath(this.path, overlayWay.paintFill);
}
} else {
// use the default paint objects
if (this.defaultPaintOutline != null) {
canvas.drawPath(this.path, this.defaultPaintOutline);
}
if (this.defaultPaintFill != null) {
canvas.drawPath(this.path, this.defaultPaintFill);
}
}
}
/**
* Creates a way in this overlay.
*
* @param index
* the index of the way.
* @return the way.
*/
protected abstract Way createWay(int index);
@Override
protected void drawOverlayBitmap(Canvas canvas, Point drawPosition, Projection projection, byte drawZoomLevel) {
int numberOfWays = size();
for (int wayIndex = 0; wayIndex < numberOfWays; ++wayIndex) {
if (isInterrupted() || sizeHasChanged()) {
// stop working
return;
}
// get the current way
Way overlayWay = createWay(wayIndex);
if (overlayWay == null) {
continue;
}
synchronized (overlayWay) {
// make sure that the current way has way nodes
if (overlayWay.wayNodes == null || overlayWay.wayNodes.length == 0) {
continue;
}
// make sure that the cached way node positions are valid
if (drawZoomLevel != overlayWay.cachedZoomLevel) {
for (int i = 0; i < overlayWay.cachedWayPositions.length; ++i) {
for (int j = 0; j < overlayWay.cachedWayPositions[i].length; ++j) {
overlayWay.cachedWayPositions[i][j] = projection.toPoint(overlayWay.wayNodes[i][j],
overlayWay.cachedWayPositions[i][j], drawZoomLevel);
}
}
overlayWay.cachedZoomLevel = drawZoomLevel;
}
assemblePath(drawPosition, overlayWay);
drawPathOnCanvas(canvas, overlayWay);
}
}
}
@Override
protected String getThreadName() {
return THREAD_NAME;
}
/**
* This method should be called after ways have been added to the overlay.
*/
protected final void populate() {
super.requestRedraw();
}
}