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.
Related
I want to create graph (with edges and vertices), to implement a problem called 3-color. I just need a little guidance on how to start, should i use a multiple views and draw each view as a circle, and then how can i connect lines (edges) between the views? should i work with pixels all the time or there is another way, more simple one because calculate pixels when dealing with big graphs (more than 10 vertices) is complicated.
thanks.
What you want is called drawing on Canvas.
As a basic example you can see this code, which will create 2 vertices and an edge connecting them:
public class MyView extends View {
private final Paint p;
private final Path path;
private final Point point1;
private final Point point2;
public MyView(Context context) {
super(context);
p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setStrokeWidth(10);
path = new Path();
point1 = new Point(200, 300);
point2 = new Point(700, 800);
}
#Override
protected void onDraw(Canvas canvas) {
// draw first vertex
p.setStyle(Paint.Style.FILL);
p.setColor(Color.GREEN);
canvas.drawCircle(point1.x, point1.y, 15, p);
// draw the edge
path.reset();
path.moveTo(point1.x, point1.y);
path.lineTo(point2.x, point2.y);
p.setStyle(Paint.Style.STROKE);
p.setColor(Color.CYAN);
canvas.drawPath(path, p);
// draw second vertex
p.setStyle(Paint.Style.FILL);
p.setColor(Color.BLUE);
canvas.drawCircle(point2.x, point2.y, 15, p);
}
}
Which will result in this:
I found this library which is a good source:
https://github.com/LordVulkan/Graphs
I want to move a bitmap image along consecutive coordinates in SurfaceView. I have a bitmap myBall drawn in the coordinate (x1, y1) on a SurfaceView as follows (partial code)(
public class MainSurfaceView extends SurfaceView implements Runnable {...
...
#Override
public void run() {
while (isRunning) {
if (!myHolder.getSurface().isValid())
continue;
Canvas canvas;// Define canvas to paint on it
canvas = myHolder.lockCanvas();
//Draw full screen rectangle to hold the floor map.
Rect dest = new Rect(0, 0, getWidth(), getHeight());
Paint paint = new Paint();
paint.setFilterBitmap(true);
canvas.drawBitmap(bgImage, null, dest, paint);
//This is the ball I want to move
canvas.drawBitmap(myBall, x1, y1, null);
myHolder.unlockCanvasAndPost(canvas);
}
}
Now I want to move it to (x2, y2) then (x3, y3) and ... as many as needed and one after the other. I have tried to use TranslateAnimation but couldn't do it.
I have figured out how to animate using a coordinates. I will explain what I did hopping that it will be helpful to others:
First I saved the coordinates as Point object
List<Point> point_list = new ArrayList<Point>();
point_list.add(new Point(x_value, y_value));//Add the x and y coordinates to the Point\
Leave implementing Runnable and use onDraw() method instead of run() method as follows:
public class MainSurfaceView extends SurfaceView {...
....
#Override
protected void onDraw(Canvas canvas) {
// Draw full screen rectangle to hold the floor map.
Rect fArea = new Rect(0, 0, getWidth(), getHeight());
Paint paint = new Paint();
paint.setFilterBitmap(true);
// draw the paint on the rectangle with the floor map
canvas.drawBitmap(bgImage, null, fArea, paint);
// Get the coordinates of x & y as Point object
List<Point> myPoints = point_list;
// Start printing myBall on the floor (view)
try {
if (index < myPoints.size()) {
// Increment the value of index and use it as index for the point_list
index++;
}
// Print myBall in each coordinates of x & y using the index
canvas.drawBitmap(myBall, myPoints.get(index).x, myPoints.get(index).y, null);
} catch (IndexOutOfBoundsException e) {
// TODO: handle exception
}
}
I use try and catch to avoid IndexOutOfBoundryExeption
Cheers!
I think this might be what you're after. What you're trying to do is tween the bitmap and there are a few ways you can do that. There is also the ViewPropertyAnimator, which can animate an entire view.
hi i want to draw path into canvas but it does not do anything, it does not draw the canvas either.
my code:
Path path = new Path();
Canvas canvas = new Canvas();
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawColor(Color.CYAN);
for (int i = 5; i < 50; i++)
{
path.setLastPoint(4, i - 1);
path.lineTo(4, i);
}
path.close();
for (int i = 0; i < 5; i++)
{
View iview = inflater.inflate(R.layout.linear_layout, null);
iview.findViewById(R.id.imageView1);//.setBackgroundColor(backgroundColors[i]);
ShapeDrawable mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(Color.YELLOW);
mDrawable.setBounds(10, 10, 15, 15);
canvas.drawPath(path, paint);
mDrawable.draw(canvas);
iview.draw(canvas);
realViewSwitcher.addView(iview);
}
it shows me only green color which is the default value of the view.backroundColor.
thanks
Canvas is just a "tool" for drawing over a Bitmap. You need to associate them this way:
Canvas canvas = new Canvas(someBitmap);
However this only lets you draw on someBitmap. If you want to draw in the view, you have to do that in onDraw(Canvas), using the Canvas you're provided with, which is already bound with the bitmap that is the real view's drawing.
To use onDraw(), you have to make a custom View (that is, extend from some View).
Then there is SurfaceView but that's another thing (and I don't know much about it).
i have a mapview with itemizedoverlay, like in the example of mapview in androids developers guide
i have my own icon on the items, but also i want to personalize them, adding some text, not only the icon. But i mean text visible on the map, not when i press on the item
can i do it? how?
on this overrided ondraw method (subclassing the ItemizedOverlay) i draw the icon bitmap and above the bitmap i draw a round rect with a text (item text), but with the canvas you can do anything you want.
if(!shadow){
for (OverlayItem item : items) {
Point point = new Point();
proj.toPixels(item.getPoint(), point);
TextPaint tPaint = new TextPaint();
tPaint.setColor(Color.BLACK);
tPaint.setStrokeWidth(20);
Paint paint = new Paint();
paint.setColor(Color.YELLOW);
float measure = tPaint.measureText( item.getTitle() );
float hMeasure = measure /2;
RectF rf = new RectF(point.x-hMeasure, point.y-40, point.x+hMeasure, point.y-20 );
canvas.drawRoundRect(rf, 5, 5, paint);
canvas.drawText(item.getTitle(), point.x-hMeasure, point.y-25, tPaint);
draw.setBounds(point.x-hWidth,point.y-hHeight,point.x+hWidth,point.y+hHeight);
draw.draw(canvas);
}
}
cheers
I would like to draw a curve connecting three points in my screen
PointA = (480,46)
PointB = (160,137)
PointC = (0,228)
How to draw the curve using Android APIs?
Whatever i wanted, i could to produce it by using the following code :
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;
}
This will find the two sides of the screen (Landscape mode) and will draw a perfect curve across the screen.