Getting all the points on the way in android - FingerPaint.java

I tried to get all the x, y coordinates that are drawn in the path on the canvas. But I could not get points. I get only a few points. Why is this?

Is there a way to get all the points x and y?

I am using FingerPaint.java as a starting point.

Link to the original FingerPaint.java

Here is the code that I modified and used:

package com.schogini.whiteboard; import java.util.ArrayList; import java.util.StringTokenizer; import android.app.Activity; import android.content.Context; import android.graphics.*; import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; //import android.widget.Toast; public class FingerPaint extends Activity implements ColorPickerDialog.OnColorChangedListener { //color - ARGB int a = 255; int r = 255; int g = 0; int b = 0; //erase Flag boolean eraseFlag=false; //Internet Posting static String toSend; static String parseStr; //array for storing x,y,r,g,b,a static ArrayList<String> rArray,gArray,bArray,alphaArray,xPointArray,yPointArray; //ArrayList<String> rArray_in,gArray_in,bArray_in,alphaArray_in,xPointArray_in,yPointArray_in; //Drawing types private static Paint mPaint; private MaskFilter mEmboss; private MaskFilter mBlur; //touch - Path Coordinates private static float mX; private static float mY; //MyView object MyView m; //point populate float dx,dy,distance; int dd,ii; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); m = new MyView(FingerPaint.this); setContentView(m); //move to appropriate module rArray = new ArrayList<String>(); gArray = new ArrayList<String>(); bArray = new ArrayList<String>(); alphaArray = new ArrayList<String>(); xPointArray = new ArrayList<String>(); yPointArray = new ArrayList<String>(); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(0xFFFF0000); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); //width of the drawing brush mPaint.setStrokeWidth(12); mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f); mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL); } public void parsing(String str22){ //example string received from server // parseStr = "255,0,0,1.0,88.0,100.0||255,0,0,1.0,88.0,101.0||255,0,0,1.0,88.0,102.0||255,0,0,1.0,88.0,103.0||255,0,0,1.0,88.0,104.0||255,0,0,1.0,88.0,105.0||255,0,0,1.0,88.0,106.0||255,0,0,1.0,88.0,107.0||255,0,0,1.0,88.0,108.0," + // "||255,0,0,1.0,88.0,109.0||255,0,0,1.0,88.0,110.0||255,0,0,1.0,88.0,111.0||255,0,0,1.0,88.0,112.0||255,0,0,1.0,88.0,113.0||255,0,0,1.0,88.0,114.0||255,0,0,1.0,88.0,115.0||255,0,0,1.0,88.0,116.0||255,0,0,1.0,88.0,117.0," + // "||255,0,0,1.0,88.0,118.0||255,0,0,1.0,88.0,119.0||255,0,0,1.0,88.0,120.0||255,0,0,1.0,80.0,100.0||255,0,0,1.0,81.0,100.0||255,0,0,1.0,82.0,100.0||255,0,0,1.0,83.0,100.0||255,0,0,1.0,84.0,100.0||255,0,0,1.0,85.0,100.0," + // "||255,0,0,1.0,86.0,100.0||255,0,0,1.0,87.0,100.0||255,0,0,1.0,88.0,100.0||255,0,0,1.0,89.0,100.0||255,0,0,1.0,91.0,100.0||255,0,0,1.0,92.0,100.0||255,0,0,1.0,93.0,100.0||255,0,0,1.0,94.0,100.0||255,0,0,1.0,95.0,100.0," + // "||255,0,0,1.0,96.0,100.0||255,0,0,1.0,97.0,100.0||255,0,0,1.0,98.0,100.0||255,0,0,1.0,99.0,100.0||255,0,0,1.0,100.0,100.0||255,0,0,1.0,101.0,100.0||255,0,0,1.0,102.0,100.0||255,0,0,1.0,103.0,100.0,"; parseStr="255,0,0,255,85.351585,90.17996||255,0,0,255,85.351585,90.17996||255,0,0,255,123.97784,80.883064||255,0,0,255,164.47311,71.58616||255,0,0,255,182.22874,65.543175||255,0,0,255,233.9381,48.3439||255,0,0,255,247.95567,42.30091||255,0,0,255,252.62822,40.441532||255,0,0,255,252.62822,40.441532||255,0,0,255,86.9091,167.34427||255,0,0,255,86.9091,167.34427||255,0,0,255,86.9091,167.34427||255,0,0,255,151.70154,133.41057||255,0,0,255,190.3278,118.07068||255,0,0,255,235.18411,98.54717||255,0,0,255,248.57867,92.03935||255,0,0,255,256.36627,89.71512||255,0,0,255,257.30078,89.250275||255,0,0,255,257.30078,89.250275||255,0,0,255,82.548065,277.97742||255,0,0,255,82.548065,277.97742||255,0,0,255,82.548065,277.97742||255,0,0,255,116.50179,258.91876||255,0,0,255,152.63605,240.7898||255,0,0,255,209.95244,215.68816||255,0,0,255,239.23363,199.41858||255,0,0,255,249.8247,192.4459||255,0,0,255,261.35028,186.86777||255,0,0,255,261.9733,186.86777||255,0,0,255,261.9733,186.86777||255,0,0,255,50.77485,53.92204||255,0,0,255,50.77485,53.92204||255,0,0,255,50.77485,53.92204||255,0,0,255,50.77485,53.92204||255,0,0,255,48.905834,62.7541||255,0,0,255,39.56077,133.87541||255,0,0,255,44.856304,185.93808||255,0,0,255,53.578365,266.82114||255,0,0,255,53.578365,287.27435||255,0,0,255,51.70935,301.6845||255,0,0,255,51.39785,303.07904||255,0,0,255,51.086346,303.5439||255,0,0,255,51.086346,303.5439||255,0,0,255,90.02411,362.57922||255,0,0,255,88.155106,355.14172||255,0,0,255,109.02575,317.0244||255,0,0,255,133.01141,323.53226||255,0,0,255,155.43958,340.26666||255,0,0,255,166.65363,344.91513||255,0,0,255,185.03226,338.4073||255,0,0,255,193.13133,326.78616||255,0,0,255,210.26395,292.38763||255,0,0,255,228.01956,296.10638||255,0,0,255,259.7928,283.09073||255,0,0,255,266.33432,263.5672||255,0,0,255,267.58032,258.91876||255,0,0,255,269.76086,256.1297||255,0,0,255,271.94138,255.20001||255,0,0,255,284.71295,248.22733||255,0,0,255,294.3695,232.42259||255,0,0,255,297.48453,212.8991||255,0,0,255,297.48453,212.8991||255,0,0,255,101.86119,202.67252||255,0,0,255,101.86119,202.67252||255,0,0,255,101.86119,202.67252||255,0,0,255,113.07527,194.77013||255,0,0,255,141.73346,178.9654||255,0,0,255,144.8485,179.43024||255,0,0,255,166.96513,192.4459||255,0,0,255,170.70317,195.23497||255,0,0,255,193.75432,195.69983||255,0,0,255,201.85338,185.93808||255,0,0,255,212.75597,146.42624||255,0,0,255,217.4285,136.19965||255,0,0,255,231.44609,135.26996||255,0,0,255,241.41415,136.66449||255,0,0,255,250.13622,136.19965||255,0,0,255,279.41742,128.76212||255,0,0,255,312.12512,100.406555||255,0,0,255,312.12512,100.406555||255,0,0,255,92.20462,52.527508||255,0,0,255,92.20462,52.527508||255,0,0,255,159.48909,44.160294||255,0,0,255,186.90128,34.398544||255,0,0,255,242.97165,20.918034||255,0,0,255,269.13785,13.48051||255,0,0,255,288.76245,11.62113||255,0,0,255,288.76245,11.62113,"; StringTokenizer tokens = new StringTokenizer(parseStr, "||"); while(tokens.hasMoreTokens()) { String second = tokens.nextToken(); StringTokenizer tempTokens = new StringTokenizer(second, ","); int index = 0; while(tempTokens.hasMoreTokens()) { String splitStr = tempTokens.nextToken(); switch (index%6) { case 0: rArray.add(splitStr); break; case 1: gArray.add(splitStr); break; case 2: bArray.add(splitStr); break; case 3: alphaArray.add(splitStr); break; case 4: xPointArray.add(splitStr); break; case 5: yPointArray.add(splitStr); break; default: break; } index++; Log.v("String44"," value = "+splitStr); } } m.redraw(); } public void colorChanged(int color) { mPaint.setColor(color); //method to convert integer color to rgba b = (color)&0xFF; g = (color>>8)&0xFF; r = (color>>16)&0xFF; a = Math.round(((color>>>24)/255)*10); } public class MyView extends View { private Bitmap mBitmap; private Canvas mCanvas; public Path mPath; public Paint mBitmapPaint; public MyView(Context c) { super(c); // reading screen size (for device Independence) DisplayMetrics displaymetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); mBitmap = Bitmap.createBitmap(displaymetrics.widthPixels,displaymetrics.heightPixels, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); mPath = new Path(); mBitmapPaint = new Paint(Paint.DITHER_FLAG); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { //background -- White canvas.drawColor(0xFFFFFFFF); //draw the bitmap from 0,0 the firstpoint in device screen canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); canvas.drawPath(mPath, mPaint); } public void touch_start(float x, float y) { //reset touch so that a new path is to be drawn mPath.reset(); mPath.moveTo(x, y); mX = x; mY = y; } public void touch_move(float x, float y) { mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); //point tracing tracePoints((int)x, (int)y,(int)mX,(int)mY); mX = x; mY = y; } public void touch_up() { mPath.lineTo(mX, mY); // commit the path to our offscreen mCanvas.drawPath(mPath, mPaint); // kill this so we don't double draw mPath.reset(); } public void arrayPopulate(float atx,float aty){ if(eraseFlag==false){ //entering points into arrayLists xPointArray.add(""+atx); yPointArray.add(""+aty); //add color as well alphaArray.add(""+a); rArray.add(""+r); gArray.add(""+g); bArray.add(""+b); // if(toSend==null){ // toSend=""+r+","+g+","+b+","+a+","+atx+","+aty+"||"; // } // else{ // toSend+=""+r+","+g+","+b+","+a+","+atx+","+aty+"||"; // } //add data to a queue for sending to server // Log.v("touch", toSend); //send data here to server //eraseFlag is true ends } } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touch_start(x, y); arrayPopulate(x, y); invalidate(); break; case MotionEvent.ACTION_MOVE: touch_move(x, y); invalidate(); break; case MotionEvent.ACTION_UP: touch_up(); arrayPopulate(x, y); invalidate(); break; } return true; } public void redraw() { int arraysize = FingerPaint.rArray.size(); int index=0; float xx,yy; //setting properties of tPaint Paint tPaint= new Paint(); tPaint.setAntiAlias(true); tPaint.setDither(true); tPaint.setStyle(Paint.Style.STROKE); tPaint.setStrokeJoin(Paint.Join.ROUND); tPaint.setStrokeCap(Paint.Cap.ROUND); tPaint.setColor(-16777216); tPaint.setStrokeWidth(12); while(index<arraysize){ //tPaint.setARGB(Integer.parseInt(alphaArray.get(0)), Integer.parseInt(rArray.get(0)), Integer.parseInt(gArray.get(0)), Integer.parseInt(bArray.get(0))); //tPaint.setColor(Color.argb(Integer.parseInt(alphaArray.get(0)), Integer.parseInt(rArray.get(0)), Integer.parseInt(gArray.get(0)), Integer.parseInt(bArray.get(0)))); xx=Float.parseFloat(xPointArray.get(index)); yy=Float.parseFloat(yPointArray.get(index)); m.mCanvas.drawPoint(xx,yy,tPaint); m.invalidate(); index++; Log.d("__REDRAW__", "X="+xx+" Y="+yy); } } } //creating Options Menu - Inflater @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } //Option Menu Selection - Actions @Override public boolean onOptionsItemSelected(MenuItem item) { mPaint.setXfermode(null); mPaint.setAlpha(255); switch (item.getItemId()) { case R.id.COLOR: this.eraseFlag=false; new ColorPickerDialog(this, this, mPaint.getColor()).show(); return true; case R.id.EMBOSS: this.eraseFlag=false; if (mPaint.getMaskFilter() != mEmboss) { mPaint.setMaskFilter(mEmboss); } else { mPaint.setMaskFilter(null); } return true; case R.id.BLUR: this.eraseFlag=false; if (mPaint.getMaskFilter() != mBlur) { mPaint.setMaskFilter(mBlur); } else { mPaint.setMaskFilter(null); } return true; case R.id.ERASE: //for toggle detection this.eraseFlag=true; //reset blurr & Emboss mPaint.setMaskFilter(null); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); return true; case R.id.REDRAW: this.eraseFlag=false; //redraw the drawn points m.redraw(); return true; } return super.onOptionsItemSelected(item); } //Bressenham mid-point algorithm for finding all points between any two points --- Straight line public void tracePoints(int xxx,int yyy,int x2, int y2) { int w = x2 - xxx ; int h = y2 - yyy ; int dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0 ; if (w<0) dx1 = -1 ; else if (w>0) dx1 = 1 ; if (h<0) dy1 = -1 ; else if (h>0) dy1 = 1 ; if (w<0) dx2 = -1 ; else if (w>0) dx2 = 1 ; int longest = Math.abs(w) ; int shortest = Math.abs(h) ; if (!(longest>shortest)) { longest = Math.abs(h) ; shortest = Math.abs(w) ; if (h<0) dy2 = -1 ; else if (h>0) dy2 = 1 ; dx2 = 0 ; } int numerator = longest >> 1 ; for (int i=0;i<=longest;i++) { m.arrayPopulate((float)xxx,(float)yyy) ; numerator += shortest ; if (!(numerator<longest)) { numerator -= longest ; xxx += dx1 ; yyy += dy1 ; } else { xxx += dx2 ; yyy += dy2 ; } } } } 
+4
source share
9 answers

