2013-12-18 5 views
0

Я использую следующий код, чтобы нарисовать путь на основе изменений ширины переменной на холсте. Пока все работает отлично, и я могу легко рисовать путь с помощью этого кода.Кривые сломаны при рисовании пути в холсте

Но нарисованный путь не является гладким, особенно когда я рисую изогнутый путь, все линии выглядят сломанными. Почему это происходит? Что-то не так в моем коде?

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 implements OnTouchListener 
    { 
     private static final float  STROKE_WIDTH = 3f;  

     private Paint     paint = new Paint(); 

     private Path     mPath = new Path(); 

     ArrayList<Path>     mPaths = new ArrayList<Path>(); 

     private Canvas     m_CanvasView; 

     private Bitmap     m_CanvasBitmap; 

     int        variableWidthDelta = 1; 

     private float     mX, mY; 

     private static final float  TOUCH_TOLERANCE = 4;  

     ArrayList<Point>    points = new ArrayList<Point>(64); 

     public MyView(Context context) 
     { 
      super(context); 
      setFocusable(true); 
      setFocusableInTouchMode(true); 
      this.setOnTouchListener(this); 

      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); 
     } 

     @Override 
     protected void onSizeChanged(int w, int h, int oldw, int oldh) 
     { 
      super.onSizeChanged(w, h, oldw, oldh); 

      m_CanvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
      m_CanvasView = new Canvas(m_CanvasBitmap); 
     } 

     @Override 
     protected void onDraw(Canvas canvas) 
     { 
      canvas.drawBitmap(m_CanvasBitmap, 0f, 0f, null);    
      m_CanvasView.drawPath(mPath, paint);  
     } 

     public boolean onTouch(View arg0, MotionEvent event) 
     { 
      float x = event.getX(); 
      float y = event.getY(); 

      switch (event.getAction()) 
      { 
       case MotionEvent.ACTION_DOWN: 
       {   
        mPath.reset(); 
        mPath.moveTo(x, y); 
        mX = x; 
        mY = y; 
        break; 
       } 
       case MotionEvent.ACTION_MOVE: 
       {       
        if (event.getPressure()>=0.00 && event.getPressure()<0.05) 
        { 
         variableWidthDelta = 1; 
        } 
        else if (event.getPressure()>=0.05 && event.getPressure()<0.10) 
        { 
         variableWidthDelta = 1; 
        } 
        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 = 1; 
        } 
        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 = 2; 
        } 
        else if (event.getPressure() >= 0.40 && event.getPressure()<0.45) 
        { 
         variableWidthDelta = 3; 
        } 
        else if (event.getPressure() >= 0.45 && event.getPressure()<0.50) 
        { 
         variableWidthDelta = 4; 
        }     

        paint.setStrokeWidth(STROKE_WIDTH + variableWidthDelta); 

        float dx = Math.abs(x - mX); 
        float dy = Math.abs(y - mY); 

        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) 
        {   
         points.add(new Point(event.getX(), event.getY())); 
         mPath = new Path(); 

         mPath = generatePath();                                  
        } 

        break; 
       } 
       case MotionEvent.ACTION_UP: 
       { 
        break; 
       } 
      } 

      invalidate(); 
      return true; 
     } 

     class Point 
     { 
      public final float x; 
      public final float y; 
      public Point(float x, float y) 
      { 
       this.x = x; 
       this.y = y; 
      } 
     } 

     public Path generatePath() 
     { 
      final float tangentScale = 0.3F; 
      int pointcount = points.size(); 

      mPath.moveTo(points.get(0).x, points.get(0).y); 
      mPath.cubicTo(
        points.get(0).x + (points.get(1).x - points.get(0).x)*tangentScale, 
        points.get(0).y + (points.get(1).y - points.get(0).y)*tangentScale, 
        points.get(1).x - (points.get(2).x - points.get(0).x)*tangentScale, 
        points.get(1).y - (points.get(2).y - points.get(0).y)*tangentScale, 
        points.get(1).x, points.get(1).y 
        ); 
      for(int p=2; p<pointcount-1; p++) 
      { 
       mPath.cubicTo(
         points.get(p-1).x + (points.get(p).x - points.get(p-2).x)*tangentScale, 
         points.get(p-1).y + (points.get(p).y - points.get(p-2).y)*tangentScale, 
         points.get(p).x - (points.get(p+1).x - points.get(p-1).x)*tangentScale, 
         points.get(p ).y - (points.get(p+1).y - points.get(p-1).y)*tangentScale, 
         points.get(p).x, points.get(p).y 
         ); 
      } 
      mPath.cubicTo(
        points.get(pointcount-2).x + (points.get(pointcount-1).x - points.get(pointcount-3).x)*tangentScale, 
        points.get(pointcount-2).y + (points.get(pointcount-1).y - points.get(pointcount-3).y)*tangentScale, 
        points.get(pointcount-1).x - (points.get(pointcount-1).x - points.get(pointcount-2).x)*tangentScale, 
        points.get(pointcount-1).y - (points.get(pointcount-1).y - points.get(pointcount-2).y)*tangentScale, 
        points.get(pointcount-1).x, points.get(pointcount-1).y 
        ); 

      return mPath; 
     } 
    } 
} 

