Draw grid over polygon in Google map V2 - android

I have made one polygon over Google map v2 and now on that polygon I want to add one grid as shown in Reference Image and that grid should have to re-sizable and portions of grid should be selectable.
I don't have any idea about this so please help on this.
I am trying this so far but still don't have any result.
All your help is appreciated.
Reference Image:

Not sure about Google Maps, but with osmdroid you should use osmbonuspack and implement a custom Polygon:
public class GridPolygon extends Polygon {
private BitmapShader bitmapShader;
private IGeoPoint lastCenterGeoPoint;
private int xOffset = 0;
private int yOffset = 0;
public GridPolygon(Context ctx) {
super(ctx);
}
public void setPatternBMP(#NonNull final Bitmap patternBMP) {
bitmapShader = new BitmapShader(patternBMP, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
mFillPaint.setShader(bitmapShader);
}
protected void recalculateMatrix(#NonNull final MapView mapView) {
//final int mapSize = TileSystem.MapSize(mapView.getZoomLevel());
final Projection projection = mapView.getProjection();
final IGeoPoint geoPoint = mapView.getMapCenter();
if (lastCenterGeoPoint == null) lastCenterGeoPoint = geoPoint;
final Point point = projection.toPixels(geoPoint, null);
final Point lastCenterPoint = projection.toPixels(lastCenterGeoPoint, null);
xOffset += lastCenterPoint.x - point.x;
yOffset += lastCenterPoint.y - point.y;
xOffset %= 100; // 100 is pixel size of shader image
yOffset %= 100;
final Matrix matrix = new Matrix();
matrix.reset();
matrix.setScale(1,1);
matrix.preTranslate(xOffset, yOffset);
//matrix.setTranslate(xOffset, yOffset);
bitmapShader.setLocalMatrix(matrix);
mFillPaint.setShader(bitmapShader);
lastCenterGeoPoint = geoPoint;
}
#Override
protected void draw(Canvas canvas, MapView mapView, boolean shadow) {
recalculateMatrix(mapView);
super.draw(canvas, mapView, shadow);
}
}
Full source code.

Related

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.
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:
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".

Programatically spread drawn markers around a drawn arc in Android Java

I am having a hard time dealing with this issue, most of the "help" i have found deals with Trigonometry, which is something I have no experience with. I need to create a view like this: Proposed Graphics.
I have the arc and and the background image of the main gauge but I need to add the time markers you see, both the oval like shapes and the times. They need to be added programmatically because the number of markers can be from 1 to 28, though probably not more than 10.
I have tried using the sweep angle to get the X/Y position of the where the arc ends (using division to define an increasing sweep angle to increment the arc) and it sort of worked for the first one but I could not replicate it for any other one with a different sweep angle.
I am also using a matrix to rotate the marker image which is more or less working, I have been trying various trig functions to get the x and y. Below is some code:
Basic code:
public class Custom_clock extends View
{
private Paint mPaint;
private RectF rectF;
private int mStrokeWidth;
private int width;
private int height;
private Typeface custom_font;
private final int MAX = 263;
private final int START = 138;
private Bitmap bitmap;
private Bitmap marker;
private int scaledSizeNumbers;
private int scaledSizeLabels;
private int scaledSizeDose;
private Matrix matrix = new Matrix();
private String hoursMinsLabel = "Minutes";
private String hoursMinsNumber = "3";
private ArrayList<String>DoseTimes = new ArrayList<>();
public Custom_clock(Context context)
{
super(context);
}
public Custom_clock(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Custom_clock(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private void initClock(){
width = getWidth();
height = getHeight();
mStrokeWidth = ((width+height)/33);
custom_font = Typeface.createFromAsset(getResources().getAssets(), "fonts/text_font.ttf");
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.base_arc3);
marker = BitmapFactory.decodeResource(getResources(), R.drawable.single_marker);
scaledSizeNumbers = getResources().getDimensionPixelSize(R.dimen.NumberFontSize);
scaledSizeLabels = getResources().getDimensionPixelSize(R.dimen.LabelFontSize);
scaledSizeDose = getResources().getDimensionPixelSize(R.dimen.DoseFontSize);
int scaledMarginWidth = getResources().getDimensionPixelSize(R.dimen.WidthMargin);
int scaledMarginTop = getResources().getDimensionPixelSize(R.dimen.TopMargin);
mPaint = new Paint();
rectF = new RectF(scaledMarginWidth,scaledMarginTop,getWidth()- scaledMarginWidth,getHeight());
DoseTimes.clear();
DoseTimes.add("1:00pm");
DoseTimes.add("2:00pm");
DoseTimes.add("3:00pm");
DoseTimes.add("4:00pm");
DoseTimes.add("5:00pm");
}
private void DrawMainArc(Canvas canvas){
Paint paint =new Paint();
initClock();
canvas.drawBitmap(bitmap,null,rectF,paint);
mPaint.setColor(getResources().getColor(R.color.light_grey));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth+2);
mPaint.setStrokeCap(Paint.Cap.ROUND);
canvas.drawArc(rectF,START,GetStops(5,MAX)*2,false, mPaint);
}
private int GetStops(int stops, int max){
return max/stops;
}
#Override
protected void onDraw(Canvas canvas)
{
if(bitmap != null){
super.onDraw(canvas);
DrawMainArc(canvas);
DrawOutlineArc(canvas);
DrawHours(canvas);
DrawHoursLabel(canvas);
DrawDoseLabel(canvas);
AddStops(canvas);
}
}
Marker specific code attempt:
This draws the first marker fairly close to where I want it but the rest are drawn up and to the left increasingly, only 2 are even visible. I know the answer lies somewhere with the angle and possibly a matrix but trig > me.
private void AddStops(Canvas canvas){
int stopsNum = DoseTimes.size();//currently 5
int rotatinalIncrement = MAX/(stopsNum);//currently 54
int markerAngle = 0;
double x;
double y;
for(int i =0; i <stopsNum; i++){
x = (canvas.getWidth()/4) * Math.cos(markerAngle);
y = (canvas.getWidth()/4) * Math.cos(markerAngle);
markerAngle = markerAngle +rotatinalIncrement;
DrawMarker(canvas,markerAngle,(int)x ,(int)y);
}
}
private void DrawMarker(Canvas canvas, int Angle, int x, int y){
int scaledSize = getResources().getDimensionPixelSize(R.dimen.MarkerSize);
Bitmap scaled = Bitmap.createScaledBitmap(marker,scaledSize,scaledSize,false);
matrix.reset();
matrix.postTranslate(-canvas.getWidth() / 2, -canvas.getHeight() / 2); // Centers image
matrix.postRotate(angle);
matrix.setRotate(Angle);
matrix.postTranslate(x, y);
canvas.drawBitmap(scaled, matrix, null);
}
At first, Math.cos and sin use argument in radians, while you (as seems from value 54) apply argument in degrees. Just make markerAngle * Math.Pi / 180 or use function like toRadians if it exists in JavaScript.
Second - for y-coordinate you have to use sin rather than cos

Android how to draw paint in free hand in MapView using overlay?

In my app Draw paint in free hand on Map view but searching lot of information finally got from rectangle shape draw on mapview but i want in place of rectangle draw free hand like zigzag how to change my code Any help please..
MapOverlay.java
public class MapOverlay extends Overlay {
private float x1,y1,x2,y2;
private GeoPoint p1=null,p2=null;
private MapExampleActivity mv = null;
private Paint paint = new Paint();
private Path path = new Path();
private boolean isUp = false;
//constructor receiving the initial point
public MapOverlay(MapExampleActivity mapV,float x,float y){
paint.setStrokeWidth(2.0f);
x1 = x;
y1 = y;
mv = mapV;
p1 = mapV.getMapView().getProjection().fromPixels((int)x1,(int)y1);
}
//override draw method to add our custom drawings
#Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
if(p1 != null && p2 != null){
//get the 2 geopoints defining the area and transform them to pixels
//this way if we move or zoom the map rectangle will follow accordingly
Point screenPts1 = new Point();
mapView.getProjection().toPixels(p1, screenPts1);
Point screenPts2 = new Point();
mapView.getProjection().toPixels(p2, screenPts2);
//draw inner rectangle
paint.setColor(Color.BLUE);
// paint.setStyle(Style.FILL);
canvas.drawPath(path, paint);
canvas.drawRect(screenPts1.x, screenPts1.y, screenPts2.x, screenPts2.y, paint);
//draw outline rectangle
// paint.setColor(Color.YELLOW);
paint.setStyle(Style.STROKE);
// canvas.drawRect(screenPts1.x, screenPts1.y, screenPts2.x, screenPts2.y, paint);
canvas.drawPath(path, paint);
}
return true;
}
#Override
public boolean onTouchEvent(MotionEvent e, MapView mapView) {
if(mv.isEditMode() && !isUp){
if(e.getAction() == MotionEvent.ACTION_DOWN){
x1 = y1 = 0;
x1 = e.getX();
y1 = e.getY();
p1 = mapView.getProjection().fromPixels((int)x1,(int)y1);
}
//here we constantly change geopoint p2 as we move out finger
if(e.getAction() == MotionEvent.ACTION_MOVE){
x2 = e.getX();
y2 = e.getY();
p2 = mapView.getProjection().fromPixels((int)x2,(int)y2);
}
//---when user lifts his finger---
if (e.getAction() == MotionEvent.ACTION_UP) {
isUp = true;
}
return true;
}
return false;
}
}
using this i able to draw like this rectangle shapes and draw up to again you click the toggle button(possible to draw multiple times)
i want draw lines instead of rectangle like below image(draw multiple times).
finally i found this link this link provide rectangle shape draw http://n3vrax.wordpress.com/2011/08/13/drawing-overlays-on-android-map-view/
just change rectangle to free draw any idea please....
You can free hand draw a line using the code bellow:
Code
public class HandDrawOverlay extends Overlay {
private boolean editMode = false;
private boolean isTouched = false;
private Paint paint = new Paint();
private Point screenPt1 = new Point();
private Point screenPt2 = new Point();
private ArrayList<GeoPoint> points = null;
public HandDrawOverlay(){
paint.setStrokeWidth(2.0f);
paint.setStyle(Style.STROKE);
paint.setColor(Color.BLUE);
}
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if(points != null && points.size() > 1){
mapView.getProjection().toPixels(points.get(0), screenPt1);
for(int i=1; i<points.size();i++){
mapView.getProjection().toPixels(points.get(i), screenPt2);
canvas.drawLine(screenPt1.x, screenPt1.y, screenPt2.x, screenPt2.y, paint);
screenPt1.set(screenPt2.x, screenPt2.y);
}
}
}
#Override
public boolean onTouchEvent(MotionEvent e, MapView mapView) {
if(editMode){
int x = (int)e.getX();
int y = (int)e.getY();
GeoPoint geoP = mapView.getProjection().fromPixels(x,y);
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
isTouched = true;
points = new ArrayList<GeoPoint>();
points.add(geoP);
break;
case MotionEvent.ACTION_MOVE:
if(isTouched)
points.add(geoP);
break;
case MotionEvent.ACTION_UP:
if(isTouched)
points.add(geoP);
isTouched = false;
break;
}
mapView.invalidate();
return true;
}
return false;
}
/**
* #return the editMode
*/
public boolean isEditMode() {
return editMode;
}
/**
* #param editMode the editMode to set
*/
public void setEditMode(boolean editMode) {
this.editMode = editMode;
}
}
to use
HandDrawOverlay handDrawOverlay;
handDrawOverlay = new HandDrawOverlay();
mapView.getOverlays().add(handDrawOverlay);
//Set edit mode to true to start drwaing
handDrawOverlay.setEditMode(true);
//Set edit mode to true to stop drwaing
handDrawOverlay.setEditMode(false);
Note
This is a full functioning example to help you starting. However, you should optimize the code to make it more efficient (i.e. using Path to store the drawing path in onDraw(), reducing the number of points recorded in onTouch(), etc.).
Enjoy it.

