5

I am trying to implement a simple drawable view. Right now I am using Path's quadTo method to draw a smooth line.

And the result like this : enter image description here

I don't know how can draw a line small gradually when user move his finger fast. The same with this example : enter image description here

Do you know how can I get this result ? (any way, engine or open source). Right now, I am thinking about implement my own "quadTo" method. But I think it is gonna be slow (or it over my ability). Because it is a native method on Android SDK.

Thank you for any help.

this is my implement for my simple drawable view for anyone who need it:

public class TestView extends LinearLayout{

private static final String TAG = "TestView";
private PointF previousPoint;
private PointF startPoint;
private PointF currentPoint;
private static final float STROKE_WIDTH = 5f;

private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;

private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint paintBm = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap bmp;
private Canvas canvasBmp;
private Path path;
private int paintSize = 25;

public TestView(Context context, AttributeSet attrs) {
    super(context, attrs);

    this.setWillNotDraw(false);
    paint.setAntiAlias(true);

    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStrokeWidth(STROKE_WIDTH);
    paint.setColor(Color.BLACK);
    //paint.setAlpha(100);

    paintBm.setAntiAlias(true);

    paintBm.setStyle(Paint.Style.STROKE);
    paintBm.setStrokeJoin(Paint.Join.ROUND);
    paintBm.setStrokeCap(Paint.Cap.ROUND);
    paintBm.setStrokeWidth(STROKE_WIDTH);
    paintBm.setColor(Color.BLACK);
    paintBm.setAlpha(100);
    path = new Path();
    //paint.setPathEffect(new CornerPathEffect(2));
}

public TestView(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
    paint.setAntiAlias(true);

    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStrokeWidth(STROKE_WIDTH);
    paint.setColor(Color.BLACK);

    path = new Path();
    //paint.setPathEffect(new CornerPathEffect(2));
}



@Override
protected void onLayout(boolean changed, int left, int top, int right,
        int bottom) {
    // TODO Auto-generated method stub
    super.onLayout(changed, left, top, right, bottom);
    if(bmp == null){
        bmp = Bitmap.createBitmap(right-left,bottom-top,Bitmap.Config.ARGB_8888);
        canvasBmp = new Canvas(bmp);

    }
}
@Override
public boolean onTouchEvent(MotionEvent event) {
    //printSamples(event);
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        currentPoint = new PointF(event.getX(), event.getY());
        previousPoint = currentPoint;
        startPoint = previousPoint;
        path.reset();
        break;

    case MotionEvent.ACTION_MOVE:
        startPoint = previousPoint;
        previousPoint = currentPoint;
        currentPoint = new PointF(event.getX(), event.getY());
        int historySize = event.getHistorySize();
        for(int i = 0; i < historySize; i++){

        }



        drawLine(canvasBmp, path, paint, previousPoint, currentPoint);
        //path.moveTo(currentPoint.x, currentPoint.y);
        break;
    case MotionEvent.ACTION_UP:
        startPoint = previousPoint;
        previousPoint = currentPoint;
        currentPoint = new PointF(event.getX(), event.getY());
        drawLine(canvasBmp, path, paint, previousPoint, currentPoint);
        paintSize = 25;
        break;
    default:
        break;
    }

    invalidate();
    return true;// super.onTouchEvent(event);
}


@Override
protected void onDraw(Canvas canvas) {
    Log.v("pichan", "dasd");
    //canvas.drawBitmap(bmp, 0,0, null);
    //canvas.drawColor(Color.BLUE);
    //canvas.drawPath(path, paint); 
    canvas.drawBitmap(bmp, 0, 0, paintBm);

}





private void drawLine(Canvas canvas, Path path, Paint paint, PointF start, PointF end)
{
    PointF mid1 = midPoint(previousPoint, startPoint);
    PointF mid2 = midPoint(end, start);

    path.reset();
    paint.setStrokeWidth(paintSize);
    path.moveTo(mid1.x, mid1.y);
    path.quadTo(previousPoint.x, previousPoint.y, mid2.x, mid2.y);
    canvas.drawPath(path, paint);
    //canvas.
    //paintSize -= 1;
}