enter image description here

ответ

1

onTouch событие не уволили достаточно быстро, так что если вы рисуете кривые достаточно быстро, вы увидите, что это происходит.

Вы можете улучшить разрешение точки, получив все записанные точки между этим событием onTouch и последним. Используйте event.getHistorySize(), чтобы получить доступное количество баллов, и получите свои вакансии с event.getHistoricalX(int) и event.getHistoricalY(int).

Если у вас все еще есть проблемы, вам, вероятно, придется реализовать некоторую интерполяцию точек. Вот простой пример, используя cubicTo(), чтобы получить плавный путь:
points - это массив всех точек, которые нужно нарисовать.
pointcount это количество точек

//This code is untested 
public Path generatePath(){ 
Path path = new Path(); 
if(points.size() < 3) return path; 
final float tangentScale = 0.3; 

path.moveTo(points[0].x, points[0].y); 
path.cubicTo(
    points[0].x + (points[1].x - points[0].x)*tangentScale, 
    points[0].y + (points[1].y - points[0].y)*tangentScale, 
    points[1].x - (points[2].x - points[0].x)*tangentScale, 
    points[1].y - (points[2].y - points[0].y)*tangentScale, 
    points[1].x, points[1].y 
    ); 
for(int p=2; p<pointcount-1; p++){ 
    path.cubicTo(
     points[p-1].x + (points[p].x - points[p-2].x)*tangentScale, 
     points[p-1].y + (points[p].y - points[p-2].y)*tangentScale, 
     points[p ].x - (points[p+1].x - points[p-1].x)*tangentScale, 
     points[p ].y - (points[p+1].y - points[p-1].y)*tangentScale, 
     points[p].x, points[p].y 
     ); 
} 
path.cubicTo(
    points[pointcount-2].x + (points[pointcount-1].x - points[pointcount-3].x)*tangentScale, 
    points[pointcount-2].y + (points[pointcount-1].y - points[pointcount-3].y)*tangentScale, 
    points[pointcount-1].x - (points[pointcount-1].x - points[pointcount-2].x)*tangentScale, 
    points[pointcount-1].y - (points[pointcount-1].y - points[pointcount-2].y)*tangentScale, 
    points[pointcount-1].x, points[pointcount-1].y 
    ); 
return path; 
} 

Адаптация это для вашего конкретного случая: (Вы должны будете модифицировать вышеупомянутый метод использовать .get() вместо аксессоров массива, так как я использую список здесь)

//A class for holding x and y values: 
class Point{ 
    public final float x; 
    public final float y; 
    public Point(float x, float y){ 
     this.x = x; 
     this.y = y; 
    } 
} 

//In your View: 
ArrayList<Point> points = new ArrayList<Points>(64); 

//In the onTouch-method if the tolerance is ok: 
points.add(new Point(event.getX(), event.GetY()); 
mPath = generatePath(); 

Вышеупомянутый способ будет генерировать округленный путь, который вы можете нарисовать. Обратите внимание, что он использует все точки, поэтому все они будут перерисовываться каждый раз (вам может понадобиться очистить холст, чтобы избежать некоторых артефактов). Возможно, вам захочется переместить generatePath -call, когда вы поднимаете палец, поэтому вы получаете более быстрый, но неровный путь предварительного просмотра во время рисования.

+0

Я делаю некоторые изменения, как вы упоминаете, и да, есть какая-то гладкость в строке, но все же не идеальная. Можете ли вы посмотреть мой отредактированный код, если я что-то пропущу. – AndroidDev

+0

У вас есть возможность увидеть мои изменения. На самом деле я застрял в этом вопросе на прошлой неделе, но могу получить любое правильное решение. – AndroidDev

+0

@Anshuman Попробуйте реализовать некоторую интерполяцию между значениями, я не уверен на 100% о том, как вы оцениваете значения x/HistoricalX. Если этого недостаточно, попробуйте включить аппаратное ускорение, если вы используете уровень API за 10 лет. Также попробуйте оптимизировать ваш код onTouch для повышения скорости. Вы также можете рассмотреть возможность использования второго потока для обработки событий. – Jave

Смежные вопросы