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.
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
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);
}
Probably this question might be duplicate.But I am finding hard to get answer as I am new to OpenCV and Canvas drawing on view for android here is my code
List<Point> pts = new ArrayList<Point>();
Converters.Mat_to_vector_Point(MatOfPoint, pts);
I am getting List correctly,where Point abstract org.opencv.core.Point.
Now i am converting those points to android.graphics.Point coordinate using correct MatOfPoint.
android.graphics.Point pt1 = new android.graphics.Point((int) pts.get(0).x, (int) pts.get(0).y);
On getting this, I am trying to draw Canvas using android.graphics.Point, but coordinates are no matching up with image coordinates. Check the code given below.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(3);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(Color.parseColor("#55000000"));
paint.setStyle(Paint.Style.FILL);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(5);
canvas.drawPaint(paint);
canvas.drawLine(point1.x,point1.y, point2.x, point2.y, paint);
}
The canvas drawn with the detected square from openCV coordinate does not match the canvas Point coordinates. Have I to manipulate the points with pixels or density of image? Any help will be appreciated.
Thanks
you need to scale the point and shift point's position by adding offset
see line 412 in CameraBridgeViewBase.java
see line 171 in JavaCameraView.java
scale=Math.min(mOpenCvCameraView.getWidth()/Matwidth,mOpenCvCameraView.getHeight())/Matheight)
xoffset=(mOpenCvCameraView.getWidth()-scale*Matwidth)/2
yoffset=(mOpenCvCameraView.getHeight()-scale*Matheight)/2
final point1's X coordinate is: point1.x*scale+xoffset
final point1's Y coordinate is: point1.y*scale+yoffset
final point2's X coordinate is: point2.x*scale+xoffset
final point2's Y coordinate is: point2.y*scale+yoffset
Points which you have calculated with opencv, references coordinates on your MAT( or on your bitmap image).
You have to scale these coordinates to your display object in order to fit your line on image.
You can use the code below to achieve your goal.
Hope it helps.
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(3);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(Color.parseColor("#55000000"));
paint.setStyle(Paint.Style.FILL);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(5);
canvas.drawPaint(paint);
//iv is the ImageView which you can draw canvas over it
// imgbitmap is bitmap image
double scaledWidth=iv.getWidth();
double scaledHeight=iv.getHeight();
double xScaleFactor= scaledWidth/imgbitmap.getWidth();
double yScaleFactor= scaledHeight/imgbitmap.getHeight();
android.graphics.Point canvas_point1 = new android.graphics.Point((int)((point1.x*xScaleFactor)),(int)((point1.y*yScaleFactor)));
android.graphics.Point canvas_point2 = new android.graphics.Point((int)((point2.x*xScaleFactor)),(int)((point2.y*yScaleFactor)));
canvas.drawLine(canvas_point1.x,canvas_point1.y, canvas_point2.x, canvas_point2.y, paint);
}
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'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.