8

Possible Duplicate:
Android How to draw a smooth line following your finger

I'm new to Android and java programming and have been playing around a bit with mobile app development. I recently created a View which simply keeps draws lines in step with the user's finger movements. However, I've been having some trouble with the Canvas.drawLines method.

Instead of getting a continuous set of lines between all points I am getting more of a dashed pattern with breaks between segments:

Broken Line Segments in Canvas.DrawLines

Here is a sample set of data and simple code to reproduce the issue (point data was taken from a real finger swipe):

public class SomeView extends android.view.View 
{
    private float[] _data = { 292.36545f, 104.37576f, 285.3567f, 112.39249f, 274.34293f, 113.39456f, 254.3179f, 115.39874f, 248.3104f, 116.40082f, 228.28535f, 118.405f, 214.26784f, 119.407104f, 211.26408f, 119.407104f, 204.25533f, 120.40918f, 202.25282f, 120.40918f, 201.25157f, 121.411255f, 199.24907f, 124.41754f, 197.24657f, 125.41962f, 196.24532f, 130.43005f, 195.24406f, 139.44885f, 197.24657f, 144.45929f };
    private Paint _paint;

    public SomeView( Context c, AttributeSet attrs)
    {
        super( c, attrs );
        _paint = new Paint();
        _paint.setColor(Color.BLUE);
        _paint.setStrokeWidth(6);   
    }   

    @Override
    public void onDraw(Canvas canvas)
    {       
        canvas.drawLines( _data, _paint);
    }           
}

After plotting out each point and overlaying it atop the line I realized that the problem is actually that each point is not being connected, only every two points. Instead of connecting point 1 to point 2 to point 3 and so on, the method is connecting 1 to 2 and then 3 to 4 as shown below:

enter image description here

I can almost get what I want by drawing calling drawLines again and providing an offset this time so that the other pairs are drawn together as well, but this seems inefficient and generally clunky to me, and the line still isn't completely smooth (gets slightly choppy on corners).

So, my question is; what am I doing wrong and how can I draw a simple, smooth line given some number of points? Heck, forget the points, if there is a better way to trace the user's finger with a line I am all ears. Thanks in advance.

Community
  • 1
  • 1
Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • I came across this answer on a very simpiliar question.. hope it helps. http://stackoverflow.com/a/8288264/2034243 – user2034243 Feb 03 '13 at 06:01

2 Answers2

13

What you get is exactly what is specified in the drawLines documentation.

One way of doing what you want would be to construct a Path from that data, and use drawPath rather than drawLines. Something like:

Path _path = new Path();
_path.moveTo(_data[0], _data[1]);
for (int i=2; i<_data.length; i+=2) {
  _path.lineTo(_data[i], _data[i+1]);
}

Then draw it with:

_canvas.drawPath(_path, _paint)

From the Path docs:

The Path class encapsulates compound (multiple contour) geometric paths consisting of straight line segments, quadratic curves, and cubic curves. It can be drawn with canvas.drawPath(path, paint), either filled or stroked (based on the paint's Style)

So you might have to change you're paint's style to get the right effect.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • You know, I read the documentation before I posted this... at three in the morning... and it didn't click for whatever reason... Thanks a lot, I'll try to get more sleep =D – Ed S. May 29 '11 at 17:43
  • Unfortunately this doesn't actually work as the path will fill areas between points and I need to draw a line. I'll keep hunting... – Ed S. May 29 '11 at 19:01
  • @Ed S.: updated my answer. see examples [here](http://bestsiteinthemultiverse.com/2008/11/android-graphics-example/) – Mat May 29 '11 at 19:07
  • And that did the trick sir, thank you again. I feel like such a beginner again... fun and frustrating all at the same time =). – Ed S. May 29 '11 at 19:14
  • You're better off not making a path. You're going to alter this stuff a lot very likely and paths are kind of expensive. You're better off just calling the drawlines routine twice, and saving memory. if (count >= 4) { if ((count & 2) != 0) { canvas.drawLines(pointlist, 0, count-2, paint); canvas.drawLines(pointlist, 2, count-2, paint); } else { canvas.drawLines(pointlist, 0, count, paint); canvas.drawLines(pointlist, 2, count - 4, paint); } } – Tatarize Sep 10 '15 at 09:10
4

I just ran into this issue tonight. For anyone else facing this, the problem is that Android doesn't draw from point 1 to point 2, then point 2 to point 3, point 3 to point 4, etc. It will draw point 1 to 2, then point 3 to 4, etc. So you can also push the previous point twice into whatever data structure you use (I used Vector). So:

private Vector<Float> mPoints = new Vector<Float>();
private float mLastX = Float.NaN;
private float mLastY = Float.NaN;

public void addPoint(float x, float y) {
    if (mLastX == Float.NaN || mLastY == Float.NaN) {
        mLastX = x;
        mLastY = y;
    } else {
        mPoints.add(mLastX);
        mPoints.add(mLastY);
        mPoints.add(x);
        mPoints.add(y);

        mLastX = x;
        mLastY = y;
    }
}

Then just make sure to convert your mPoints to a float[] and pass that to canvas.drawLines().

MCLLC
  • 496
  • 4
  • 12
  • 1
    You can just use the same array twice. int size = pack.length; canvas.drawLines(pack,0,size,linePaint); canvas.drawLines(pack,2,size-2,linePaint); Just give an offset of 2. So the second one draws the missing ones. – Tatarize Feb 16 '15 at 18:13
  • i did so and my path just disappeared :( – Ana Feb 18 '16 at 13:49