Search code examples
androidimageosmdroidosmbonuspack

Draw image on osm map osmdroid


I want to draw image on osm map, using osmdroid/osmbonuspack. I have tried Marker and SimpleLocationOverlay. These display the image as overlay, like a pin which doesn't change scale. But I want to show image which becomes part of Map, such that when Map is Zoomed-in, the image should scale up, and when zoomed-out, it should scale down.


Solution

  • With some modifications of GroundOverlay.java and MainActivity.java of osmbonuspack repo:

    public class MainActivity extends AppCompatActivity {
    
        MapView mMapView = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            Context ctx = getApplicationContext();
            Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
    
            setContentView(R.layout.activity_main);
    
            mMapView = (MapView) findViewById(R.id.map);
            mMapView.setTileSource(TileSourceFactory.MAPNIK);
    
            mMapView.setBuiltInZoomControls(true);
            mMapView.setMultiTouchControls(true);
            GeoPoint overlayCenterPoint = new GeoPoint(50.450667, 30.523193);
            IMapController mapController = mMapView.getController();
            mapController.setZoom(17f);
            mapController.setCenter(overlayCenterPoint);
            mMapView.setMapOrientation(0.0f);
    
            GroundOverlay myGroundOverlay = new GroundOverlay();
            myGroundOverlay.setPosition(overlayCenterPoint);
            Drawable d = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_launcher, null);
            myGroundOverlay.setImage(d.mutate());
            myGroundOverlay.setDimensions(200.0f);
            myGroundOverlay.setTransparency(0.25f);
            myGroundOverlay.setBearing(0);
            mMapView.getOverlays().add(myGroundOverlay);
    
            mMapView.invalidate();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mMapView.onResume();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            mMapView.onPause();
        }
    
        public class GroundOverlay extends Overlay {
    
            protected Drawable mImage;
            protected GeoPoint mPosition;
            protected float mBearing;
            protected float mWidth, mHeight;
            protected float mTransparency;
            public final static float NO_DIMENSION = -1.0f;
            protected Point mPositionPixels, mSouthEastPixels;
    
            public GroundOverlay() {
                super();
                mWidth = 10.0f;
                mHeight = NO_DIMENSION;
                mBearing = 0.0f;
                mTransparency = 0.0f;
                mPositionPixels = new Point();
                mSouthEastPixels = new Point();
            }
    
            public void setImage(Drawable image){
                mImage = image;
            }
    
            public Drawable getImage(){
                return mImage;
            }
    
            public GeoPoint getPosition(){
                return mPosition.clone();
            }
    
            public void setPosition(GeoPoint position){
                mPosition = position.clone();
            }
    
            public float getBearing(){
                return mBearing;
            }
    
            public void setBearing(float bearing){
                mBearing = bearing;
            }
    
            public void setDimensions(float width){
                mWidth = width;
                mHeight = NO_DIMENSION;
            }
    
            public void setDimensions(float width, float height){
                mWidth = width;
                mHeight = height;
            }
    
            public float getHeight(){
                return mHeight;
            }
    
            public float getWidth(){
                return mWidth;
            }
    
            public void setTransparency(float transparency){
                mTransparency = transparency;
            }
    
            public float getTransparency(){
                return mTransparency;
            }
    
            protected void computeHeight(){
                if (mHeight == NO_DIMENSION && mImage != null){
                    mHeight = mWidth * mImage.getIntrinsicHeight() / mImage.getIntrinsicWidth();
                }
            }
    
            /** @return the bounding box, ignoring the bearing of the GroundOverlay (similar to Google Maps API) */
            public BoundingBox getBoundingBox(){
                computeHeight();
                GeoPoint pEast = mPosition.destinationPoint(mWidth, 90.0f);
                GeoPoint pSouthEast = pEast.destinationPoint(mHeight, -180.0f);
                double north = mPosition.getLatitude()*2 - pSouthEast.getLatitude();
                double west = mPosition.getLongitude()*2 - pEast.getLongitude();
                return new BoundingBox(north, pEast.getLongitude(), pSouthEast.getLatitude(), west);
            }
    
            public void setPositionFromBounds(BoundingBox bb){
                mPosition = bb.getCenterWithDateLine();
                GeoPoint pEast = new GeoPoint(mPosition.getLatitude(), bb.getLonEast());
                GeoPoint pWest = new GeoPoint(mPosition.getLatitude(), bb.getLonWest());
                mWidth = (float)pEast.distanceToAsDouble(pWest);
                GeoPoint pSouth = new GeoPoint(bb.getLatSouth(), mPosition.getLongitude());
                GeoPoint pNorth = new GeoPoint(bb.getLatNorth(), mPosition.getLongitude());
                mHeight = (float)pSouth.distanceToAsDouble(pNorth);
            }
    
            @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) {
                if (shadow)
                    return;
                if (mImage == null)
                    return;
    
                computeHeight();
    
                final Projection pj = mapView.getProjection();
    
                pj.toPixels(mPosition, mPositionPixels);
                GeoPoint pEast = mPosition.destinationPoint(mWidth/2, 90.0f);
                GeoPoint pSouthEast = pEast.destinationPoint(mHeight/2, -180.0f);
                pj.toPixels(pSouthEast, mSouthEastPixels);
                int hWidth = mSouthEastPixels.x-mPositionPixels.x;
                int hHeight = mSouthEastPixels.y-mPositionPixels.y;
                mImage.setBounds(-hWidth, -hHeight, hWidth, hHeight);
    
                mImage.setAlpha(255-(int)(mTransparency*255));
    
                drawAt(canvas, mImage, mPositionPixels.x, mPositionPixels.y, false, -mBearing);
            }
    
        }
    }
    

    you can get something like that:

    Ground overlay zoom example

    Main part is:

    // overlay center point
    GeoPoint overlayCenterPoint = new GeoPoint(50.450667, 30.523193);
    IMapController mapController = mMapView.getController();
    mapController.setZoom(17f);
    mapController.setCenter(overlayCenterPoint);
    mMapView.setMapOrientation(0.0f);
    
    GroundOverlay myGroundOverlay = new GroundOverlay();
    myGroundOverlay.setPosition(overlayCenterPoint);
    Drawable d = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_launcher, null);
    myGroundOverlay.setImage(d.mutate());
    
    // overlay width in meters (height calculated automatically) also you can set both width and height
    myGroundOverlay.setDimensions(200.0f);
    myGroundOverlay.setTransparency(0.25f);
    myGroundOverlay.setBearing(0);
    mMapView.getOverlays().add(myGroundOverlay);
    

    and it's "self-commented".