Try using the following code. Hope this solves your problem. When I draw, I get all the glasses perfectly, regardless of whether I draw slowly or fast.

 public class HRCanvas extends Activity implements OnTouchListener{ DrawPanel dp; private ArrayList<Path> pointsToDraw = new ArrayList<Path>(); private Paint mPaint; Path path; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); dp = new DrawPanel(this); dp.setOnTouchListener(this); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); requestWindowFeature(Window.FEATURE_NO_TITLE); mPaint = new Paint(); mPaint.setDither(true); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(30); FrameLayout fl = new FrameLayout(this); fl.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); fl.addView(dp); setContentView(fl); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); dp.pause(); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); dp.resume(); } public class DrawPanel extends SurfaceView implements Runnable{ Thread t = null; SurfaceHolder holder; boolean isItOk = false ; public DrawPanel(Context context) { super(context); // TODO Auto-generated constructor stub holder = getHolder(); } @Override public void run() { // TODO Auto-generated method stub while( isItOk == true){ if(!holder.getSurface().isValid()){ continue; } Canvas c = holder.lockCanvas(); c.drawARGB(255, 0, 0, 0); onDraw(c); holder.unlockCanvasAndPost(c); } } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); synchronized(pointsToDraw) { for (Path path : pointsToDraw) { canvas.drawPath(path, mPaint); } } } public void pause(){ isItOk = false; while(true){ try{ t.join(); }catch(InterruptedException e){ e.printStackTrace(); } break; } t = null; } public void resume(){ isItOk = true; t = new Thread(this); t.start(); } } @Override public boolean onTouch(View v, MotionEvent me) { // TODO Auto-generated method stub synchronized(pointsToDraw) { if(me.getAction() == MotionEvent.ACTION_DOWN){ path = new Path(); path.moveTo(me.getX(), me.getY()); //path.lineTo(me.getX(), me.getY()); pointsToDraw.add(path); }else if(me.getAction() == MotionEvent.ACTION_MOVE){ path.lineTo(me.getX(), me.getY()); }else if(me.getAction() == MotionEvent.ACTION_UP){ //path.lineTo(me.getX(), me.getY()); } } return true; } } 
+1
source

You need to interpolate to find points between updates. I recommend cosine interpolation. It is easy to implement, gives decent results and inexpensively computationally.

 public double cosineInterpolation(double x1, double x2, double normal) { double ft = normal * 3.1415927; double f = (1 - Math.cos(ft)) * .5; return x1 * (1 - f) + x2 * f; } 

You will need to call this method twice; once for x and once for y coordinates of two subsequent points.

+1
source

You can solve this using the MATH equation.

Use the linear equation, y = mx + c Put (x1, y1) and (x2, y2) to get two equations and decide to get the values ​​of m and c. (you can find direct equations to get m and c somewhere). Then create a loop to start with x = x1 to x = x2 Using y = mx + c, we get the value of y (now you know m and c)

Hope this helps.

0
source

Replace this code for the touch event ....

  float downx = 0; float downy = 0; float upx = 0; float upy = 0; public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: downx = event.getX(); downy = event.getY(); break; case MotionEvent.ACTION_MOVE: upx = event.getX(); upy = event.getY(); canvas.drawLine(downx, downy, upx, upy, paint); imageView.invalidate(); downx = upx; downy = upy; break; break; case MotionEvent.ACTION_UP: upx = event.getX(); upy = event.getY(); canvas.drawLine(downx, downy, upx, upy, paint); imageView.invalidate(); break; case MotionEvent.ACTION_CANCEL: break; default: break; } return true; } 
