2014-01-28 23 views
1

我試圖通過使用bezier類的以下鏈接捕獲數字簽名。使用bezier時的簽名捕獲缺陷

http://corner.squareup.com/2010/07/smooth-signatures.html

http://corner.squareup.com/2012/07/smoother-signatures.html

我能能正確繪製簽名時,簽名是沒有擡起手指。但是,當我擡起手指並再次開始簽名時,它會畫出一條連接前一點和新點的線。 enter image description here

在上圖中,我放了5個點。但不是從第一個點到另一個點畫一條線。

Bezier.java

public class Bezier { 
private Point controlPointOne; 
private Point controlPointTwo; 
private int drawSteps; 
private Point endPoint; 
private int mColor; 
private Point startPoint;` 


public Bezier() { 
} 
public Bezier(Point paramPoint1, Point paramPoint2, Point paramPoint3, 
     Point paramPoint4) { 
    this.startPoint = paramPoint1; 
    this.controlPointOne = paramPoint2; 
    this.controlPointTwo = paramPoint3; 
    this.endPoint = paramPoint4; 
    this.drawSteps = ((int) (paramPoint1.distanceTo(paramPoint2) 
      + paramPoint2.distanceTo(paramPoint3) + paramPoint3 
      .distanceTo(paramPoint4))); 
} 

public void draw(Canvas canvas, Paint paint, float startWidth, float endWidth) { 
    float originalWidth = paint.getStrokeWidth(); 
    float widthDelta = endWidth - startWidth; 

    for (int i = 0; i < drawSteps; i++) { 
     float t = ((float) i)/drawSteps; 
     float tt = t * t; 
     float ttt = tt * t; 
     float u = 1 - t; 
     float uu = u * u; 
     float uuu = uu * u; 

     float x = uuu * startPoint.x; 
     x += 3 * uu * t * getControlPointOne().x; 
     x += 3 * u * tt * getControlPointTwo().x; 
     x += ttt * endPoint.x; 

     float y = uuu * startPoint.y; 
     y += 3 * uu * t * getControlPointOne().y; 
     y += 3 * u * tt * getControlPointTwo().y; 
     y += ttt * endPoint.y; 

     paint.setStrokeWidth(startWidth + ttt * widthDelta); 
     canvas.drawPoint(x, y, paint); 
    } 

    paint.setStrokeWidth(originalWidth); 
} 
public int getColor() { 
    return this.mColor; 
} 

public Point getControlPointOne() { 
    return this.controlPointOne; 
} 

public Point getControlPointTwo() { 
    return this.controlPointTwo; 
} 

public int getDrawSteps() { 
    return this.drawSteps; 
} 

public Point getEndPoint() { 
    return this.endPoint; 
} 

public Point getStartPoint() { 
    return this.startPoint; 
} 

public void setColor(int paramInt) { 
    this.mColor = Color.BLACK; 
} 

public void setControlPointOne(Point paramPoint) { 
    this.controlPointOne = paramPoint; 
} 

public void setControlPointTwo(Point paramPoint) { 
    this.controlPointTwo = paramPoint; 
} 

public void setDrawSteps(int paramInt) { 
    this.drawSteps = paramInt; 
} 

public void setEndPoint(Point paramPoint) { 
    this.endPoint = paramPoint; 
} 

public void setStartPoint(Point paramPoint) { 
    this.startPoint = paramPoint; 
} 

}

SignatureView.java

public class SignatureViewDemo extends View { 
    private int color = Color.BLACK; 
    private Bitmap m_Bitmap; 
    private final Paint m_BorderPaint; 
    private Canvas m_Canvas; 
    private Point m_CropBotRight; 
    private Point m_CropTopLeft; 
    private float m_CurrentX; 
    private float m_CurrentY; 
    private final float m_DesiredDash; 
    private float m_LastWidth = 6.5F; 
    private Paint m_PenPaint; 
    private int m_PointIndex = 0; 
    private ArrayList<Point> m_Points = new ArrayList<Point>(); 
    private final float m_StrokeWidth; 
    boolean m_Empty; 



public SignatureViewDemo(Context paramContext) { 

    this(paramContext, null); 
} 

public SignatureViewDemo(Context paramContext, 
     AttributeSet paramAttributeSet) { 
    this(paramContext, paramAttributeSet, 0); 
} 



public SignatureViewDemo(Context paramContext, 
     AttributeSet paramAttributeSet, int paramInt) 

    super(paramContext, paramAttributeSet, paramInt); 
    setFocusable(true); 
    this.m_PenPaint = new Paint(); 
    this.m_PenPaint.setAntiAlias(true); 
    this.m_PenPaint.setColor(Color.BLACK); 
    this.m_PenPaint.setStrokeWidth(5.0F); 
    this.m_PenPaint.setStrokeJoin(Paint.Join.ROUND); 
    this.m_PenPaint.setStrokeCap(Paint.Cap.ROUND); 
    this.m_CurrentY = (0.0F/0.0F); 
    this.m_CurrentX = (0.0F/0.0F); 
    this.m_StrokeWidth = 5.0F; 
    this.m_DesiredDash = 10.0F; 
    this.m_BorderPaint = new Paint(); 
    this.m_BorderPaint.setColor(Color.BLACK); 
    this.m_BorderPaint.setStyle(Paint.Style.STROKE); 
    this.m_BorderPaint.setStrokeWidth(this.m_StrokeWidth); 
} 

public void addBezier(Bezier paramBezier, float paramFloat1, 
     float paramFloat2) { 
    if (this.m_Bitmap == null) { 
     this.m_Bitmap = Bitmap.createBitmap(getWidth(), getHeight(), 
       Bitmap.Config.ARGB_8888); 
     this.m_Canvas = new Canvas(this.m_Bitmap); 
    } 
    paramBezier.draw(this.m_Canvas, this.m_PenPaint, paramFloat1, 
      paramFloat2); 
} 

public void addPoint(Point paramPoint) { 
    if ((paramPoint.getX() < this.m_CropTopLeft.getX()) 
      && (paramPoint.getX() >= 0.0F)) 
     this.m_CropTopLeft.setX(paramPoint.getX()); 
    if ((paramPoint.getY() < this.m_CropTopLeft.getY()) 
      && (paramPoint.getY() >= 0.0F)) 
     this.m_CropTopLeft.setY(paramPoint.getY()); 
    if ((paramPoint.getX() > this.m_CropBotRight.getX()) 
      && (paramPoint.getX() <= this.m_Canvas.getWidth())) 
     this.m_CropBotRight.setX(paramPoint.getX()); 
    if ((paramPoint.getY() > this.m_CropBotRight.getY()) 
      && (paramPoint.getY() <= this.m_Canvas.getHeight())) 
     this.m_CropBotRight.setY(paramPoint.getY()); 
    this.m_Points.add(paramPoint); 
    drawPoints(); 
} 

// public void clear() { 
// if (this.m_Canvas == null) 
// this.m_Canvas.drawColor(0, PorterDuff.Mode.CLEAR); 
// invalidate(); 
// // return; 
// } 

public void clear() { 
    if (this.m_Canvas == null) 
     return; 
    while (m_Empty) { 
     m_Canvas.drawColor(0, PorterDuff.Mode.CLEAR); 
     m_Empty = true; 
     invalidate(); 
     return; 
    } 
} 

public void drawBitmap(Bitmap paramBitmap) { 
    clear(); 
    if ((paramBitmap != null) && (this.m_Canvas != null) 
      && (this.m_Canvas.getWidth() != 0) 
      && (this.m_Canvas.getHeight() != 0)) { 
     Matrix localMatrix = new Matrix(); 
     localMatrix.setRectToRect(
       new RectF(0.0F, 0.0F, paramBitmap.getWidth(), paramBitmap 
         .getHeight()), 
       new RectF(0.0F, 0.0F, this.m_Canvas.getWidth(), 
         this.m_Canvas.getHeight()), 
       Matrix.ScaleToFit.CENTER); 
     this.m_Canvas.drawBitmap(paramBitmap, localMatrix, null); 
     m_Empty = false; 
    } 
    invalidate(); 
} 

public void drawPoints() { 
    if ((m_Points.size() >= 4) 
      && (4 + this.m_PointIndex <= this.m_Points.size())) { 
     Point localPoint1 = (Point) this.m_Points.get(this.m_PointIndex); 
     Point localPoint2 = (Point) this.m_Points 
       .get(1 + this.m_PointIndex); 
     Point localPoint3 = (Point) this.m_Points 
       .get(2 + this.m_PointIndex); 
     Point localPoint4 = (Point) this.m_Points 
       .get(3 + this.m_PointIndex); 
     Bezier localBezier = new Bezier(localPoint1, localPoint2, 
       localPoint3, localPoint4); 
     localBezier.setColor(Color.GREEN); 
     float f = strokeWidth(8.0F/localPoint4.velocityFrom(localPoint1)); 
     addBezier(localBezier, this.m_LastWidth, f); 
     invalidate(); 
     this.m_LastWidth = f; 
     this.m_PointIndex = (3 + this.m_PointIndex); 
     m_Empty = false; 
    } 
} 

public boolean isEmpty() { 
    return m_Empty; 
} 

public Bitmap getBitmap() { 
    return this.m_Bitmap; 
} 

public int getColor() { 
    return this.color; 
} 

protected void onDraw(Canvas paramCanvas) { 
    if (this.m_Bitmap != null) 
     paramCanvas.drawBitmap(this.m_Bitmap, 0.0F, 0.0F, null); 
} 

protected void onMeasure(int paramInt1, int paramInt2) { 
    int i = View.MeasureSpec.getSize(paramInt1); 
    int j = View.MeasureSpec.getSize(paramInt2); 
    this.m_CropTopLeft = new Point(i, j); 
    this.m_CropBotRight = new Point(0.0F, 0.0F); 
    setMeasuredDimension(i, j); 
} 

protected void onSizeChanged(int paramInt1, int paramInt2, int paramInt3, 
     int paramInt4) { 
    Bitmap localBitmap = Bitmap.createBitmap(paramInt1, paramInt2, 
      Bitmap.Config.ARGB_8888); 
    this.m_Canvas = new Canvas(localBitmap); 
    float f1 = 2.0F * (this.m_Canvas.getWidth() + this.m_Canvas.getHeight() - 2.0F * this.m_StrokeWidth); 
    float f2 = f1 
      * this.m_DesiredDash 
      /(Math.round(f1/(4.0F * this.m_DesiredDash)) * (4.0F * this.m_DesiredDash)); 
    Paint localPaint = this.m_BorderPaint; 
    float[] arrayOfFloat = new float[2]; 
    arrayOfFloat[0] = f2; 
    arrayOfFloat[1] = f2; 
    localPaint.setPathEffect(new DashPathEffect(arrayOfFloat, f2/2.0F)); 
    clear(); 
    if (this.m_Bitmap != null) { 
     Rect localRect = new Rect(0, 0, this.m_Canvas.getWidth(), 
       this.m_Canvas.getHeight()); 
     this.m_Canvas.drawBitmap(this.m_Bitmap, null, localRect, null); 
     m_Empty = false; 
    } 
    this.m_Bitmap = localBitmap; 
} 

public boolean onTouchEvent(MotionEvent paramMotionEvent) { 
    int i = 0xFF & paramMotionEvent.getAction(); 
    if (i == 0) { 
     this.m_CurrentX = paramMotionEvent.getX(); 
     this.m_CurrentY = paramMotionEvent.getY(); 
     addPoint(new Point(this.m_CurrentX, this.m_CurrentY, 
       paramMotionEvent.getEventTime())); 
     getParent().requestDisallowInterceptTouchEvent(true); 
    } 
    // while (m_Empty) { 
    if ((i == 1) || (i == 3)) { 
     this.m_CurrentY = (0.0F/0.0F); 
     this.m_CurrentX = (0.0F/0.0F); 
     this.m_Points.clear(); 
     this.m_PointIndex = 0; 
     getParent().requestDisallowInterceptTouchEvent(false); 
    } 
    // if ((this.m_Points.size() < 4) || (4 + this.m_PointIndex > 
    // this.m_Points.size())) 
    // while (1 + this.m_PointIndex <= this.m_Points.size()) 
    drawPoints(); 
    if ((i == 2) || (i == 1)) { 
     for (int j = 0; j < paramMotionEvent.getHistorySize(); j++) 
      addPoint(new Point(paramMotionEvent.getHistoricalX(j), 
        paramMotionEvent.getHistoricalY(j), 
        paramMotionEvent.getHistoricalEventTime(j))); 
     addPoint(new Point(paramMotionEvent.getX(), 
       paramMotionEvent.getY(), paramMotionEvent.getEventTime())); 

    } 
    // } 
    return true; 
} 

public void setColor(int paramInt) { 
    this.color = Color.BLACK; 
} 

public Point getCropBotRight() { 
    return this.m_CropBotRight; 
} 

public Point getCropTopLeft() { 
    return this.m_CropTopLeft; 
} 

// public float strokeWidth(float paramFloat) { 
// if (paramFloat > 11.0F) 
// paramFloat = 10.0F; 
// if (paramFloat < 5.0F) 
// paramFloat = 6.0F; 
// return paramFloat; 
// } 

public float strokeWidth(float paramFloat) { 
    if (paramFloat > 11.0F) 
     paramFloat = 10.0F; 
    while (m_Empty) { 
     if (paramFloat < 5.0F) 
      paramFloat = 6.0F; 
     return paramFloat; 
    } 
    return paramFloat; 
} 

Point.java

public class Point { 

    private long time; 
    float x; 
    float y; 


    public Point(float paramFloat1, float paramFloat2) { 
     this.x = paramFloat1; 
     this.y = paramFloat2; 
    } 

    public Point(float paramFloat1, float paramFloat2, long paramLong) { 
     this.x = paramFloat1; 
     this.y = paramFloat2; 
     this.time = paramLong; 
    } 

    protected float distanceTo(Point paramPoint) { 
     float f1 = this.x - paramPoint.getX(); 
     float f2 = this.y - paramPoint.getY(); 
     return FloatMath.sqrt(f1 * f1 + f2 * f2); 
    } 

    public long getTime() { 
     return this.time; 
    } 

    public float getX() { 
     return this.x; 
    } 

    public float getY() { 
     return this.y; 
    } 

    public void setX(float paramFloat) { 
     this.x = paramFloat; 
    } 

    public void setY(float paramFloat) { 
     this.y = paramFloat; 
    } 

    public float velocityFrom(Point start) { 
     return distanceTo(start)/(this.time - start.time); 
     } 
}   
+0

通過手指速度代碼粘貼代碼 – appukrb

+0

曲線=你根本不想要貝塞爾曲線,你需要Catmull-Rom。他們通過以特定速度穿過點來具體定義。 (兩者都是Hermite曲線,並且可以互相轉換而不會損失精度,但是您真的只是想立即使用Catmull-Rom) –

+0

但是,如示例鏈接所示,當用戶想要簽署兩個單獨的單詞時,不要用一行連接兩個詞。 –

回答

0

在你應該onTouchEvent事件處理程序注意MotionEvent.ACTION_DOWNMotionEvent.ACTION_UP事件,因爲它們標記手勢的開始和結束。

private boolean drawing = false; 

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

    switch (event.getAction()) { 
    case MotionEvent.ACTION_DOWN: 
     // Mark drawing as started 
     drawing = true; 
     path.moveTo(eventX, eventY); 
     return true; 
    case MotionEvent.ACTION_MOVE: 
     // Draw after ACTION_DOWN 
     if (drawing) { 
      path.lineTo(eventX, eventY); 
     } 
     break; 
    case MotionEvent.ACTION_UP: 
     if (drawing) { 
      path.lineTo(eventX, eventY); 
      // Mark drawing as finished 
      drawing = false; 
     } 
     break; 
    default: 
     return false; 
    } 

    if (drawing) { 
     // Schedules a repaint. 
     invalidate(); 
    } 
    return true; 
} 

避免使用命名常量的值併除以零。