private PointF  midPoint(PointF p1, PointF p2)
{
    return new PointF((p1.x + p2.x) / 2.0f ,  (p1.y + p2.y) * 0.5f);
}

}
gZerone
  • 673
  • 12
  • 28
  • I used your logic to draw smooth line and yep its working nicely, but in my case the path are drawn using variable width and to achieve that i detect pressure from the motion event and based on pressure applied by the user direct stylus, I am changing the paint stroke width, Everything works fine using your logic, but sometimes the path drawn is not joint properly. can u please check whats wrong in my code http://pastebin.com/niDbXf29. – AndroidDev Dec 30 '13 at 07:36
  • it's a good idea, I am busy now. I 'll check it to night. Hope I can help – gZerone Dec 31 '13 at 09:01
  • Ok..no probs. Check the screenshots also. So that you will able to know what actually wrong in my code http://imageshack.us/photo/my-images/28/4o3t.png/ – AndroidDev Dec 31 '13 at 09:21
  • Hi @Anshuman. I checked your solution and your problem. I think with your solution the line could not be smooth. Because the distance between events(MotionEvent) are different. If your finger move quickly, the distance will be longer and reverse. Example we have three points : p1, p2, p3. The distance between p1-> p2 = 5, and the stroke size is 10. And the distance from p2->p3 = 10 and the stroke size is 20. => the lines could not be smooth. – gZerone Jan 02 '14 at 08:41
  • Actually in my case, based on different pressure value i am setting strokeWidth value to my paint object, In my case lines drawn are smooth, but while drawing a line whenever pressure value varies, then the joining point between the thin and thick line drawn based on pressure looks like it overlap with one another. So is there a way to solve that issue. Send you the new screenshot to show u the actual error http://imageshack.com/a/img132/7016/8y0v.png – AndroidDev Jan 02 '14 at 10:07
  • I understood what's your problem. I faced the problem before. And the only way that I can think is you have to build your own drawline method (in my case is "quadTo" method). When you implement your own drawline method, you can change the strokeWidth when you drawing the point between the thin and thick line drawn. – gZerone Jan 03 '14 at 02:57
  • After lot of trial and error i am able to bring smoothness in the drawing, My next step is to calculate the Stroke width based on the speed and pressure of the motion event, and whatever stroke width i got i need to set it on the paint object, I got one link which do that thing but they gave very little demonstration for calculating the stroke width. Can u please check the link and tell me how they calculate the Stroke width based on pressure and speed.http://corner.squareup.com/2012/07/smoother-signatures.html. Check the variable width concept there. – AndroidDev Jan 07 '14 at 09:26
  • hi @AndroidDev. I checked the link. They calculate the Stroke width based on the speed(not pressure). As you can see here : public float velocityFrom(Point start) { return distanceTo(start) / (this.time - start.time); } They calculate the velocity(speed) by device the distance between two points to the period of time. You can get the distance follow http://stackoverflow.com/questions/929773/calculating-the-distance-between-two-points. – gZerone Jan 09 '14 at 03:13
  • Then next step is filtering : // A simple lowpass filter to mitigate velocity aberrations. velocity = VELOCITY_FILTER_WEIGHT * velocity + (1 - VELOCITY_FILTER_WEIGHT) * lastVelocity; From the final velocity value, you can get the stroke value by "strokeWidth()" method (you have to write your own strokeWidth() method). The bigger velocity value, the smaller strokeWidth value. – gZerone Jan 09 '14 at 03:14
  • Can you share the sample if you have to draw smoothly @gZerone – Karthikkumar Dec 16 '20 at 10:28

1 Answers1

6

After time researching, I build a SignView which let user sign on or draw and the result will be save to an image file.

Anyone interested in can take a look here: SignView

Hoping this custom view can save someone time.

gZerone
  • 673
  • 12
  • 28