Drawing a shape with a curve line - android

Whant to draw as in this image
for that would use as in the link ShapeDrawable Drawing multiple shapes with ShapeDrawable in xml with Android but don't know how to make the line curve
---------------------edit-----------------------------------
based on #Bojan Kseneman answer tried with the following code
PointF pt1l = new PointF(canvas.getWidth()/2+40, (float)newPosY-canvas.getWidth()/40);//canvas.getWidth()/40
PointF pt2l = new PointF(canvas.getWidth()/2+40, (float)newPosY+canvas.getWidth()/40);
PointF midl = new PointF(canvas.getWidth()/2+30, (float)newPosY+canvas.getWidth()/40);
PointF pt1r = new PointF(canvas.getWidth()/2-40, (float)newPosY-canvas.getWidth()/40);
PointF pt2r = new PointF(canvas.getWidth()/2-40, (float)newPosY+canvas.getWidth()/40);
PointF midr = new PointF(canvas.getWidth()/2-30, (float)newPosY+(canvas.getWidth()/40)/2);
Path pathLeft = new Path();
//pathLeft.setFillType(Path.FillType.EVEN_ODD);
pathLeft.moveTo(pt1l.x,pt1l.y);
pathLeft.quadTo(midl.x,midl.y,pt2l.x,pt2l.y);
Path pathRight = new Path();
//pathRight.setFillType(Path.FillType.EVEN_ODD);
pathRight.moveTo(pt1r.x,pt1r.y);
pathRight.quadTo(midr.x,midr.y,pt2r.x,pt2r.y);
Paint curveLineR = new Paint();
curveLineR.setColor(Color.GREEN);
Paint curveLineL = new Paint();
curveLineL.setColor(Color.GREEN);
Paint circle = new Paint();
circle.setColor(Color.GREEN);
canvas.drawPath(pathLeft, curveLineL);
canvas.drawPath(pathRight, curveLineR);
//canvas.drawCircle(canvas.getWidth()/2,canvas.getHeight()/2,canvas.getWidth()/30,circle);
canvas.drawCircle(canvas.getWidth()/2,(float)newPosY,canvas.getWidth()/40,circle);
but didn't get a curve line more like parte of a circle(changing the value of midr and midl got closer but still was't quite a line). Maybe with a bit of more tests could get the line but for now only need the circle, for anyone that also trying to get the curve line leaving the code and +1 for #Bojan Kseneman for pointing in the right direction.

You should make a custom View and draw stuff like that with the Canvas. You have to draw two paths (two curves) and a circle in the middle. Here is the basic idea, you will have to do the rest of the work on your own.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path pathLeft = new Path();
pathLeft.moveTo(x1, y1);
pathLeft.quadTo(x1, y1, x2, y2);
Path pathRight = new Path();
pathLeft.moveTo(x1, y1);
pathLeft.quadTo(x1, y1, x2, y2);
canvas.drawPath(pathLeft, mPathPaint);
canvas.drawPath(pathRight, mPathPaint);
canvas.drawCircle(x, y, radius, paint);
}

Related

How to draw a curved line in android?

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);

Android: How can I use quadTo in Path class correctly?

I was trying to start a quadratic curve from (0, 0) to the bottom right of my device screen. I did some research and looks like I can use quadTo method in the Path class to achieve that. I wrote the following code but I don't see the curve is drawn:
int w = getDisplayWidth();
int h = getDisplayHeight();
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
paint.setStrokeCap(Paint.Cap.ROUND);
PointF pt1 = new PointF(0, 0);
PointF pt2 = new PointF(w, h);
Path path = new Path();
// Find the mid point
float x2 = (pt2.x + pt1.x)/2;
float y2 = (pt2.y + pt1.y)/2;
// Move the path to the mid point
path.moveTo(x2, y2);
// Draw a cruve from 0,0 to w, h
path.quadTo(pt1.x, pt1.y, pt2.x, pt2.y);
m_canvas.drawPath(path, paint);
The output is the image below:
Did I miss something?
Thanks.
According to the documentation:
void quadTo(float x1, float y1, float x2, float y2)
Add a quadratic bezier from the last point, approaching control point
(x1,y1), and ending at (x2,y2).
Currently you are drawing a curve starting in the middle of the screen (x2,y2), through the (0,0) point and ending in (width, height).
Try something like this:
PointF pt1 = new PointF(0, 0);
PointF pt2 = new PointF(w, h);
PointF mid = new PointF(w, h/2);
Path path = new Path();
path.moveTo(0, 0);
path.quadTo(mid.x, mid.y, pt2.x, pt2.y);

Line and text with canvas in android

I've a noob question about android dev.
I search how to draw a line with a text on it.
I visited a lot of website talking about it but no one answer me.
i've created this function :
private void creerLigne(float x, float y, float xend, float yend, int color) {
Bitmap bmp = Bitmap.createBitmap(mImage.getWidth(), mImage.getHeight(), Config.ARGB_8888);
Canvas c = new Canvas(bmp);
mImage.draw(c);
Paint p = new Paint();
p.setColor(color);
p.setTextSize(50);
Path path = new Path();
path.moveTo(x - xend, y - yend);
c.drawTextOnPath("42", path, 0,30,p);
c.drawLine(x, y, xend, yend, p);
mImage.setImageBitmap(bmp);
}
With this, i've a line and the text but the text is in the top left hand corner :( .
Thanks for your help.
The coordinates x, y, xend, yend are all absolute positions within the image, right?
In this case the Path should be build as:
Path path = new Path();
path.moveTo(x,y);
path.lineTo(xend, yend);
c.drawTextOnPath("42", 0, 30, path, p); // baseline is 30 pixel above the path
In the Paint you can also set flags to ensure the text is centered along the path with p.setTextAlign(Paint.Align.CENTER)

Android Mapview slows after drawing too much polygon?

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.

Draw a perfect curve connecting three points

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.

Categories

Resources