package com.nutiteq.maps;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import com.nutiteq.components.MapPos;
import com.nutiteq.components.TileMapBounds;
import com.nutiteq.components.ZoomRange;
import com.nutiteq.task.Task;
import com.nutiteq.ui.Copyright;
import com.nutiteq.ui.StringCopyright;
import com.nutiteq.utils.Utils;
/**
* <p>
* Base class for maps that handles some common logic between different map
* types.
* </p>
* <p>
* Handles properties:
* <ul>
* <li>copyright string</li>
* <li>tile size</li>
* <li>zoom range (min/max zoom)</li>
* </ul>
* </p>
* <p>
* Default map size, map bounds and zoom handling is implemented based on
* OpenStreetMap system. Feel free to override these based on your specific
* needs.
* </p>
*/
public abstract class BaseMap implements GeoMap {
private Copyright copyright;
private final int tileSize;
private final ZoomRange zoomRange;
private MapTileOverlay overlay;
private Image missingTile;
public BaseMap(final Copyright copyright, final int tileSize, final int minZoom, final int maxZoom) {
this.copyright = copyright;
this.tileSize = tileSize;
this.zoomRange = new ZoomRange(minZoom, maxZoom);
}
public BaseMap(final String copyright, final int tileSize, final int minZoom, final int maxZoom) {
this(new StringCopyright(copyright), tileSize, minZoom, maxZoom);
}
public Task getInitializationTask() {
return null;
}
public Copyright getCopyright() {
return copyright;
}
public int getTileSize() {
return tileSize;
}
public int getMaxZoom() {
return zoomRange.getMaxZoom();
}
public int getMinZoom() {
return zoomRange.getMinZoom();
}
public ZoomRange getZoomRange() {
return zoomRange;
}
/**
* <p>
* Handles zoom for display middle point (as default the red cross on screen)
* by assuming that map size between single zoom levels is always magnitude of
* two (next map size is two times smaller or bigger).
* </p>
* <p>
* For example for OpenStreetMap zoom level 0 world size is 256x256 pixels and
* center point will be in 128x128. If zoomed in one level world size will be
* 512x512 pixels and center point will be at 256x256.
* </p>
*
* @param middlePoint
* map position on witch to perform zoom action
* @param zoomSteps
* zoom steps needed to handle
* @return maps position on new zoom level
*/
public MapPos zoom(final MapPos middlePoint, final int zoomSteps) {
int x = middlePoint.getX();
int y = middlePoint.getY();
int zoom = middlePoint.getZoom();
if (zoomSteps > 0) {
// zoom in
x <<= zoomSteps;
y <<= zoomSteps;
} else {
x >>= -zoomSteps;
y >>= -zoomSteps;
}
zoom += zoomSteps;
return new MapPos(x, y, zoom);
}
/**
* Get map bounds for specified zoom level.
*
* @param zoom
* zoom level for witch to get map bounds
* @return bounds for zoom level for given map
*/
public TileMapBounds getTileMapBounds(final int zoom) {
final MapPos min = new MapPos(0, 0, zoom);
final MapPos max = new MapPos(getMapWidth(zoom) - 1, getMapHeight(zoom) - 1, zoom);
return new TileMapBounds(min, max);
}
/**
* Get map height for given zoom level. Default implementation is done for
* OpenStreetMap system (map tile edge is power of 2)
*
* @param zoom
* zoom level for witch to get map height
* @return map height
*/
public int getMapHeight(final int zoom) {
return 1 << (zoom + Utils.log2(getTileSize()));
}
/**
* Get map width for given zoom level. Default implementation is done for
* OpenStreetMap system (map tile edge is power of 2)
*
* @param zoom
* zoom level for witch to get map width
* @return map width
*/
public int getMapWidth(final int zoom) {
return 1 << (zoom + Utils.log2(getTileSize()));
}
public void addTileOverlay(final MapTileOverlay overlay) {
this.overlay = overlay;
}
public MapTileOverlay getTileOverlay() {
return overlay;
}
public void setMissingTileImage(final Image missingTile) {
this.missingTile = missingTile;
}
public Image getMissingTileImage() {
if (missingTile == null) {
missingTile = Image.createImage(getTileSize(), getTileSize());
final Graphics g = missingTile.getGraphics();
g.setColor(0xFFFF0000);
g.fillRect(0, 0, getTileSize(), getTileSize());
}
return missingTile;
}
public void setCopyright(final Copyright copyright) {
this.copyright = copyright;
}
}