How do I draw a line Overlay on Google Maps Android

I am trying to draw a line on my maps project, but can't get the line to draw. Where and how do I declare the overlay? I've tried various methods, but can't get it to work. ie, code just displays errors in Eclipse. What I am NOT trying to do is draw a route from A to B, but rather draw the route as I am moving.
// Creating a MapView
public class Gpstrack extends MapActivity {
private MapView map;
private MapController controller;
private Projection projection;
ArrayList<GeoPoint> geoPointsArray = new ArrayList<GeoPoint>();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initMapView();
initMyLocation();
TabHost.TabSpec spec;
TabHost th = (TabHost)findViewById(R.id.tabhost);
th.setup();
spec = th.newTabSpec("tag1");
spec.setContent(R.id.map_Tab);
spec.setIndicator("Map");
th.addTab(spec);
spec = th.newTabSpec("tag2");
spec.setContent(R.id.log_Tab);
spec.setIndicator("Log");
th.addTab(spec);
spec = th.newTabSpec("tag3");
spec.setContent(R.id.details_Tab);
spec.setIndicator("Details");
th.addTab(spec);
spec = th.newTabSpec("tag4");
spec.setContent(R.id.student_Tab);
spec.setIndicator("Student Info");
th.addTab(spec);
}
#Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
//Map and Controls
private void initMapView() {
map = (MapView) findViewById(R.id.mvMain);
controller = map.getController();
map.setSatellite(true);
//map.setStreetView(true);
map.setBuiltInZoomControls(true);
}
//Creates an Overlay that marks current position
private void initMyLocation() {
final MyLocationOverlay overlay = new MyLocationOverlay(this, map);
overlay.enableMyLocation();
overlay.enableCompass();
overlay.runOnFirstFix(new Runnable() {
public void run() {
controller.setZoom(17);
controller.animateTo(overlay.getMyLocation());
map.getOverlays().add(overlay);
}
});
}
//Experiment
class MyOverlay extends Overlay {
public void draw(Canvas canvas, MapView mapv, boolean shadow) {
super.draw(canvas, mapv, shadow);
Projection projection = mapv.getProjection();
Path p = new Path();
for (int i = 0; i < geoPointsArray.size(); i++) {
if (i == geoPointsArray.size() -1) {
break;
}
Point from = new Point();
Point to = new Point();
projection.toPixels(geoPointsArray.get(i), from);
projection.toPixels(geoPointsArray.get(i + 1), to);
p.moveTo(from.x, from.y);
p.lineTo(to.x, to.y);
}
Paint mPaint = new Paint();
mPaint.setStyle(Style.STROKE);
mPaint.setColor(Color.GREEN);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(5);
canvas.drawPath(p, mPaint);
mapv.invalidate();
super.draw(canvas, mapv, shadow);
}
}
}
Have you tried with this demo to implement the Google Map Overlay?
In you overlay class you can draw line like this
public class MapOverlay extends com.google.android.maps.Overlay
{
Canvas canvas;
#Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
long when)
{
// TODO Auto-generated method stub
super.draw(canvas, mapView, shadow);
this.canvas=canvas;
Point screenpoint = new Point();
mapView.getProjection().toPixels(p, screenpoint);
Bitmap bmp = BitmapFactory.decodeResource(
getResources(), R.drawable.pushpin);
canvas.drawBitmap(bmp, canvas.getWidth()/4,
canvas.getHeight()/4, null);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawLine(canvas.getWidth()/4, canvas.getHeight()/4,
canvas.getWidth()/2, canvas.getHeight()/2, paint);
return true;
}
return true;
}
}
the draw line function is like
public void drawLine (float startX, float startY,
float stopX, float stopY, Paint paint)
Since: API Level 1 Draw a line segment with the specified start and stop x,y coordinates, using the specified paint.
Parameters
startX The x-coordinate of the start point of the line
startY The y-coordinate of the start point of the line
paint The paint used to draw the line
and you can reffer this quetion if you want to draw a path
J2ME/Android/BlackBerry - driving directions, route between two locations
I think you should try this link Drawing a line/path on Google Maps
and this one J2ME/Android/BlackBerry - driving directions, route between two locations .I think this should help you.

