Java – how to smooth the paint path when painting with variable width strokes

I created a sample drawing application. Users can draw with variable width strokes. So far, the drawing path of variable strokes is working, but the drawn lines are not smooth. The code I used to implement is as follows

Help me solve this problem, because I have insisted on it in the last two days

Code for drawing paths with variable stroke width

public class FingerPaint extends GraphicsActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }

    public void colorChanged(int color)  {
    }

    public class MyView extends View {

        private static final float stroke_WIDTH = 5f;    
        private Paint paint = new Paint();
        private Path mPath = new Path();
        ArrayList<Path> mPaths = new ArrayList<Path>();
        ArrayList<Integer> mstrokes = new ArrayList<Integer>();

        private float lastTouchX;
        private float lastTouchY;
        private final RectF dirtyRect = new RectF();
        private int laststroke = -1;
        int variableWidthDelta = 0;

        private static final float stroke_DELTA = 0.0001f; // for float comparison
        private static final float stroke_INCREMENT = 0.01f; // amount to interpolate
        private float currentstroke = stroke_WIDTH;
        private float targetstroke = stroke_WIDTH;

        private float mX, mY;
        private static final float TOUCH_TOLERANCE = 4;

        public MyView(Context context)  {
            super(context);

            paint.setAntiAlias(true);
            paint.setDither(true);
            paint.setStyle(Paint.Style.stroke);
            paint.setstrokeJoin(Paint.Join.ROUND);
            paint.setstrokeCap(Paint.Cap.ROUND);    
            paint.setstrokeWidth(stroke_WIDTH);
        }

        public void clear() {
            mPath.reset();
            // Repaints the entire view.
            invalidate();
        }

        @Override
        protected void onDraw(Canvas canvas)  {
            for(int i=0; i<mPaths.size();i++) {
                paint.setstrokeWidth(mstrokes.get(i));
                canvas.drawPath(mPaths.get(i), paint);
            }
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float eventX = event.getX();
            float eventY = event.getY();
            int historySize = event.getHistorySize();

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    resetDirtyRect(eventX, eventY);
//                  mPath.reset();
                    mPath.moveTo(eventX, eventY);
                    mX = eventX;
                    mY = eventY;
                    break;                  
                }
                case MotionEvent.ACTION_MOVE: {                 
                    if (event.getPressure()>=0.00 && event.getPressure()<0.05) {
                        variableWidthDelta = -2;
                    } else if (event.getPressure()>=0.05 && event.getPressure()<0.10) {
                        variableWidthDelta = -2;
                    } else if (event.getPressure()>=0.10 && event.getPressure()<0.15) {
                        variableWidthDelta = -2;
                    } else if (event.getPressure()>=0.15 && event.getPressure()<0.20) {
                        variableWidthDelta = -2;
                    } else if (event.getPressure()>=0.20 && event.getPressure()<0.25) {
                        variableWidthDelta = -2;
                    } else if (event.getPressure() >= 0.25 && event.getPressure()<0.30) {
                        variableWidthDelta = 1;
                    } else if (event.getPressure() >= 0.30 && event.getPressure()<0.35) {
                        variableWidthDelta = 2;
                    } else if (event.getPressure() >= 0.35 && event.getPressure()<0.40) {
                        variableWidthDelta = 3;
                    } else if (event.getPressure() >= 0.40 && event.getPressure()<0.45) {
                        variableWidthDelta = 4;
                    } else if (event.getPressure() >= 0.45 && event.getPressure()<0.60) {
                        variableWidthDelta = 5;
                    }                                          

                    // if current not roughly equal to target
                    if( Math.abs(targetstroke - currentstroke) > stroke_DELTA ) 
                    {
                        // move towards target by the increment
                        if( targetstroke > currentstroke)
                        {
                            currentstroke = Math.min(targetstroke, currentstroke + stroke_INCREMENT);
                        }
                        else
                        {
                            currentstroke = Math.max(targetstroke, currentstroke - stroke_INCREMENT);
                        }

                    } 
                    mstrokes.add((int) currentstroke);

                    targetstroke = variableWidthDelta;

                    float dx = Math.abs(eventX - mX);
                    float dy = Math.abs(eventY - mY);

                    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                        if(laststroke != variableWidthDelta) {
                            mPath.lineTo(mX, mY);

                            mPath = new Path();
                            mPath.moveTo(mX,mY);
                            mPaths.add(mPath);
                        }

                        mPath.quadTo(mX, mY, (eventX + mX)/2, (eventY + mY)/2);
                        mX = eventX;
                        mY = eventY;
                    }

                    for (int i = 0; i < historySize; i++) {
                        float historicalX = event.getHistoricalX(i);
                        float historicalY = event.getHistoricalY(i);
                        expandDirtyRect(historicalX, historicalY);
                    }
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    for (int i = 0; i < historySize; i++) {
                        float historicalX = event.getHistoricalX(i);
                        float historicalY = event.getHistoricalY(i);
                        expandDirtyRect(historicalX, historicalY);
                    }
                   mPath.lineTo(mX, mY);                   
                   break;
                }
            }

            // Include half the stroke width to avoid clipping.
            invalidate();

            lastTouchX = eventX;
            lastTouchY = eventY;
            laststroke = variableWidthDelta;

            return true;
        }

        private void expandDirtyRect(float historicalX, float historicalY) {
            if (historicalX < dirtyRect.left) {
                dirtyRect.left = historicalX;
            }  else if (historicalX > dirtyRect.right) {
                dirtyRect.right = historicalX;
            }
            if (historicalY < dirtyRect.top) {
                dirtyRect.top = historicalY;
            } else if (historicalY > dirtyRect.bottom) {
                dirtyRect.bottom = historicalY;
            }
        }

        /**
         * Resets the dirty region when the motion event occurs.
         */
        private void resetDirtyRect(float eventX, float eventY) {
            // The lastTouchX and lastTouchY were set when the ACTION_DOWN
            // motion event occurred.
            dirtyRect.left = Math.min(lastTouchX, eventX);
            dirtyRect.right = Math.max(lastTouchX, eventX);
            dirtyRect.top = Math.min(lastTouchY, eventY);
            dirtyRect.bottom = Math.max(lastTouchY, eventY);
        }
    }
}

The output I get

The output I want to achieve

resolvent:

When you detect a change, you can set the target and insert the target until it is reached, instead of immediately jumping to the new stroke width. Your mstrokes need to be floats instead of integers

private static final float stroke_DELTA = 0.0001f; // for float comparison
private static final float stroke_INCREMENT = 0.01f; // amount to interpolate
private float currentstroke = stroke_WIDTH;
private float targetstroke = stroke_WIDTH;

Where you currently create a new path for the new stroke width:

// if current not roughly equal to target
if( Math.abs(targetstroke - currentstroke) > stroke_DELTA ) {
    // move towards target by the increment
    if( targetstroke > currentstroke )
        currentstroke = Math.min(targetstroke, currentstroke + stroke_INCREMENT);
    else
        currentstroke = Math.max(targetstroke, currentstroke - stroke_INCREMENT);
    mPath.lineTo(mX, mY);

    mPath = new Path();
    mPath.moveTo(mX,mY);
    mPaths.add(mPath);
    mstrokes.add(currentstroke);
}

You will update targetstroke. For the current setting of variablewidthdelta

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>