0
source

Check out the code . The project is not completed, but the lines are drawn quickly and smoothly on my Atrix. Although it uses quadTo, which sounds like you want to avoid it. What device are you testing with?

0
source

I noticed that you are not calling arrayPopulate(x, y); in the onTouchEvent(MotionEvent event) function in MotionEvent.ACTION_MOVE . Is it possible that you are losing data there?

Is there a reason you are trying to transcode the Path class? If you really need to, you probably have to include Bezier curves and straight lines, and more, if you ever decide to use any other functions , If they use native to execute Bezier curves, you probably want to as well.

0
source

I ran into the same issue as AndroidKid,

Due to the number of background actions, my application cannot record all points of the touch event. My test application captures twenty places for action, since my actual application captures only 5-6 points. So I get an object that looks like a polygon.

As the Android Kid said, when I draw slowly, I get the right curve as the points are written correctly.

In my test application, I had a path object to add points and use canvas.drawPath , which gave me a better result than canvas.drawLine .

Android Kid

Also try if you can compromise sharp edges with smooth curves in your path.

 paint.setPathEffect(new CornerPathEffect(25)); 

In any case, you will be guys!

0
source

I know this question is old, but you can get all the points in the event when the equipment tracks events faster than they are delivered using the event history. Sort of:

 int historySize = event.getHistorySize(); for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); path.lineTo(historicalX, historicalY); } 

A source

0
source

Why don't you just draw it on a bitmap using black and then scroll through all the pixels to get the dots?

  Paint cPaint = new Paint(); cPaint.setAntiAlias(false); cPaint.setColor(0xFF000000); Bitmap topBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas topCanvas = new Canvas(topBitmap); topCanvas.drawColor(0xFFFFFFFF, PorterDuff.Mode.CLEAR); topCanvas.drawPath(mPath, cPaint); for (int x=0; x<w; x++) { for (int y=0; y<h; y++) { if (topBitmap.getPixel(x, y) == 0xFF000000) { // record the point } } } 

In any case, the path will not contain each drawn point. In addition, if an Android device or something similar to a path object also works on another device, you can simply recreate the path there using the points of your movement event.

-1
source

All Articles