I'm having troubles on a simple task.
I'm trying to draw a square at the top left of the map shown below. (top left of the map projection)
But when I convert pixel 0,0 to latitude and longitude with TileSystem (TileSystem.PixelXYToLatLong) the point looks like it is drawn on the screen and not on the map... Why?
The code:
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
// Translate point to x y coordinates on the screen
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
Point point1_draw = new Point();
Point point2_draw = new Point();
Point point3_draw = new Point();
Point point4_draw = new Point();
mapView.getProjection().toPixels(geoPointFromScreenCoords(0,0,mapView),
point1_draw);
mapView.getProjection().toPixels(geoPointFromScreenCoords(0,100,mapView),
point2_draw);
mapView.getProjection().toPixels(geoPointFromScreenCoords(100,0,mapView),
point3_draw);
mapView.getProjection().toPixels(geoPointFromScreenCoords(100,100,mapView),
point4_draw);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point4_draw.x, point4_draw.y);
path.lineTo(point1_draw.x, point1_draw.y);
path.close();
//canvas.drawCircle(120, 20, 15, paint);
canvas.drawPath(path, paint);
super.draw(canvas, mapView, false);
}`
I'm extending ItemizedOverlay. And this path is drawn on the screen and not on the map. So when i scrol away this path moves with the map... And I dont want that.
Why are you overriding draw instead of addItem?
Here is a video on how to draw on a map
Related
I am new to Android and I am developing a sample project on drawing lines. I want to draw a curved or elevated line connecting two points (x1,y1 and x2,y2). I tried canvas.drawArc() method, but the RectF values inside the drawArc method is just the x,y center points of circle. It is giving me an arc between my two points. But I want a curved line exactly connecting my two points. Can somebody help me? Thanks in advance.
Declare this method inside onDraw method:
private void drawOvalAndArrow(Canvas canvas){
Paint circlePaint = new Paint();
circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeWidth(2);
circlePaint.setColor(Color.CYAN);
float centerWidth = canvas.getWidth()/2; //get center x of display
float centerHeight = canvas.getHeight()/2; //get center y of display
float circleRadius = 20; //set radius
float circleDistance = 200; //set distance between both circles
//draw circles
canvas.drawCircle(centerWidth, centerHeight, circleRadius, circlePaint);
canvas.drawCircle(centerWidth+circleDistance, centerHeight, circleRadius, circlePaint);
//to draw an arrow, just lines needed, so style is only STROKE
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setColor(Color.RED);
//create a path to draw on
Path arrowPath = new Path();
//create an invisible oval. the oval is for "behind the scenes" ,to set the path´
//area. Imagine this is an egg behind your circles. the circles are in the middle of this egg
final RectF arrowOval = new RectF();
arrowOval.set(centerWidth,
centerHeight-80,
centerWidth + circleDistance,
centerHeight+80);
//add the oval to path
arrowPath.addArc(arrowOval,-180,180);
//draw path on canvas
canvas.drawPath(arrowPath, circlePaint);
//draw arrowhead on path start
arrowPath.moveTo(centerWidth,centerHeight ); //move to the center of first circle
arrowPath.lineTo(centerWidth-circleRadius, centerHeight-circleRadius);//draw the first arrowhead line to the left
arrowPath.moveTo(centerWidth,centerHeight );//move back to the center
arrowPath.lineTo(centerWidth+circleRadius, centerHeight-circleRadius);//draw the next arrowhead line to the right
//same as above on path end
arrowPath.moveTo(centerWidth+circleDistance,centerHeight );
arrowPath.lineTo((centerWidth+circleDistance)-circleRadius, centerHeight-circleRadius);
arrowPath.moveTo(centerWidth+circleDistance,centerHeight );
arrowPath.lineTo((centerWidth+circleDistance)+circleRadius, centerHeight-circleRadius);
//draw the path
canvas.drawPath(arrowPath,circlePaint);
}
Also this will find the two sides of the screen (Landscape mode) and will draw a perfect curve across the screen
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
PointF mPoint1 = new PointF(w/1.2F, h/1.2F);
PointF mPoint2 = new PointF(w/24, h/1.2F);
Path myPath1 = new Path();
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
myPath1 = drawCurve(canvas, paint, mPoint1, mPoint2);
canvas.drawPath(myPath1, paint);
}
private Path drawCurve(Canvas canvas, Paint paint, PointF mPointa, PointF mPointb) {
Path myPath = new Path();
myPath.moveTo(63*w/64, h/10);
myPath.quadTo(mPointa.x, mPointa.y, mPointb.x, mPointb.y);
return myPath;
}
Useful references on painting in android:
How to draw Arcs in Android using canvas?
Basic Painting with Views
It might not be what u want, but take a look at http://developer.android.com/reference/android/graphics/Path.html more precisely at moveTo, lineTo, quadTo and cubicTo. (The last 2 methods will draw bezier curves, either quadratic or cubic. If u don't know what those are, take a look at http://en.wikipedia.org/wiki/B%C3%A9zier_curve You only need to understand the parameters of the funcion, not the math behind it). For your purpose you can do like this:
Path mPath;
Paint paint;
mPath = new Path();
mPath.moveTo(x1, y1);
mPath.cubicTo(anchor1_x, anchor1_y, anchor2_x, anchor2_y, x2, y2); /*the anchors you want, the curve will tend to reach these anchor points; look at the wikipedia article to understand more */
paint = new Paint();
paint.setColor(0xFFFFFFFF);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(width); //the width you want
canvas.drawPath(mPath, paint);
I am trying to draw a filled polygon on a map view in my app. No matter what I have tried it will not draw filled in. I can get the strokes to show up but I can not get it to fill. Below is the draw method of my polygon class. It overrides overlays.
public void draw(Canvas canvas, MapView mapv, boolean shadow) {
super.draw(canvas, mapv, shadow);
Paint mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
Paint mPaintFill = new Paint();
mPaintFill.setStyle(Paint.Style.FILL);
mPaintFill.setColor(Color.GREEN);
Path path = new Path();
GeoPoint start = route.get(0);
for (int i = 1; i < route.size(); ++i) {
Point p1 = new Point();
Point p2 = new Point();
Projection projection = mapv.getProjection();
projection.toPixels(start, p1);
projection.toPixels(route.get(i), p2);
path.moveTo(p2.x, p2.y);
path.lineTo(p1.x, p1.y);
start = route.get(i);
}
canvas.drawPath(path, mPaint);
canvas.drawPath(path, mPaintFill);
//canvas.clipPath(path, Op.DIFFERENCE);
}
The above code for me will draw the lines correctly but it doesn't get filled in. Removing canvas.drawPath(path, mPaint); and just leaving the fill one results in nothing showing on the map. I have even tried setting Paint.Style.STROKE to Paint.Style.FILL_AND_STROKE. I am at a complete loss and at this point am thinking it is something simple I am over looking.
I currently need to display a boat/cruise ship route in a MapView, something like this
I started coding my version of it, but since every example that I see of water routes are the same I started wondering if there was a "standard" method of doing it. I have been searching for hours and haven't found anything yet, so I decided to ask here.
Here's what I have so far:
Point point2 = new Point();
projection.toPixels(gp2, point2);
paint.setStrokeWidth(5);
paint.setPathEffect(new DashPathEffect(new float[] {8,12}, 5));
paint.setAlpha(defaultColor==Color.parseColor("#6C8715")?200:100);
canvas.drawLine(point.x, point.y, point2.x,point2.y, paint);
It is working and the only thing left to do is adjust the line every time that the user zooms.
Is this the way to do it, or there's a standard way of doing it?
Any help is appreciated, thank you.
If you move your code to an Overlay then you wouldn't have to worry about adjusting the line when the user zooms/pans. Since you probably have more than two points to draw you can also take advantage of the Path class.
import com.google.android.maps.Overlay;
class PathOverlay extends Overlay {
private void List<GeoPoint>geoPoints;
public PathOverlay(List<GeoPoint> points) {
this.geoPoints = geoPoints;
}
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapv, shadow);
Paint paint = new Paint();
paint.setStrokeWidth(5);
paint.setPathEffect(new DashPathEffect(new float[] {8,12}, 5));
paint.setAlpha(defaultColor==Color.parseColor("#6C8715")?200:100);
Path path = new Path();
boolean isFirst = true;
for (GeoPoint geoPoint : this.geoPoints) {
Point point = new Point();
mapView.getProjection().toPixels(geoPoint, point);
if (isFirst) {
isFirst = false;
path.moveTo(point.x, point.y);
}
else {
path.lineTo(point.x,point.y);
}
}
canvas.drawPath(path, paint);
}
}
Extend Overlay and override draw() method in it. Then do the same you did previously. You will get automatic redraw in move/zoom
This one answer will work for you How to draw a path on a map using kml file?
public PNGOverlay(Bitmap original, GeoPoint topLeftGeoPoint, GeoPoint bottomRightGeoPoint) {
this.original = Bitmap.createScaledBitmap(original, original.getWidth(), original.getHeight(), true);
...
topGeoPoint = topLeftGeoPoint;
bottomGeoPoint = bottomRightGeoPoint;
}
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, false);
Projection projection = mapView.getProjection();
Point leftTop = new Point();
Point rightTop = new Point();
Point rightBottom = new Point();
Point leftBottom = new Point();
projection.toPixels(topGeoPoint, leftTop);
projection.toPixels(new GeoPoint(topGeoPoint.getLatitudeE6(), bottomGeoPoint.getLongitudeE6()), rightTop);
projection.toPixels(bottomGeoPoint, rightBottom);
projection.toPixels(new GeoPoint(bottomGeoPoint.getLatitudeE6(), topGeoPoint.getLongitudeE6()), leftBottom);
....
Paint paint = new Paint();
paint.setFilterBitmap(true);
paint.setAntiAlias(true);
canvas.drawBitmap(original, null, new Rect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y), paint);
....
}
I have a problem with this code. When I draw the png on the mapView, the png image is showed over the compass and over the GPS position indicatior? Any idea?
From your question is difficult to guess what is exactly your problem, but if you mean that the PNG is being drawn over the other overlays and you want it to be under them, you can solve it by adding the PNG overlay first to the mapview.
MapView calls the draw method from each overlay by the order that you add them:
mapview.getoverlays().add(overlay1);
mapview.getoverlays().add(overlay2);
This results in overlay2 being drawn over overlay1.
mapview.getoverlays().add(overlay2);
mapview.getoverlays().add(overlay1);
This results in overlay1 being drawn over overlay2.
good luck.
I've this custom class that extends the Overlay that is being added into my mapview. i have just one of this class that adds all my polygon and text into this overlay class. However this results in a very slow mapview. I added a draw integer and tested out that this class will draw 84 times each time the ondraw function is being called. Is there any solution that will help to reduce the loading speed of the mapview? Right now the mapview is very slow, each time i move left right or even zoom will be very slow. looking at the android catlog, it seems to me that overlay class ondraw is being called everysecond? should i be looking at another type of layer instead of using overlay?
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow)
{
shadow=false;
int numberofdraw= 0;
//outline
Paint paint = new Paint();
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(2);
//paint.setColor(0x10000000);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
Point point1_draw = new Point();
for (int i =0;i<data.getCustomPolygonList().size();i++)
{
CustomPolygon customPolygon= data.getCustomPolygonList().get(i);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
for(int n=0;n<customPolygon.getCorrdinateList().size();n++)
{
GeoPoint sector1 = new GeoPoint((int)(customPolygon.getCorrdinateList().get(n).getLatitude()*1e6), (int)((customPolygon.getCorrdinateList().get(n).getLongitude())*1e6));
if(n==0){
mapView.getProjection().toPixels(sector1, point1_draw);
path.moveTo(point1_draw.x,point1_draw.y);
}else
{
mapView.getProjection().toPixels(sector1, point1_draw);
path.lineTo(point1_draw.x,point1_draw.y);
}
}
path.close();
canvas.drawPath(path, paint);
numberofdraw++;
// canvas.clipPath(path, Op.DIFFERENCE);
}
//inside sector color
for (int i =0;i<data.getCustomPolygonList().size();i++)
{
CustomPolygon customPolygon= data.getCustomPolygonList().get(i);
paint = new Paint();
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(2);
paint.setColor(0x186666ff);
//paint.setColor(customPolygon.getColor());
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
point1_draw = new Point();
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
for(int n=0;n<customPolygon.getCorrdinateList().size();n++)
{
GeoPoint sector1 = new GeoPoint((int)(customPolygon.getCorrdinateList().get(n).getLatitude()*1e6), (int)((customPolygon.getCorrdinateList().get(n).getLongitude())*1e6));
if(n==0){
mapView.getProjection().toPixels(sector1, point1_draw);
path.moveTo(point1_draw.x,point1_draw.y);
}else
{
mapView.getProjection().toPixels(sector1, point1_draw);
path.lineTo(point1_draw.x,point1_draw.y);
}
}
path.close();
numberofdraw++;
canvas.drawPath(path, paint);
}
//inside sector text
for (int i =0;i<data.getCustomPolygonList().size();i++)
{
CustomPolygon customPolygon= data.getCustomPolygonList().get(i);
TextPaint paintText = new TextPaint();
Point point1 = new Point();
String text=customPolygon.getName();
for(int n=0;n<customPolygon.getCorrdinateList().size();n++)
{
if(customPolygon.getTextLocation()!=null)
{
paintText.setTextSize(24);
Rect rect = new Rect();
paintText.getTextBounds(text, 0, text.length(), rect);
paintText.setTextAlign(Paint.Align.CENTER);
paintText.setTypeface(Typeface.DEFAULT_BOLD);
paintText.setColor(Color.BLACK);
GeoPoint sector1 = new GeoPoint((int)(customPolygon.getTextLocation().getLatitude()*1e6), (int)((customPolygon.getTextLocation().getLongitude())*1e6));
mapView.getProjection().toPixels(sector1, point1);
}
}
numberofdraw++;
canvas.drawText(text, point1.x, point1.y, paintText);
}
Log.e(Config.log_id,"draw no. "+ numberofdraw+"");
}
there are many ways you can improve it, I will suggest you one.
Buffering:
For each polygon create a new canvas and a new bitmap
Canvas myBufferCanvas;
Bitmap myBufferBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
myBufferCanvas = new Canvas(myBufferBitmap);
Then only call draw when the polygon is change, call the draw with myBufferCanvas and then call drawBitmap on the true canvas.
The advantage of this method is performance, it will be extremely fast! The disadvantage is memory, if you have to many polygons, you can kill the device. Just try reusing them some home and you will be fine.
Just remember that you can apply any transformation to your buffered image without redrawing it.
I think you should be using a custom ItemizedOverlay to manage drawing items on your MapView. That aside, there are some changes you can make to your existing code which I'm sure would speed it up. In your draw() method you are creating new Paint objects each time, setting their properties and then disposing of them. Worse still, inside the draw() method you loop through the polygon list twice, creating more Paint objects or TextPaint objects. Instead, you can create one of each Paint object once when the Overlay is initialised and then re-use them in the loop. You may also be able to do everything in one loop.
Process the data, then build the paths and finally paint the paths on the map, see the response from TWiStErRob in this post.