OsmMapView.java :  » Map » maps-minus » coderminus » maps » Android Open Source

Android Open Source » Map » maps minus 
maps minus » coderminus » maps » OsmMapView.java
package coderminus.maps;

import java.util.Vector;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;

public class OsmMapView extends View
{
  public class Tiles extends Vector<Tile> 
  {
    private static final long serialVersionUID = -6468659912600523042L;
  }

  
  public static class Mercator 
  {
      final private static double R_MAJOR = 6378137.0;
      //final private static double R_MINOR = 6356752.3142;
      final public static double MAX_X = 20037508.34;
      final public static double MAX_Y = 20037508.34;

      public static double  mercX(double lon) 
      {
          return R_MAJOR * Math.toRadians(lon);
      }

      public static double mercY(double lat) 
      {
        return (Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180)) *
               (20037508.34 / 180);
      }
  }

  private Paint paint = new Paint();
  private int offsetX = 0;
  private int offsetY = 0;
  private int touchDownX = 0;
  private int touchDownY = 0;
  private int zoomLevel = 1;
  
  private Handler handler = new Handler() 
  {
    @Override
    public void handleMessage(final Message msg) 
    {
      sizeWatcher.onSizeChanged(msg.arg1, msg.arg2);
      if(msg.what == 1)
      {
        invalidate();
      }
    }
  };
  
  private int touchOffsetX;
  private int touchOffsetY;
  private Tile[] tiles = new Tile[9];
  private int incrementsX[] = new int[] {0, 1, 2, 0, 1, 2, 0, 1, 2};
  private int incrementsY[] = new int[] {0, 0, 0, 1, 1, 1, 2, 2, 2};
  
  private static final int TILE_SIZE = 256;
  private Animation zoomInAnimation;
  private Animation zoomOutAnimation;
  private int pendingZoomLevel;
  private int locationOffsetX;
  private int locationOffsetY;
  private Bitmap currentPos = null;
  private TileQueueSizeWatcher sizeWatcher;
  private TilesProvider tilesProvider;
  private Context context;
  
  public OsmMapView(Context context, AttributeSet attrs) 
  {
    super(context, attrs);
    this.context = context;
    
    zoomInAnimation = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
    zoomInAnimation.setDuration(150L);

    zoomOutAnimation = new ScaleAnimation(1, 0.5f, 1, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
    zoomOutAnimation.setDuration(150L);
    currentPos = BitmapFactory.decodeResource(this.getContext().getResources(), R.drawable.ic_maps_indicator_current_position);
  }

  public void setSizeWatcher(TileQueueSizeWatcher sizeWatcher)
  {
    this.sizeWatcher = sizeWatcher;
    tilesProvider = new TilesProvider(this.getContext(), handler, sizeWatcher);
    tilesProvider.setCachePath(Configuration.getCachePath(context));
    tilesProvider.setTilePostfix(Configuration.getTilePostfix(context));
  }
  
  @Override
  protected void onDraw(Canvas canvas) 
  {
    super.onDraw(canvas);
    
    for(Tile tile : tiles) 
    {
      if(isOnScreen(tile)) 
      {
        Bitmap bitmap = getBitmap(tile);
        
        if(bitmap != null) 
        {
              canvas.drawBitmap(bitmap, this.offsetX + tile.offsetX, this.offsetY + tile.offsetY, this.paint);
        }
        drawLocation(canvas);
      }
    }
  }

//  private void queueNextZoomAhead(Tile tile) 
//  {
//    if(zoomLevel >= 17) return;
//    int nextZoomLevel = zoomLevel + 1;
//    
//    nextTile.mapX = tile.mapX * 2;
//    nextTile.mapY = tile.mapY * 2;
//    nextTile.key  = nextZoomLevel + "/" + nextTile.mapX + "/" + nextTile.mapY + ".png";
//    if(!tilesCache.hasTileBitmap(nextTile.key))
//    //if(!tilesCache.isInFile(nextTile.key))
//    {
//      getBitmap(nextTile);
//    }
//    
//    nextTile.mapX = tile.mapX * 2 + 1;
//    nextTile.mapY = tile.mapY * 2;
//    nextTile.key  = nextZoomLevel + "/" + nextTile.mapX + "/" + nextTile.mapY + ".png";
//    if(!tilesCache.hasTileBitmap(nextTile.key))
//    //if(!tilesCache.isInFile(nextTile.key))
//    {
//      getBitmap(nextTile);
//    }
//    
//    nextTile.mapX = tile.mapX * 2;
//    nextTile.mapY = tile.mapY * 2 + 1;
//    nextTile.key  = nextZoomLevel + "/" + nextTile.mapX + "/" + nextTile.mapY + ".png";
//    if(!tilesCache.hasTileBitmap(nextTile.key))
//    //if(!tilesCache.isInFile(nextTile.key))
//    {
//      getBitmap(nextTile);
//    }
//    
//    nextTile.mapX = tile.mapX * 2 + 1;
//    nextTile.mapY = tile.mapY * 2 + 1;
//    nextTile.key  = nextZoomLevel + "/" + nextTile.mapX + "/" + nextTile.mapY + ".png";
//    if(!tilesCache.hasTileBitmap(nextTile.key))
//    //if(!tilesCache.isInFile(nextTile.key))
//    {
//      getBitmap(nextTile);
//    }
//  }

  private void drawLocation(Canvas canvas) 
  {
    if(this.locationOffsetX != 0 && this.locationOffsetY != 0) 
    {
        int x = this.offsetX - this.locationOffsetX - 20;
        int y = this.offsetY - this.locationOffsetY - 20;
          canvas.drawBitmap(
              currentPos, 
              x, 
              y, this.paint);
       }
  }

  private boolean isOnScreen(Tile tile) 
  {
    if(tile == null)
    {
      return false;
    }
    
    int upperLeftX = tile.offsetX + this.offsetX;
    int upperLeftY = tile.offsetY + this.offsetY;
    int width = this.getWidth();
    int height = this.getHeight();
    
    if(((upperLeftX + TILE_SIZE) >= 0) && (upperLeftX  < width) &&
       ((upperLeftY + TILE_SIZE) >= 0) && (upperLeftY  < height)) 
    {
      return isSane(tile);
    }
    return false;
  }

  private boolean isSane(Tile tile) 
  {
    if(tile.mapX >= 0 && 
       tile.mapY >= 0 &&
       tile.mapX <= (Math.pow(2, zoomLevel) - 1) &&
       tile.mapY <= (Math.pow(2, zoomLevel) - 1)
       )
    {
      return true;
    }
    return false;
  }

  private Tile[] initializeCurrentTiles(int zoomLevel, int offsetX, int offsetY, int size) 
  {
    int mapX = (0 - offsetX)/TILE_SIZE;
    int mapY = (0 - offsetY)/TILE_SIZE;
    
    for(int index = 0; index < size; ++index) 
    {
      if(tiles[index] == null) 
      {
        tiles[index] = new Tile();
      }
      
      if(tiles[index].mapX != (mapX + incrementsX[index]) ||
         tiles[index].mapY != (mapY + incrementsY[index])  )
      {
          tiles[index].mapX    = mapX + incrementsX[index];
          tiles[index].mapY    = mapY + incrementsY[index];
          tiles[index].offsetX = tiles[index].mapX * TILE_SIZE;
          tiles[index].offsetY = tiles[index].mapY * TILE_SIZE;
          tiles[index].zoom    = zoomLevel;
          tiles[index].key     = (zoomLevel + "/" + tiles[index].mapX + "/" + tiles[index].mapY + ".png").intern();
      }
    }    
    return tiles;    
  }

  private Bitmap getBitmap(Tile tile) 
  {
    return tilesProvider.getTileBitmap(tile);
  }

  public void setZoom(int zoomLevel) 
  {
    this.zoomLevel = zoomLevel;
    this.pendingZoomLevel = zoomLevel;
  }  
  
  @Override
  protected void onAnimationEnd() 
  {
    if(this.zoomLevel > pendingZoomLevel) 
    {
      this.zoomLevel = pendingZoomLevel;
      zoomOut();
      sizeWatcher.enableZoomOut();
    }
    else if(this.zoomLevel < pendingZoomLevel)
    {
      this.zoomLevel = pendingZoomLevel;
      zoomIn();
      sizeWatcher.enableZoomIn();
    }
    
    super.onAnimationEnd();
    invalidate();
  }

  @Override
  public boolean onTouchEvent(final MotionEvent event) 
  {
    switch (event.getAction()) 
    {
      case MotionEvent.ACTION_DOWN:
        this.touchDownX = (int) event.getX();
        this.touchDownY = (int) event.getY();
        this.touchOffsetX = this.offsetX;
        this.touchOffsetY = this.offsetY;
        invalidate();
        return true;
      case MotionEvent.ACTION_MOVE:
        setOffsetX(this.touchOffsetX + (int) event.getX() - this.touchDownX);
        setOffsetY(this.touchOffsetY + (int) event.getY() - this.touchDownY);
        invalidate();
        return true;
      case MotionEvent.ACTION_UP:
        setOffsetX(this.touchOffsetX + (int) event.getX() - this.touchDownX);
        setOffsetY(this.touchOffsetY + (int) event.getY() - this.touchDownY);
        invalidate();
    }

    return super.onTouchEvent(event);
  }

  public int getOffsetX() 
  {
    return offsetX;
  }

  public int getOffsetY() 
  {
    return offsetY;
  }

  public void setOffsetX(int offsetX) 
  {
    if(pendingZoomLevel == this.zoomLevel)
    {
        if((offsetX + 255) > this.getWidth()) 
        {
          this.offsetX = this.getWidth() - 255;
        }
        else if((offsetX - 255) < getMaxOffsetX()) 
        {
          this.offsetX = getMaxOffsetX() + 255;
        }
        else 
        {
          this.offsetX = offsetX;
        }
    }
  }

  private int getMaxOffsetX() 
  {
    return (int) (0 - (Math.pow(2, zoomLevel)) * 256);
  }

  public void setOffsetY(int offsetY) 
  {
    if(pendingZoomLevel == this.zoomLevel)
    {
        if((offsetY + 255) > this.getHeight()) 
        {
          this.offsetY = this.getHeight() - 255;
        }
        else if((offsetY - 255) < getMaxOffsetX()) 
        {
          this.offsetY = getMaxOffsetX() + 255;
        }
        else 
        {
          this.offsetY = offsetY;
        }
        initializeCurrentTiles(zoomLevel, this.offsetX, this.offsetY, 9);
    }
  }

  public void clearCurrentCache() 
  {
    tilesProvider.clearCache();
    
    for(Tile tile : tiles) 
    {
      if(isOnScreen(tile)) 
      {
        tilesProvider.removeTile(tile);
      }
    }
  }

  public void zoomOut() 
  {
    setOffsetX(getOffsetX()/2 + (getWidth ()/4));
    setOffsetY(getOffsetY()/2 + (getHeight()/4));
    locationOffsetX = locationOffsetX/2;
    locationOffsetY = locationOffsetY/2;
    tilesProvider.clearResizeCache();
  }

  public void zoomIn() 
  {
    setOffsetX((getOffsetX())*2 - (getWidth ()/2));
    setOffsetY((getOffsetY())*2 - (getHeight()/2));
    locationOffsetX = locationOffsetX*2;
    locationOffsetY = locationOffsetY*2;
    tilesProvider.clearResizeCache();
//    Tile[] tiles = getTiles(zoomLevel, this.offsetX, this.offsetY, 9);
//    for(Tile tile : tiles) 
//    {
//      getBitmap(tile);
//      if(isOnScreen(tile)) 
//      {
//        queueNextZoomAhead(tile);
//      }
//    }

  }

  public void animateZoomOut(int zoomLevel) 
  {
    if(pendingZoomLevel == this.zoomLevel)
    {
        this.pendingZoomLevel = zoomLevel;
        startAnimation(zoomOutAnimation);
    }
  }

  public void animateZoomIn(int zoomLevel) 
  {
    if(this.pendingZoomLevel == this.zoomLevel)
    {
        this.pendingZoomLevel = zoomLevel;
        startAnimation(zoomInAnimation);
    }
  }

  public void cacheCurrentMap(int level) 
  {
    new TilesCacher().execute(tiles, tilesProvider, zoomLevel, level);
  }


  public void centerMapTo(double lon, double lat) 
  {
    double merc_x = convertLonToMercX(lon);
    double merc_y = convertLatToMercY(lat);
    
    double mapWidth = (Math.pow(2, zoomLevel) * 256);
    
    double pixelSize = mapWidth/(Mercator.MAX_X * 2);
    
    double pixelX = Mercator.MAX_X - (0 - merc_x);
    double pixelY = Mercator.MAX_Y - merc_y;
    
    int pixelOffsetX = (int) (pixelX * pixelSize);
    int pixelOffsetY = (int) (pixelY * pixelSize);
    
    locationOffsetX = 0 - pixelOffsetX;
    locationOffsetY = 0 - pixelOffsetY;
    setOffsetX(locationOffsetX + (getWidth ()/2));
    setOffsetY(locationOffsetY + (getHeight()/2));
    invalidate();
  }

  /**
   * X
   * @param lon
   * @return
   */
  private double convertLonToMercX(double lon) 
  {
    return Mercator.mercX(lon);
  }

  /**
   * Y
   * @param lat
   * @return
   */
  private double convertLatToMercY(double lat) 
  {
    return Mercator.mercY(lat);
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.