draw circle with transparency in mapview

I have a problem with mapview and Overlay.
I must to draw a circle on the map everytime that change GPS position.
I used the method draw in my overlay class that extend overlay.
The problem is that I must draw these circles with transparency, but when the circles overlap each other in the intersection point the color it's different because there is a sum of alpha.
How I can fix it?
This is my overlay class:
public class ImpactOverlay extends Overlay {
private static int CIRCLERADIUS = 0;
private GeoPoint geopoint;
private int myCircleRadius;
Point point = new Point();
Paint circle = new Paint(Paint.ANTI_ALIAS_FLAG);
private long systemTime= -1 ;
public ImpactOverlay(GeoPoint point, int myRadius) {
geopoint = point;
CIRCLERADIUS = myRadius; // assegna raggio del cerchio
}
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
// Transfrom geoposition to Point on canvas
Projection projection = mapView.getProjection();
projection.toPixels(geopoint, point);
// the circle to mark the spot
circle.setColor(Color.parseColor("#88ff0000"));
circle.setAlpha(122); // trasparenza
myCircleRadius = metersToRadius(CIRCLERADIUS, mapView,
(double) geopoint.getLatitudeE6() / 1000000);
canvas.drawCircle(point.x, point.y, myCircleRadius, circle);
}
public static int metersToRadius(float meters, MapView map, double latitude) {
return (int) (map.getProjection().metersToEquatorPixels(meters) * (1 / Math
.cos(Math.toRadians(latitude))));
}
#Override
/* Implementa il doppio tap per eseguire zoom sulla mappa */
public boolean onTouchEvent(MotionEvent event, MapView mapView) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if ((System.currentTimeMillis() - systemTime) < 250) {
mapView.getController().zoomIn();
}
systemTime = System.currentTimeMillis();
break;
}
return false;
}
}
CircleOptions circle = new CircleOptions();
circle.center(new LatLng(latitude, longitude))
.radius(1500)//in meters
.strokeColor(Color.BLUE)//border color
.strokeWidth(3.0f)//border width
.fillColor(0x200000ff);//inside circle
googleMap.addCircle(circle);//GoogleMap googleMap(initialize accordingly)
Well one possibility is to clip the area away which is intersecting the second circle like that, pseudo code:
canvas.clipPath(circle2.toPath())
canvas.draw(circle1)
canvas.removeClip()
canvas.draw(circle2)
You need to take account of the intersection when you clip, something like this:
.
#Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
long when) {
Paint paint = new Paint();
paint.setColor(Color.parseColor("#88ff0000"));
paint.setAlpha(16); // quite transparent
Point point = new Point();
Point point2 = new Point();
float radius = 50.0f;
Projection projection = mapView.getProjection();
projection.toPixels(mGpt, point); // 1st GeoPoint
projection.toPixels(mGpt2, point2); // 2nd GeoPoint
Path path1 = new Path();
Path path2 = new Path();
path1.addCircle(point.x, point.y, radius, Direction.CW); // 1st circle
path2.addCircle(point2.x, point2.y, radius, Direction.CW); // 2nd circle
canvas.save(); // save canvas without the clip region
canvas.clipPath(path2, Region.Op.DIFFERENCE); // clip the region
// to the whole view less where circle2 will be when it's drawn
canvas.drawPath(path1, paint); // draw 1st circle minus where it overlaps
canvas.restore(); // clear the clip region
canvas.drawPath(path2, paint); // draw 2nd circle (unclipped)
return false;
}
should work
You don't need to know how many shapes are there beforehand. If you use separate overlays you could just easily draw each and add the corresponding area to the clipping area.
Full code follows:
import java.util.List;
import android.graphics.*;
import android.graphics.Path.Direction;
import android.graphics.Region.Op;
import android.os.Bundle;
import android.view.MotionEvent;
import com.google.android.maps.*;
public class CircleTest extends MapActivity {
private MapView m_map;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
m_map = (MapView) findViewById(R.id.mapview);
m_map.displayZoomControls(true);
m_map.setBuiltInZoomControls(true);
}
#Override
protected void onStart() {
super.onStart();
// m_map.getOverlays().add(new ); // some other overlays
m_map.getOverlays().add(new ImpactGeneratorOverlay());
// the impact areas are being inserted between these two, see ImpactGeneratorOverlay
m_map.getOverlays().add(new ImpactClipRestoreOverlay());
}
/**
* Restore clipping area to the saved one.
*/
public static class ImpactClipRestoreOverlay extends Overlay {
#Override
public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
super.draw(canvas, mapView, shadow);
canvas.restore();
}
}
/**
* Handles events, on touch down it adds a new Impact area to the map,
* just before the ClipRestore overlay (assume it's the last, if not store position, and insert before).
*/
public static class ImpactGeneratorOverlay extends Overlay {
#Override
public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
super.draw(canvas, mapView, shadow);
canvas.save();
}
#Override
public boolean onTouchEvent(final MotionEvent e, final MapView mapView) {
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
GeoPoint point = mapView.getProjection().fromPixels((int) e.getX(), (int) e.getY());
List<Overlay> overlays = mapView.getOverlays();
overlays.add(overlays.size() - 1, new ImpactOverlay(point, 1000));
break;
}
return super.onTouchEvent(e, mapView);
}
}
/**
* Draw impact and remove the current shape path from the drawable area.
*/
public static class ImpactOverlay extends Overlay {
// shape parameters
private final GeoPoint circleCenter;
private final int circleRadius;
// drawing cache
private final Point circleDrawCenter = new Point();
private final Paint circlePaint = new Paint();
public ImpactOverlay(final GeoPoint circleCenter, final int circleRadius) {
this.circleCenter = circleCenter;
this.circleRadius = circleRadius;
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.argb(64, 255, 0, 0));
}
#Override
public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
// Transfrom geoposition to Point on canvas
Projection projection = mapView.getProjection();
projection.toPixels(circleCenter, circleDrawCenter);
// the circle to mark the spot
float circleDrawRadius = ImpactOverlay.metersToRadius(mapView, circleRadius, circleCenter.getLatitudeE6() / 1e6f);
// create circle from path
Path path = new Path();
path.addCircle(circleDrawCenter.x, circleDrawCenter.y, circleDrawRadius, Direction.CW);
// draw circle
canvas.drawPath(path, circlePaint);
// remove circle from further posibble drawing areas
canvas.clipPath(path, Op.DIFFERENCE);
}
public static float metersToRadius(final MapView map, final float meters, final float latitude) {
return (float) (map.getProjection().metersToEquatorPixels(meters) * (1 / Math.cos(Math.toRadians(latitude))));
}
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
}
This contains a fix for clipping unwanted layers, say the first one, but this can be avoided if you just gather all the circles in one overlay and draw them in one draw method.
The key is to draw and set clipping (even if they exist in different overlays, not advised!):
canvas.save();
canvas.drawPath(path1, paint);
canvas.clipPath(path1, Op.DIFFERENCE);
canvas.drawPath(path2, paint); // do not draw over path1
canvas.clipPath(path2, Op.DIFFERENCE);
canvas.drawPath(path3, paint); // do not draw over path1 + path2
canvas.clipPath(path3, Op.DIFFERENCE);
// do not draw over path1 + path2 + path3
canvas.restore();
canvas.drawPath(path4, paint); // draw over anything

Categories

Resources