手写签名
This commit is contained in:
parent
24ce192f76
commit
08288d205d
@ -4,6 +4,9 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.tenlionsoft.baselib.constant.Constant;
|
||||
import com.tenlionsoft.baselib.utils.LogUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
@ -12,7 +15,7 @@ public abstract class BasePen {
|
||||
/**
|
||||
* 绘制计算的次数,数值越小计算的次数越多
|
||||
*/
|
||||
public static final int STEP_FACTOR = 20;
|
||||
public static final int STEP_FACTOR = 10;
|
||||
|
||||
protected ArrayList<ControllerPoint> mHWPointList = new ArrayList<>();
|
||||
protected ControllerPoint mLastPoint = new ControllerPoint(0, 0);
|
||||
@ -51,7 +54,7 @@ public abstract class BasePen {
|
||||
// event会被下一次事件重用,这里必须生成新的,否则会有问题
|
||||
int action = event.getAction() & event.getActionMasked();
|
||||
MotionEvent event2 = MotionEvent.obtain(event);
|
||||
|
||||
LogUtils.e("绘制"+action);
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
lastId = event2.getPointerId(0);
|
||||
@ -197,6 +200,15 @@ public abstract class BasePen {
|
||||
mHWPointList.clear();
|
||||
}
|
||||
|
||||
public void onDo() {
|
||||
LogUtils.e(mHWPointList.size());
|
||||
if(mHWPointList.size()>0){
|
||||
LogUtils.e(mHWPointList.size());
|
||||
mHWPointList.remove(mHWPointList.size() - 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制
|
||||
* 当现在的点和触摸点的位置在一起的时候不用去绘制
|
||||
|
@ -96,7 +96,7 @@ public class PaintView extends View {
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
//通过压感值来设置画笔的粗细
|
||||
setPaintPressure(event.getPressure());
|
||||
setPaintPressure(event.getPressure(), event.getToolType(event.getActionIndex()));
|
||||
//获取触摸的工具
|
||||
toolType = event.getToolType(event.getActionIndex());
|
||||
// FINGER手指 STYLUS手写笔 MOUSE鼠标
|
||||
@ -133,8 +133,9 @@ public class PaintView extends View {
|
||||
|
||||
/**
|
||||
* 构建Bitmap,用来保存绘制的图
|
||||
* @isCrop 是否清除边界空白
|
||||
*
|
||||
* @return 所绘制的bitmap
|
||||
* @isCrop 是否清除边界空白
|
||||
*/
|
||||
public Bitmap buildAreaBitmap(boolean isCrop) {
|
||||
Bitmap result;
|
||||
@ -150,11 +151,16 @@ public class PaintView extends View {
|
||||
|
||||
/**
|
||||
* 设置压力传感值
|
||||
*
|
||||
* @param pressure
|
||||
*/
|
||||
private void setPaintPressure(float pressure) {
|
||||
private void setPaintPressure(float pressure, int type) {
|
||||
if (mPaint != null) {
|
||||
mPaint.setStrokeWidth(strokeWidth*pressure);
|
||||
if (type == 2) {
|
||||
mPaint.setStrokeWidth(strokeWidth * pressure * 5);
|
||||
} else {
|
||||
mPaint.setStrokeWidth(strokeWidth * pressure);
|
||||
}
|
||||
mStokeBrushPen.setPaint(mPaint);
|
||||
invalidate();
|
||||
}
|
||||
@ -162,6 +168,7 @@ public class PaintView extends View {
|
||||
|
||||
/**
|
||||
* 设置画笔大小
|
||||
*
|
||||
* @param width 大小
|
||||
*/
|
||||
public void setPaintWidth(int width) {
|
||||
@ -176,6 +183,7 @@ public class PaintView extends View {
|
||||
|
||||
/**
|
||||
* 设置画笔颜色
|
||||
*
|
||||
* @param color 颜色
|
||||
*/
|
||||
public void setPaintColor(int color) {
|
||||
@ -200,6 +208,15 @@ public class PaintView extends View {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void onDo(){
|
||||
mStokeBrushPen.onDo();
|
||||
if (mStepOperation != null) {
|
||||
mStepOperation.reset();
|
||||
mStepOperation.addBitmap(mBitmap);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 释放
|
||||
|
@ -4,6 +4,8 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import com.tenlionsoft.baselib.utils.LogUtils;
|
||||
|
||||
public class SteelPen extends BasePen {
|
||||
|
||||
@Override
|
||||
@ -23,6 +25,7 @@ public class SteelPen extends BasePen {
|
||||
ControllerPoint point = mBezier.getPoint(t);
|
||||
mHWPointList.add(point);
|
||||
}
|
||||
LogUtils.e("doMove==" + mHWPointList.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,459 @@
|
||||
package com.tenlionsoft.baselib.core.widget.pens;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Author:Double
|
||||
* Time:2019/4/22
|
||||
* Description:This is DrawingStrokes
|
||||
*/
|
||||
|
||||
public class DrawingStrokes {
|
||||
private final static String TAG = DrawingStrokes.class.getSimpleName();
|
||||
public Paint mPaint;
|
||||
public Vector<TimePoint> myPoints = new Vector<>();
|
||||
public Path strokesPath = null;
|
||||
public float lastLineX;
|
||||
public float lastLineY;
|
||||
|
||||
public float mLastX;
|
||||
public float mLastY;
|
||||
public float mLLastX;
|
||||
public float mLLastY;
|
||||
public Bitmap myBitmap;
|
||||
public Canvas myCanvas;
|
||||
public Vector<TimePoint> mPoint;
|
||||
|
||||
public TimePoint lastTop= new TimePoint();
|
||||
public TimePoint lastBottom=new TimePoint();
|
||||
public boolean isDown = false,isUp = false;
|
||||
public float mLastK = 0;
|
||||
public View strokeView;
|
||||
public Strokes strokes = null;
|
||||
//抬笔和操作笔划时的绘图
|
||||
public Canvas canvasStroke;
|
||||
public Bitmap bitmapStroke;
|
||||
|
||||
public boolean isUnDo = false;
|
||||
public SplineCurveStrategy splineCurveStrategy;
|
||||
|
||||
public int state = -1;
|
||||
public final static int X_ADD_Y_ADD = 0X00;
|
||||
public final static int X_ADD_Y_DEC = 0X01;
|
||||
public final static int X_ADD_Y_SAM = 0X02;
|
||||
public final static int X_DEC_Y_ADD = 0X03;
|
||||
public final static int X_DEC_Y_DEC = 0X04;
|
||||
public final static int X_DEC_Y_SAM = 0X05;
|
||||
public final static int X_SAM_Y_ADD = 0X06;
|
||||
public final static int X_SAM_Y_DEC = 0X07;
|
||||
public final static int X_SAM_Y_SAM = 0X08;
|
||||
public boolean debug = false;
|
||||
public float mLastWidth ;
|
||||
private float width, height;
|
||||
private float maxWidth;
|
||||
private PenType penType;
|
||||
public DrawingStrokes(View strokeView, Strokes strokes){
|
||||
this.strokes = strokes;
|
||||
this.strokeView = strokeView;
|
||||
this.strokesPath = new Path();
|
||||
mPoint = new Vector<>();
|
||||
}
|
||||
public void setSize(float width,float height,Paint mPaint){
|
||||
if (myBitmap != null) return;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
initBitmap();
|
||||
initBitmapStroke();
|
||||
if(this.mPaint == null) {
|
||||
this.mPaint = mPaint;
|
||||
}
|
||||
}
|
||||
public void setPenType(PenType penType) {
|
||||
this.penType = penType;
|
||||
}
|
||||
private void initBitmap(){
|
||||
if(myBitmap == null){
|
||||
myBitmap = Bitmap.createBitmap((int)width,(int)height, Bitmap.Config.ARGB_8888);
|
||||
myCanvas = new Canvas(myBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private void initBitmapStroke(){
|
||||
if(bitmapStroke == null){
|
||||
bitmapStroke = Bitmap.createBitmap((int)width,(int)height, Bitmap.Config.ARGB_8888);
|
||||
canvasStroke = new Canvas(bitmapStroke);
|
||||
}
|
||||
}
|
||||
|
||||
public float strokeWidth(float press,float widthDelta){
|
||||
float width = Math.min(maxWidth , (0.1f * (1 + press * (maxWidth * 10 - 1) ))) * 0.9f + mLastWidth * 0.1f;
|
||||
if(width>mLastWidth)
|
||||
return Math.min(width , mLastWidth + widthDelta);
|
||||
else
|
||||
return Math.max(width , mLastWidth - widthDelta);
|
||||
}
|
||||
|
||||
public void setMaxWidth(float maxWidth){
|
||||
this.maxWidth = maxWidth;
|
||||
Log.i(TAG, "maxWidth " + maxWidth);
|
||||
}
|
||||
|
||||
public float getMaxWidth() {
|
||||
return maxWidth;
|
||||
}
|
||||
public void addPoint(TimePoint timePoint,float pressure){
|
||||
mPoint.add(timePoint);
|
||||
|
||||
if(mPoint.size() > 3){
|
||||
SplineCurve splineCurve = new SplineCurve(mPoint.get(0),
|
||||
mPoint.get(1), mPoint.get(2), mPoint.get(3));
|
||||
float velocity = splineCurve.point3.velocityFrom(splineCurve.point2);
|
||||
float widthDelta = 0;
|
||||
float newWidth;
|
||||
if (false) {
|
||||
if (velocity > 3) {
|
||||
splineCurve.steps = 4;
|
||||
widthDelta = 0.8f;
|
||||
} else if (velocity > 2) {
|
||||
splineCurve.steps = 3;
|
||||
widthDelta = 0.7f;
|
||||
} else if (velocity > 1) {
|
||||
splineCurve.steps = 3;
|
||||
widthDelta = 0.6f;
|
||||
} else if (velocity > 0.5) {
|
||||
splineCurve.steps = 2;
|
||||
widthDelta = 0.5f;
|
||||
} else if (velocity > 0.2) {
|
||||
splineCurve.steps = 2;
|
||||
widthDelta = 0.4f;
|
||||
} else if (velocity > 0.1) {
|
||||
splineCurve.steps = 1;
|
||||
widthDelta = 0.3f;
|
||||
} else {
|
||||
splineCurve.steps = 1;
|
||||
widthDelta = 0.2f;
|
||||
}
|
||||
Log.i(TAG, "pressure: " + pressure);
|
||||
if (pressure < 0.4)
|
||||
newWidth = strokeWidth(pressure, 1 - pressure);
|
||||
else
|
||||
newWidth = strokeWidth(pressure, widthDelta);
|
||||
} else {
|
||||
if (velocity > 3) {
|
||||
splineCurve.steps = 4;
|
||||
widthDelta = 3.0f;
|
||||
} else if (velocity > 2) {
|
||||
splineCurve.steps = 3;
|
||||
widthDelta = 2.0f;
|
||||
} else if (velocity > 1) {
|
||||
splineCurve.steps = 3;
|
||||
widthDelta = 1.0f;
|
||||
} else if (velocity > 0.5) {
|
||||
splineCurve.steps = 2;
|
||||
widthDelta = 0.8f;
|
||||
} else if (velocity > 0.2) {
|
||||
splineCurve.steps = 2;
|
||||
widthDelta = 0.6f;
|
||||
} else if (velocity > 0.1) {
|
||||
splineCurve.steps = 1;
|
||||
widthDelta = 0.3f;
|
||||
} else {
|
||||
splineCurve.steps = 1;
|
||||
widthDelta = 0.2f;
|
||||
}
|
||||
newWidth = strokeWidth(pressure, widthDelta) ;
|
||||
}
|
||||
newWidth = Float.isNaN(newWidth) ? mLastWidth : newWidth;
|
||||
Log.i(TAG, "newWidth" + newWidth);
|
||||
if(strokes.getMyPathSize() >= 1) {
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize() - 1).addOriginPoint(new TimePoint(timePoint.x, timePoint.y));
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize() - 1).addOriginWidth(newWidth);
|
||||
}
|
||||
if(isUp){
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize() - 1).addOriginPoint(new TimePoint(timePoint.x, timePoint.y));
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize() - 1).addOriginWidth(newWidth);
|
||||
}
|
||||
if (splineCurveStrategy == null) {
|
||||
splineCurveStrategy = new SplineCurveStrategy(splineCurve, mLastWidth, newWidth, myCanvas, mPaint);
|
||||
splineCurveStrategy.initLastPoint(lastTop, lastBottom);
|
||||
} else {
|
||||
splineCurveStrategy.updateData(mLastWidth, newWidth, splineCurve);
|
||||
}
|
||||
Log.i("penType", penType.getPenType() + "");
|
||||
switch (penType.getPenType()) {
|
||||
case PenType.PEN:
|
||||
splineCurveStrategy.drawPen(this);//钢笔
|
||||
break;
|
||||
case PenType.BRUSH:
|
||||
splineCurveStrategy.drawBrushPen(this);//毛笔
|
||||
break;
|
||||
}
|
||||
mPoint.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
public double mult(float x1,float y1,float x2,float y2,float x3,float y3){
|
||||
return (x1 - x3)*(y2 - y3) - (x2 - x3)*(y1 - y3);
|
||||
}
|
||||
public boolean intersect(float x1,float y1,float x2,float y2,float x3,float y3,
|
||||
float x4,float y4){
|
||||
if(Math.max(x1,x2)<Math.min(x3,x4)){
|
||||
return false;
|
||||
}
|
||||
if(Math.max(y1,y2)<Math.min(y3,y4)){
|
||||
return false;
|
||||
}
|
||||
if(Math.max(x3,x4)<Math.min(x1,x2)){
|
||||
return false;
|
||||
}
|
||||
if(Math.max(y3,y4)<Math.min(y1,y2)){
|
||||
return false;
|
||||
}
|
||||
if(mult(x3,y3,x2,y2,x1,y1)*mult(x2,y2,x4,y4,x1,y1)<0){
|
||||
return false;
|
||||
}
|
||||
if(mult(x1,y1,x4,y4,x3,y3)*mult(x4,y4,x2,y2,x3,y3)<0){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public float calculateDegree(float x1,float y1,float x2,float y2,float x3,float y3){
|
||||
float b = (float)Math.sqrt((x1 - x2)*( x1 - x2) + (y1 - y2) * (y1 - y2));
|
||||
float c = (float)Math.sqrt((x2 - x3)*( x2 - x3) +
|
||||
(y2 - y3) * (y2 - y3));
|
||||
float a = (float)Math.sqrt((x1 - x3)*( x1 - x3) +
|
||||
(y1 - y3) * (y1 - y3));
|
||||
if(c==0||b==0) return 0;
|
||||
float sum = (b * b + c * c - a * a)/(2*b*c);
|
||||
float degree =(float) Math.acos(sum) * 180 / (float)Math.PI;
|
||||
Log.i(TAG, "degree : " + degree);
|
||||
if(Float.isNaN(degree)) degree = 0;
|
||||
return degree;
|
||||
}
|
||||
public Handler myHandler = new Handler(){
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
//当所有笔划都画到bitmapStroke上时
|
||||
//清除myBitmap上的笔划 这步很重要
|
||||
if(myCanvas!=null) {
|
||||
myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
|
||||
myCanvas.drawBitmap(bitmapStroke, 0, 0, mPaint);
|
||||
strokeView.invalidate();
|
||||
}
|
||||
}
|
||||
};
|
||||
public void updatePathToCanvas(){
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
canvasStroke.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
|
||||
strokes.draw(canvasStroke,mPaint);
|
||||
myHandler.sendEmptyMessage(0);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void moveTo(float x,float y,float pressure){
|
||||
strokesPath.reset();
|
||||
myPoints.clear();
|
||||
mPoint.clear();
|
||||
isDown = true;
|
||||
isUp = false;
|
||||
mLLastX = x;
|
||||
mLLastY = y;
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
mLastWidth = Math.min(maxWidth , 0.1f * (1 + (pressure+0.2f) * (maxWidth * 10 - 1) ));
|
||||
mLastK = 0;
|
||||
strokes.addMyPath(strokes.getMyPathSize(), strokes.getMyPathSize() + strokes.getRecycleStrokesListSize());
|
||||
addPoint(new TimePoint(x, y), pressure);
|
||||
addPoint(new TimePoint(x, y), pressure);
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize()-1).addOriginPoint(new TimePoint(x, y));
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize()-1).addOriginPoint(new TimePoint(x,y));
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize()-1).addOriginWidth(mLastWidth);
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize()-1).addOriginWidth(mLastWidth);
|
||||
}
|
||||
public void lineTo(float x,float y,float pressure,boolean isUp){
|
||||
if (isUp) {
|
||||
addPoint(new TimePoint(x, y), pressure);
|
||||
this.isUp = true;
|
||||
addPoint(new TimePoint(x, y), pressure);
|
||||
for(int i = myPoints.size() - 1;i>=0;i--){
|
||||
strokesPath.lineTo(myPoints.elementAt(i).getX(),myPoints.elementAt(i).getY());
|
||||
strokes.getMyPathList().get(strokes.getMyPathSize()-1).addPoint(new TimePoint(myPoints.elementAt(i).getX(),myPoints.elementAt(i).getY()));
|
||||
}
|
||||
myPoints.clear();
|
||||
strokes.getMyPathList().elementAt(strokes.getMyPathSize()-1).setStroke(strokesPath);
|
||||
setUnDo(false);
|
||||
Log.i(TAG, "拟合前的点数量" + strokes.getMyPathList().elementAt(strokes.getMyPathSize() - 1).getOriginPoints().size());
|
||||
Log.i(TAG,"拟合后的点数量" + strokes.getMyPathList().elementAt(strokes.getMyPathSize() - 1).getPoints().size());
|
||||
} else {
|
||||
addPoint(new TimePoint(x, y), pressure);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas,Paint mPaint) {
|
||||
// TODO Auto-generated method stub
|
||||
canvas.drawBitmap(myBitmap, 0, 0, mPaint);
|
||||
}
|
||||
|
||||
//撤销
|
||||
public void unDo(){
|
||||
Log.i(TAG, "unDo");
|
||||
setUnDo(true);
|
||||
//首先判断两个vector中笔划的优先级
|
||||
int recycleVectorPriority = -1;
|
||||
int myVectorPriority = -1;
|
||||
int myPicturePriority = -1;
|
||||
int recyclePicturePriority = -1;
|
||||
if(strokes.getMyPathSize() > 0){
|
||||
myVectorPriority = strokes.getMyPathList().elementAt(strokes.getMyPathSize()-1).getPriority();
|
||||
}
|
||||
if(strokes.getRecycleStrokesListSize() > 0){
|
||||
recycleVectorPriority = strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).getPriority();
|
||||
}
|
||||
//说明有可以撤销的笔划
|
||||
if(recycleVectorPriority != -1 || myVectorPriority != -1||myPicturePriority!=-1||recyclePicturePriority!=-1){
|
||||
if(myVectorPriority >= recycleVectorPriority && myVectorPriority >= myPicturePriority &&myVectorPriority>=recyclePicturePriority){
|
||||
//将笔划压入撤销栈
|
||||
strokes.addUnDoStrokes(strokes.getMyPathList().elementAt(strokes.getMyPathSize()-1));
|
||||
//移除myPath最后一个
|
||||
strokes.deleteMyPath(strokes.getMyPathSize()-1);
|
||||
}
|
||||
|
||||
if(recycleVectorPriority>=myPicturePriority&&recycleVectorPriority>=myVectorPriority&&recycleVectorPriority>=recyclePicturePriority){//可能一次会撤销很多笔划 因为当初可能一次删除多个笔划 所以要循环
|
||||
int priority = -1;
|
||||
do {
|
||||
//降低回收栈中笔划的优先级
|
||||
strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).setPriority(
|
||||
strokes.getMyPathList().elementAt(strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).getLocation()).getPriority());
|
||||
//设置撤销栈中笔划的优先级继承回收站的 方便恢复多个笔划
|
||||
strokes.getMyPathList().elementAt(strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).getLocation()).setPriority(
|
||||
recycleVectorPriority);
|
||||
//将myPath对应位置的笔划压入撤销栈
|
||||
Log.i(TAG,strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).getLocation()+" ");
|
||||
strokes.addUnDoStrokes(strokes.getMyPathList().elementAt(strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).getLocation()));
|
||||
//移除myPath对应位置的笔划
|
||||
strokes.deleteMyPath(strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).getLocation());
|
||||
strokes.getMyPathList().add(strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).getLocation(),
|
||||
strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1));
|
||||
strokes.deleteRecycleStrokesList(strokes.getRecycleStrokesListSize() - 1);
|
||||
//继续判断下一个笔划的优先级
|
||||
priority = -1;
|
||||
if(strokes.getRecycleStrokesListSize() > 0)
|
||||
priority = strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).getPriority();
|
||||
}while(priority == recycleVectorPriority);
|
||||
}
|
||||
updatePathToCanvas();
|
||||
}
|
||||
|
||||
}
|
||||
public void reDo(){
|
||||
Log.i(TAG, "reDo");
|
||||
//对三个栈都做清空
|
||||
if(isUnDo) setUnDo(false);
|
||||
strokes.getMyPathList().clear();
|
||||
strokes.getRecycleStrokesList().clear();
|
||||
updatePathToCanvas();
|
||||
}
|
||||
public void clear(){
|
||||
//对三个栈都做清空
|
||||
if(isUnDo) setUnDo(false);
|
||||
strokes.getMyPathList().clear();
|
||||
strokes.getRecycleStrokesList().clear();
|
||||
}
|
||||
|
||||
public void recover(){
|
||||
//上一步必须是撤销
|
||||
if(isUnDo){
|
||||
Log.i(TAG, "recover");
|
||||
int strokePriority = -1;
|
||||
int strokeSize = strokes.getUnDoStrokesList().size();
|
||||
if(strokeSize>0)
|
||||
strokePriority = strokes.getUnDoStrokesList().elementAt(strokeSize - 1).getPriority();
|
||||
int picturePriority = -1;
|
||||
Log.i(TAG,strokePriority+" "+picturePriority);
|
||||
if(strokePriority!=-1||picturePriority!=-1) {
|
||||
int addPriority = strokes.getMyPathSize() + strokes.getRecycleStrokesListSize();
|
||||
if ((picturePriority!=-1&&strokePriority <= picturePriority && strokePriority!=-1)||
|
||||
(picturePriority==-1&&strokePriority!=-1)) {
|
||||
//可能是恢复多个
|
||||
int priority = -1;
|
||||
int finalPriority = strokePriority;
|
||||
do {
|
||||
//恢复的位置是插入
|
||||
if (strokes.getUnDoStrokesList().elementAt(strokeSize - 1).getLocation() < strokes.getMyPathSize()) {
|
||||
//降低撤销栈中笔划的优先级
|
||||
strokes.getUnDoStrokesList().elementAt(strokeSize - 1).setPriority(
|
||||
strokes.getMyPathList().elementAt(strokes.getUnDoStrokesList().elementAt(strokeSize - 1).getLocation()).getPriority()
|
||||
);
|
||||
//将myPath对应位置上的压入回收栈
|
||||
strokes.getRecycleStrokesList().add(strokes.getMyPathList().elementAt(strokes.getUnDoStrokesList().elementAt(strokeSize - 1).getLocation()));
|
||||
//增加优先级
|
||||
strokes.getRecycleStrokesList().elementAt(strokes.getRecycleStrokesListSize() - 1).setPriority(addPriority);
|
||||
//删除myPath对应的笔划
|
||||
strokes.deleteMyPath(strokes.getUnDoStrokesList().elementAt(strokeSize - 1).getLocation());
|
||||
}
|
||||
//将撤销栈中最后一个压入myPath对应的位置上
|
||||
strokes.getMyPathList().add(strokes.getUnDoStrokesList().elementAt(strokeSize - 1).getLocation(),
|
||||
strokes.getUnDoStrokesList().elementAt(strokeSize - 1));
|
||||
//删除撤销栈最后一个
|
||||
strokes.deleteUnDoStrokesList(strokeSize - 1);
|
||||
//继续判断下一个笔划的优先级
|
||||
priority = -1;
|
||||
strokeSize = strokes.getUnDoStrokesList().size();
|
||||
if (strokeSize > 0)
|
||||
priority = strokes.getUnDoStrokesList().elementAt(strokeSize - 1).getPriority();
|
||||
} while (priority == finalPriority);
|
||||
updatePathToCanvas();
|
||||
}
|
||||
if ((strokePriority!=-1&&strokePriority >= picturePriority&&picturePriority!=-1)||
|
||||
(strokePriority==-1&&picturePriority!=-1)) {
|
||||
//可能是恢复多个
|
||||
int priority = -1;
|
||||
int finalPriority = picturePriority;
|
||||
updatePathToCanvas();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUnDo() {
|
||||
return isUnDo;
|
||||
}
|
||||
|
||||
public void setUnDo(boolean unDo) {
|
||||
isUnDo = unDo;
|
||||
if(!unDo){
|
||||
strokes.clearUnDoStrokesList();
|
||||
}
|
||||
}
|
||||
public void onDestroy(){
|
||||
if(myBitmap!=null&&!myBitmap.isRecycled()){
|
||||
myCanvas = null;
|
||||
myBitmap.recycle();
|
||||
myBitmap = null;
|
||||
}
|
||||
if(bitmapStroke != null && !bitmapStroke.isRecycled()){
|
||||
canvasStroke = null;
|
||||
bitmapStroke.recycle();
|
||||
bitmapStroke = null;
|
||||
}
|
||||
setUnDo(false);
|
||||
clear();
|
||||
myPoints.clear();
|
||||
}
|
||||
}
|
19
baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/PenType.java
Executable file
19
baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/PenType.java
Executable file
@ -0,0 +1,19 @@
|
||||
package com.tenlionsoft.baselib.core.widget.pens;
|
||||
|
||||
/**
|
||||
* Created by BJ-00314 on 2019/5/20.
|
||||
*/
|
||||
|
||||
public class PenType {
|
||||
/**笔的类型*/
|
||||
public static final int PEN = 0x00;
|
||||
public static final int BRUSH = 0x01;
|
||||
/**记录当前笔类型 默认刚开始都是钢笔*/
|
||||
private int penType = PEN;
|
||||
public void setPenType(int penType) {
|
||||
this.penType = penType;
|
||||
}
|
||||
public int getPenType() {
|
||||
return penType;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.tenlionsoft.baselib.core.widget.pens;
|
||||
|
||||
|
||||
/**
|
||||
* Author:Double
|
||||
* Time:2019/4/22
|
||||
* Description:This is SplineCurve
|
||||
*/
|
||||
public class SplineCurve {
|
||||
public TimePoint point1;
|
||||
public TimePoint point2;//起点
|
||||
public TimePoint point3;//结束点
|
||||
public TimePoint point4;
|
||||
public int steps = 10;//设定在曲线上取的点数
|
||||
|
||||
public SplineCurve(TimePoint point1, TimePoint point2,
|
||||
TimePoint point3, TimePoint point4){
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
this.point3 = point3;
|
||||
this.point4 = point4;
|
||||
}
|
||||
//获得贝塞尔曲线中取得的10个点的相邻点距离和
|
||||
public float length(){
|
||||
int length = 0;
|
||||
float perStep;
|
||||
double cx, cy, px = 0, py = 0, xdiff, ydiff;
|
||||
for(int i = 0;i <= steps; i++){
|
||||
perStep = (float)i / steps;
|
||||
cx = point(perStep, this.point1.x, this.point2.x, this.point3.x,
|
||||
this.point4.x);
|
||||
cy = point(perStep, this.point1.y, this.point2.y, this.point3.y,
|
||||
this.point4.y);
|
||||
if(i > 0){//计算与上一个点的距离
|
||||
xdiff = cx - px;
|
||||
ydiff = cy - py;
|
||||
length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
|
||||
}
|
||||
px = cx;
|
||||
py = cy;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
//通过贝塞尔算法返回每个点的x或者y值
|
||||
public double point(float perStep, float point1, float point2, float point3, float point4){
|
||||
return point1 * (1.0 - perStep) * (1.0 - perStep) * (1.0 - perStep) / 6.0
|
||||
+ point2 * (3 * perStep * perStep * perStep - 6 * perStep * perStep + 4) / 6.0
|
||||
+ point3 * (-3 * perStep * perStep * perStep + 3 * perStep * perStep + 3 * perStep + 1)/6.0
|
||||
+point4 * perStep * perStep * perStep / 6.0;
|
||||
}
|
||||
}
|
@ -0,0 +1,686 @@
|
||||
package com.tenlionsoft.baselib.core.widget.pens;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Author:Double
|
||||
* Time:2019/4/22
|
||||
* Description:This is SplineCurveStrategy
|
||||
*/
|
||||
public class SplineCurveStrategy {
|
||||
public int curveIndex = 2;
|
||||
public float startWidth;
|
||||
public float endWidth;
|
||||
public SplineCurve splineCurve;
|
||||
public Paint blurryPaint;
|
||||
public Paint mMosaicPaint;
|
||||
public Paint eraserPaint;
|
||||
public final int eraserWidth = 50;
|
||||
protected Canvas canvas;
|
||||
protected Paint mPaint;
|
||||
public TimePoint lastTop,lastBottom;
|
||||
protected Path mPath;
|
||||
public SplineCurveStrategy(SplineCurve splineCurve, float startWidth, float endWidth, Canvas canvas, Paint mPaint){
|
||||
this.splineCurve = splineCurve;
|
||||
this.startWidth = startWidth;
|
||||
this.endWidth = endWidth;
|
||||
this.blurryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
this.mMosaicPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
this.eraserPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
this.eraserPaint.setColor(Color.WHITE);
|
||||
this.eraserPaint.setStrokeWidth(eraserWidth);
|
||||
this.eraserPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
this.eraserPaint.setStrokeJoin(Paint.Join.ROUND);
|
||||
mMosaicPaint.setAlpha(80);
|
||||
mMosaicPaint.setStrokeCap(Paint.Cap.BUTT);
|
||||
mMosaicPaint.setStrokeJoin(Paint.Join.ROUND);
|
||||
//mMosaicPaint.setStyle(Paint.Style.FILL);
|
||||
mMosaicPaint.setStrokeWidth(12f);
|
||||
this.canvas = canvas;
|
||||
this.mPaint = mPaint;
|
||||
this.mPath = new Path();
|
||||
}
|
||||
|
||||
public void updateData(float startWidth,float endWidth, SplineCurve splineCurve){
|
||||
this.splineCurve = splineCurve;
|
||||
this.startWidth = startWidth;
|
||||
this.endWidth = endWidth;
|
||||
}
|
||||
|
||||
public double mult(float x1,float y1,float x2,float y2,float x3,float y3){
|
||||
return (x1 - x3)*(y2 - y3) - (x2 - x3)*(y1 - y3);
|
||||
}
|
||||
public void initLastPoint(TimePoint lastTop,TimePoint lastBottom){
|
||||
this.lastTop = lastTop;
|
||||
this.lastBottom = lastBottom;
|
||||
}
|
||||
public void drawPen(DrawingStrokes drawingStrokes) {
|
||||
if(drawingStrokes.debug)
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
else mPaint.setStyle(Paint.Style.FILL);
|
||||
mPaint.setColor(Color.BLACK);
|
||||
//获得笔在两点间不同宽度的差值
|
||||
int drawSteps = (int)Math.floor(splineCurve.length());
|
||||
if(drawingStrokes.isUp) {
|
||||
//curveIndex = 1;
|
||||
if(drawSteps > 2)
|
||||
curveIndex = (drawSteps - 2)/2;
|
||||
else curveIndex = 1;
|
||||
if(curveIndex < 1) curveIndex = 1;
|
||||
if(drawSteps == 0) drawSteps = 2;
|
||||
}else if(drawingStrokes.isDown){
|
||||
curveIndex = 1;
|
||||
if(drawSteps == 0) drawSteps = 2;
|
||||
}else{
|
||||
if(drawSteps > 100) curveIndex = 40;
|
||||
else if(drawSteps > 80) curveIndex = 35;
|
||||
else if(drawSteps > 70) curveIndex = 30;
|
||||
else if(drawSteps > 60) curveIndex = 25;
|
||||
else if(drawSteps > 50) curveIndex = 20;
|
||||
else if(drawSteps > 40) curveIndex = 15;
|
||||
else if(drawSteps > 30) curveIndex = 13;
|
||||
else if(drawSteps > 20) curveIndex = 9;
|
||||
else if(drawSteps > 10) curveIndex = 7;
|
||||
else if(drawSteps >= 4) curveIndex = 3;
|
||||
else curveIndex = 1;
|
||||
}
|
||||
float widthDelta = endWidth - startWidth;
|
||||
//两点间实际轨迹距离
|
||||
float k = 0;
|
||||
TimePoint myPointC,myPointD,myPointA,myPointB;
|
||||
//危险
|
||||
boolean modify = false;
|
||||
if(drawSteps==0) {
|
||||
drawSteps = 1;
|
||||
modify = true;
|
||||
}
|
||||
Log.i("w_pen",drawSteps+" "+curveIndex);
|
||||
// curveIndex = drawSteps/2;
|
||||
// if(curveIndex==0) curveIndex=1;
|
||||
for(int i = 0,num = 1; i < drawSteps; i+=curveIndex,num++){
|
||||
mPath.reset();
|
||||
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 * splineCurve.point1.x / 6.0f;
|
||||
x += (3*ttt-6*tt+4) * splineCurve.point2.x/ 6.0f;
|
||||
x += (-3*ttt+3*tt+3*t+1)* splineCurve.point3.x/ 6.0f;
|
||||
x += ttt * splineCurve.point4.x/ 6.0f;
|
||||
float y = uuu * splineCurve.point1.y/ 6.0f;
|
||||
y += (3*ttt-6*tt+4) * splineCurve.point2.y/ 6.0f;
|
||||
y += (-3*ttt+3*tt+3*t+1) * splineCurve.point3.y/ 6.0f;
|
||||
y += ttt * splineCurve.point4.y/ 6.0f;
|
||||
float currentWidth = startWidth + t * widthDelta ;
|
||||
if(!drawingStrokes.isUp)
|
||||
if(Math.abs(t*widthDelta)>0.2f*num) {
|
||||
if(t*widthDelta>0)
|
||||
currentWidth = startWidth + 0.2f*num;
|
||||
else currentWidth = startWidth - 0.2f*num;
|
||||
}
|
||||
int currentState = 0;
|
||||
float numX = x - drawingStrokes.mLastX;
|
||||
float numY = y - drawingStrokes.mLastY;
|
||||
if(numX > 0 && numY >0) currentState = drawingStrokes.X_ADD_Y_ADD;
|
||||
if(numX > 0 && numY < 0) currentState = drawingStrokes.X_ADD_Y_DEC;
|
||||
if(numX > 0 && numY == 0) currentState = drawingStrokes.X_ADD_Y_SAM;
|
||||
if(numX < 0 && numY > 0) currentState = drawingStrokes.X_DEC_Y_ADD;
|
||||
if(numX < 0 && numY <0) currentState = drawingStrokes.X_DEC_Y_DEC;
|
||||
if(numX < 0 && numY == 0) currentState = drawingStrokes.X_DEC_Y_SAM;
|
||||
if(numX == 0 && numY > 0) currentState = drawingStrokes.X_SAM_Y_ADD;
|
||||
if(numX == 0 && numY < 0) currentState = drawingStrokes.X_SAM_Y_DEC;
|
||||
if(numX == 0 && numY == 0) currentState = drawingStrokes.X_SAM_Y_SAM;
|
||||
// if(drawingStrokes.state!=currentState&&modify&&!drawingStrokes.isUp&&!drawingStrokes.isDown){//保证转弯处不恶意修改值
|
||||
// break;
|
||||
// }
|
||||
if( x != drawingStrokes.mLastX){
|
||||
k = (y - drawingStrokes.mLastY) / (x - drawingStrokes.mLastX);
|
||||
//上个点的上下端点MyPointA,MyPointB
|
||||
myPointA = new TimePoint( (drawingStrokes.mLastWidth / 2 )* (-k) / (float) Math.sqrt(k * k + 1) + drawingStrokes.mLastX,
|
||||
(drawingStrokes.mLastWidth / 2 ) / (float) Math.sqrt(k * k + 1) + drawingStrokes.mLastY);
|
||||
myPointB = new TimePoint( (-drawingStrokes.mLastWidth / 2 )* (-k) / (float) Math.sqrt(k * k + 1) + drawingStrokes.mLastX,
|
||||
(-drawingStrokes.mLastWidth / 2 ) / (float) Math.sqrt(k * k + 1) + drawingStrokes.mLastY);
|
||||
//当前点的上下端点MyPointC,MyPointD
|
||||
myPointC = new TimePoint( (currentWidth / 2 )* (-k) / (float) Math.sqrt(k * k + 1) + x,
|
||||
(currentWidth / 2 ) / (float) Math.sqrt(k * k + 1) + y);
|
||||
myPointD = new TimePoint( (-currentWidth / 2 )* (-k) / (float) Math.sqrt(k * k + 1) + x,
|
||||
(-currentWidth / 2 ) / (float) Math.sqrt(k * k + 1) + y);
|
||||
|
||||
}else{
|
||||
myPointA = new TimePoint( drawingStrokes.mLastWidth / 2 + drawingStrokes.mLastX,
|
||||
drawingStrokes.mLastY);
|
||||
myPointB = new TimePoint( -drawingStrokes.mLastWidth / 2 + drawingStrokes.mLastX,
|
||||
drawingStrokes.mLastY);
|
||||
myPointC = new TimePoint( currentWidth / 2 + x,
|
||||
y);
|
||||
myPointD = new TimePoint( -currentWidth / 2 + x,
|
||||
y);
|
||||
}
|
||||
if(drawingStrokes.isDown){//起点 需要算AB
|
||||
//算出矩形的四个点
|
||||
TimePoint A,B,C,D;
|
||||
if( myPointA.x != myPointB.x){
|
||||
k = (myPointA.y - myPointB.y) / (myPointA.x - myPointB.x);
|
||||
A = new TimePoint( (drawingStrokes.mLastWidth )* (-k) / (float) Math.sqrt(k * k + 1) + myPointA.x,
|
||||
(drawingStrokes.mLastWidth ) / (float) Math.sqrt(k * k + 1) + myPointA.y);
|
||||
B = new TimePoint( (-drawingStrokes.mLastWidth )* (-k) / (float) Math.sqrt(k * k + 1) + myPointA.x,
|
||||
(-drawingStrokes.mLastWidth ) / (float) Math.sqrt(k * k + 1) + myPointA.y);
|
||||
//当前点的上下端点MyPointC,MyPointD
|
||||
C = new TimePoint( (drawingStrokes.mLastWidth )* (-k) / (float) Math.sqrt(k * k + 1) + myPointB.x,
|
||||
(drawingStrokes.mLastWidth ) / (float) Math.sqrt(k * k + 1) + myPointB.y);
|
||||
D = new TimePoint( (-drawingStrokes.mLastWidth )* (-k) / (float) Math.sqrt(k * k + 1) + myPointB.x,
|
||||
(-drawingStrokes.mLastWidth ) / (float) Math.sqrt(k * k + 1) + myPointB.y);
|
||||
|
||||
}else{
|
||||
A = new TimePoint( drawingStrokes.mLastWidth + myPointA.x,
|
||||
myPointA.y);
|
||||
B = new TimePoint( -drawingStrokes.mLastWidth + myPointA.x,
|
||||
myPointA.y);
|
||||
C = new TimePoint( drawingStrokes.mLastWidth + myPointB.x,
|
||||
myPointB.y);
|
||||
D = new TimePoint( -drawingStrokes.mLastWidth / 2 + myPointB.x,
|
||||
myPointB.y);
|
||||
}
|
||||
TimePoint centerAC = new TimePoint((A.x+C.x)/2,(A.y+C.y)/2);
|
||||
TimePoint centerBD = new TimePoint((B.x+D.x)/2,(B.y+D.y)/2);
|
||||
boolean isAC = true;
|
||||
if( myPointA.x != myPointB.x){
|
||||
float b = myPointA.y - k *myPointA.x;
|
||||
if((centerAC.y - k* centerAC.x - b)*(drawingStrokes.mPoint.get(3).y - k*drawingStrokes.mPoint.get(3).x - b)<=0){
|
||||
isAC = true;
|
||||
}else {
|
||||
isAC = false;
|
||||
}
|
||||
// if ((drawingStrokes.mLastY - centerAC.y) / (drawingStrokes.mLastX - centerAC.x) * k >0) {
|
||||
// isAC = true;
|
||||
// } else {
|
||||
// isAC = false;
|
||||
// }
|
||||
}else{
|
||||
if((centerAC.y-myPointA.y)*(drawingStrokes.mPoint.get(3).y - myPointA.y)<=0){
|
||||
isAC = true;
|
||||
}else {
|
||||
isAC = false;
|
||||
}
|
||||
}
|
||||
if(!drawingStrokes.debug) {
|
||||
//填充
|
||||
// mPath.moveTo(myPointB.x, myPointB.y);
|
||||
// mPath.lineTo(myPointD.x, myPointD.y);
|
||||
//// //**mPath.lineTo(myPointC.x, myPointC.y);
|
||||
// mPath.lineTo(myPointC.x, myPointC.y);
|
||||
// mPath.lineTo(myPointA.x, myPointA.y);
|
||||
mPath.moveTo(myPointB.x, myPointB.y);
|
||||
if(isAC)
|
||||
mPath.quadTo(centerAC.x,centerAC.y,myPointA.x,myPointA.y);
|
||||
else mPath.quadTo(centerBD.x,centerBD.y,myPointA.x,myPointA.y);
|
||||
mPath.lineTo(myPointC.x, myPointC.y);
|
||||
mPath.lineTo(myPointD.x, myPointD.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
canvas.drawPath(mPath,mPaint);
|
||||
mPath.reset();
|
||||
}else {
|
||||
//测试
|
||||
// mPath.moveTo(myPointB.x, myPointB.y);
|
||||
// mPath.lineTo(myPointD.x, myPointD.y);
|
||||
// //**mPath.lineTo(myPointC.x, myPointC.y);
|
||||
// mPath.moveTo(myPointC.x, myPointC.y);
|
||||
// mPath.lineTo(myPointA.x, myPointA.y);
|
||||
|
||||
mPath.moveTo(myPointB.x, myPointB.y);
|
||||
if(isAC)
|
||||
mPath.quadTo(centerAC.x,centerAC.y,myPointA.x,myPointA.y);
|
||||
else mPath.quadTo(centerBD.x,centerBD.y,myPointA.x,myPointA.y);
|
||||
mPath.lineTo(myPointC.x, myPointC.y);
|
||||
mPath.moveTo(myPointB.x, myPointB.y);
|
||||
mPath.lineTo(myPointD.x, myPointD.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
}
|
||||
|
||||
drawingStrokes.isDown = false;
|
||||
|
||||
drawingStrokes.strokesPath.moveTo(myPointB.x, myPointB.y);
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointB.x,myPointB.y));
|
||||
if(isAC) {
|
||||
drawingStrokes.strokesPath.quadTo(centerAC.x, centerAC.y, myPointA.x, myPointA.y);
|
||||
drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new TimePoint(centerAC.x, centerAC.y));
|
||||
}
|
||||
else {
|
||||
drawingStrokes.strokesPath.quadTo(centerBD.x, centerBD.y, myPointA.x, myPointA.y);
|
||||
drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new TimePoint(centerBD.x, centerBD.y));
|
||||
}
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointA.x, myPointA.y));
|
||||
drawingStrokes.strokesPath.lineTo(myPointC.x, myPointC.y);
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointC.x, myPointC.y));
|
||||
drawingStrokes.lastLineX = myPointC.x;
|
||||
drawingStrokes.lastLineY = myPointC.y;
|
||||
//drawingStrokes.myPoints.add(new MyPoints(myPointA.x,myPointA.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointB.x,myPointB.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointD.x,myPointD.y));
|
||||
|
||||
}else{
|
||||
//相交为180
|
||||
if((drawingStrokes.mLLastX == drawingStrokes.mLastX &&drawingStrokes.mLastX == x)
|
||||
||(drawingStrokes.mLLastX != drawingStrokes.mLastX &&drawingStrokes.mLastX != x && (k == drawingStrokes.mLastK || -k == drawingStrokes.mLastK))){
|
||||
if (-k == drawingStrokes.mLastK&&k!=0) {//特殊情况
|
||||
Log.d("123","特殊来了"+k);
|
||||
}
|
||||
}else{
|
||||
//判断外端点画弧
|
||||
float degereeA = drawingStrokes.calculateDegree(drawingStrokes.mLastX,drawingStrokes.mLastY,
|
||||
drawingStrokes.mLLastX, drawingStrokes.mLLastY, myPointA.x,myPointA.y);
|
||||
float degereeB = drawingStrokes.calculateDegree(drawingStrokes.mLastX,drawingStrokes.mLastY,
|
||||
drawingStrokes.mLLastX, drawingStrokes.mLLastY, myPointB.x,myPointB.y);
|
||||
float degereeLT = drawingStrokes.calculateDegree(drawingStrokes.mLastX,drawingStrokes.mLastY,
|
||||
x, y, lastTop.x,lastTop.y);
|
||||
float degereeLB = drawingStrokes.calculateDegree(drawingStrokes.mLastX,drawingStrokes.mLastY,
|
||||
x, y, lastBottom.x,lastBottom.y);
|
||||
//谁大谁是外端点
|
||||
if ((degereeA >= degereeB&°ereeLT >= degereeLB)||(degereeA <= degereeB&°ereeLT <= degereeLB)) {
|
||||
if(!drawingStrokes.debug) {
|
||||
//填充
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(lastTop.x, lastTop.y);
|
||||
mPath.lineTo(lastBottom.x, lastBottom.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
mPath.lineTo(myPointA.x, myPointA.y);
|
||||
canvas.drawPath(mPath,mPaint);
|
||||
mPath.reset();
|
||||
}else {
|
||||
//测试
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(lastTop.x, lastTop.y);
|
||||
mPath.moveTo(lastBottom.x, lastBottom.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
}
|
||||
if(drawingStrokes.lastLineX == lastTop.x && drawingStrokes.lastLineY == lastTop.y){
|
||||
drawingStrokes.strokesPath.lineTo(myPointA.x, myPointA.y);
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointA.x, myPointA.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointB.x,myPointB.y));
|
||||
drawingStrokes.lastLineX = myPointA.x;
|
||||
drawingStrokes.lastLineY = myPointA.y;
|
||||
}else{
|
||||
drawingStrokes.strokesPath.lineTo(myPointB.x, myPointB.y);
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointB.x, myPointB.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointA.x,myPointA.y));
|
||||
drawingStrokes.lastLineX = myPointB.x;
|
||||
drawingStrokes.lastLineY = myPointB.y;
|
||||
}
|
||||
} else {
|
||||
//测试
|
||||
if (drawingStrokes.intersect(myPointA.x, myPointA.y, lastBottom.x, lastBottom.y, x, y, drawingStrokes.mLastX, drawingStrokes.mLastY)
|
||||
|| drawingStrokes.intersect(myPointA.x, myPointA.y, lastBottom.x, lastBottom.y, drawingStrokes.mLLastX, drawingStrokes.mLLastY,
|
||||
drawingStrokes.mLastX, drawingStrokes.mLastY)) {
|
||||
//转弯了
|
||||
if(drawingStrokes.state!=-1&&drawingStrokes.state != currentState) {
|
||||
if(!drawingStrokes.debug) {
|
||||
//填充
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(lastBottom.x, lastBottom.y);
|
||||
mPath.lineTo(lastTop.x, lastTop.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
mPath.lineTo(myPointA.x, myPointA.y);
|
||||
canvas.drawPath(mPath,mPaint);
|
||||
mPath.reset();
|
||||
}else {
|
||||
//测试
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(lastBottom.x, lastBottom.y);
|
||||
mPath.moveTo(lastTop.x, lastTop.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
}
|
||||
if(drawingStrokes.lastLineX == lastBottom.x && drawingStrokes.lastLineY == lastBottom.y){
|
||||
drawingStrokes.strokesPath.lineTo(myPointA.x, myPointA.y);
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointA.x, myPointA.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointB.x,myPointB.y));
|
||||
drawingStrokes.lastLineX = myPointA.x;
|
||||
drawingStrokes.lastLineY = myPointA.y;
|
||||
}else{
|
||||
drawingStrokes.strokesPath.lineTo(myPointB.x, myPointB.y);
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointB.x, myPointB.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointA.x,myPointA.y));
|
||||
drawingStrokes.lastLineX = myPointB.x;
|
||||
drawingStrokes.lastLineY = myPointB.y;
|
||||
}
|
||||
}else{
|
||||
if(!drawingStrokes.debug) {
|
||||
//填充
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(lastTop.x, lastTop.y);
|
||||
mPath.lineTo(lastBottom.x, lastBottom.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
mPath.lineTo(myPointA.x, myPointA.y);
|
||||
canvas.drawPath(mPath,mPaint);
|
||||
mPath.reset();
|
||||
}else {
|
||||
//测试
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(lastTop.x, lastTop.y);
|
||||
mPath.moveTo(lastBottom.x, lastBottom.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
}
|
||||
if(drawingStrokes.lastLineX == lastTop.x && drawingStrokes.lastLineY == lastTop.y){
|
||||
drawingStrokes.strokesPath.lineTo(myPointA.x, myPointA.y);
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointA.x, myPointA.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointB.x,myPointB.y));
|
||||
drawingStrokes.lastLineX = myPointA.x;
|
||||
drawingStrokes.lastLineY = myPointA.y;
|
||||
}else{
|
||||
drawingStrokes.strokesPath.lineTo(myPointB.x, myPointB.y);
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointB.x, myPointB.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointA.x,myPointA.y));
|
||||
drawingStrokes.lastLineX = myPointB.x;
|
||||
drawingStrokes.lastLineY = myPointB.y;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(!drawingStrokes.debug) {
|
||||
//填充
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(lastBottom.x, lastBottom.y);
|
||||
mPath.lineTo(lastTop.x, lastTop.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
mPath.lineTo(myPointA.x, myPointA.y);
|
||||
canvas.drawPath(mPath,mPaint);
|
||||
mPath.reset();
|
||||
}else {
|
||||
//测试
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(lastBottom.x, lastBottom.y);
|
||||
mPath.moveTo(lastTop.x, lastTop.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
}
|
||||
if(drawingStrokes.lastLineX == lastBottom.x && drawingStrokes.lastLineY == lastBottom.y){
|
||||
drawingStrokes.strokesPath.lineTo(myPointA.x, myPointA.y);
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointA.x, myPointA.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointB.x,myPointB.y));
|
||||
drawingStrokes.lastLineX = myPointA.x;
|
||||
drawingStrokes.lastLineY = myPointA.y;
|
||||
}else{
|
||||
drawingStrokes.strokesPath.lineTo(myPointB.x, myPointB.y);
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointB.x, myPointB.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointA.x,myPointA.y));
|
||||
drawingStrokes.lastLineX = myPointB.x;
|
||||
drawingStrokes.lastLineY = myPointB.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!drawingStrokes.debug) {
|
||||
//填充
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(myPointC.x, myPointC.y);
|
||||
mPath.lineTo(myPointD.x, myPointD.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
mPath.lineTo(myPointA.x, myPointA.y);
|
||||
canvas.drawPath(mPath,mPaint);
|
||||
mPath.reset();
|
||||
}else {
|
||||
//测试
|
||||
mPath.moveTo(myPointA.x, myPointA.y);
|
||||
mPath.lineTo(myPointC.x, myPointC.y);
|
||||
mPath.moveTo(myPointD.x, myPointD.y);
|
||||
mPath.lineTo(myPointB.x, myPointB.y);
|
||||
}
|
||||
if(drawingStrokes.lastLineX == myPointA.x && drawingStrokes.lastLineY == myPointA.y){
|
||||
drawingStrokes.strokesPath.lineTo(myPointC.x, myPointC.y);
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointC.x, myPointC.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointD.x,myPointD.y));
|
||||
drawingStrokes.lastLineX = myPointC.x;
|
||||
drawingStrokes.lastLineY = myPointC.y;
|
||||
}else{
|
||||
drawingStrokes.strokesPath.lineTo(myPointD.x, myPointD.y);
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointD.x, myPointD.y));
|
||||
drawingStrokes.myPoints.add(new TimePoint(myPointC.x,myPointC.y));
|
||||
drawingStrokes.lastLineX = myPointD.x;
|
||||
drawingStrokes.lastLineY = myPointD.y;
|
||||
}
|
||||
}
|
||||
if(drawingStrokes.isUp && i >= drawSteps -curveIndex ){
|
||||
// mPath.moveTo(myPointC.x, myPointC.y);
|
||||
// //控制点+结束点
|
||||
// mPath.lineTo(myPointD.x,myPointD.y);
|
||||
drawingStrokes.isUp = false;
|
||||
TimePoint A,B,C,D;
|
||||
if( myPointC.x != myPointD.x){
|
||||
k = (myPointC.y - myPointD.y) / (myPointC.x - myPointD.x);
|
||||
A = new TimePoint( (currentWidth )* (-k) / (float) Math.sqrt(k * k + 1) + myPointC.x,
|
||||
(currentWidth ) / (float) Math.sqrt(k * k + 1) + myPointC.y);
|
||||
B = new TimePoint( (-currentWidth )* (-k) / (float) Math.sqrt(k * k + 1) + myPointD.x,
|
||||
(-currentWidth ) / (float) Math.sqrt(k * k + 1) + myPointD.y);
|
||||
//当前点的上下端点MyPointC,MyPointD
|
||||
C = new TimePoint( (currentWidth )* (-k) / (float) Math.sqrt(k * k + 1) + myPointC.x,
|
||||
(currentWidth ) / (float) Math.sqrt(k * k + 1) + myPointC.y);
|
||||
D = new TimePoint( (-currentWidth )* (-k) / (float) Math.sqrt(k * k + 1) + myPointD.x,
|
||||
(-currentWidth ) / (float) Math.sqrt(k * k + 1) + myPointD.y);
|
||||
|
||||
}else{
|
||||
A = new TimePoint( currentWidth + myPointC.x,
|
||||
myPointC.y);
|
||||
B = new TimePoint( -currentWidth + myPointD.x,
|
||||
myPointD.y);
|
||||
C = new TimePoint( currentWidth + myPointC.x,
|
||||
myPointC.y);
|
||||
D = new TimePoint( -currentWidth + myPointD.x,
|
||||
myPointD.y);
|
||||
}
|
||||
TimePoint centerAC = new TimePoint((A.x+C.x)/2,(A.y+C.y)/2);
|
||||
TimePoint centerBD = new TimePoint((B.x+D.x)/2,(B.y+D.y)/2);
|
||||
boolean isAC = true;
|
||||
if( myPointC.x != myPointD.x){
|
||||
float b = myPointC.y - k *myPointC.x;
|
||||
if((centerAC.y - k* centerAC.x - b)*(drawingStrokes.mLastY - k*drawingStrokes.mLastX - b)<=0){
|
||||
isAC = true;
|
||||
}else {
|
||||
isAC = false;
|
||||
}
|
||||
}else{
|
||||
if((centerAC.y-myPointC.y)*(drawingStrokes.mLastY - myPointC.y)<=0){
|
||||
isAC = true;
|
||||
}else {
|
||||
isAC = false;
|
||||
}
|
||||
}
|
||||
mPath.moveTo(myPointC.x, myPointC.y);
|
||||
if(isAC){
|
||||
mPath.quadTo(centerAC.x,centerAC.y,myPointD.x,myPointD.y);
|
||||
if(drawingStrokes.lastLineX == myPointC.x&&drawingStrokes.lastLineY == myPointC.y) {
|
||||
drawingStrokes.strokesPath.quadTo(centerAC.x, centerAC.y, myPointD.x, myPointD.y);
|
||||
//rawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(centerAC.x, centerAC.y));
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointD.x, myPointD.y));
|
||||
}else{
|
||||
drawingStrokes.strokesPath.quadTo(centerAC.x, centerAC.y, myPointC.x, myPointC.y);
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(centerAC.x, centerAC.y));
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointC.x, myPointC.y));
|
||||
}
|
||||
}else{
|
||||
mPath.quadTo(centerBD.x,centerBD.y,myPointD.x,myPointD.y);
|
||||
if(drawingStrokes.lastLineX == myPointC.x&&drawingStrokes.lastLineY == myPointC.y) {
|
||||
drawingStrokes.strokesPath.quadTo(centerBD.x, centerBD.y, myPointD.x, myPointD.y);
|
||||
// drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(centerBD.x, centerBD.y));
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointD.x, myPointD.y));
|
||||
}else{
|
||||
drawingStrokes.strokesPath.quadTo(centerBD.x, centerBD.y, myPointC.x, myPointC.y);
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(centerBD.x, centerBD.y));
|
||||
//drawingStrokes.strokes.getMyPathList().get(drawingStrokes.strokes.getMyPathSize()-1).addPoint(new MyPoints(myPointC.x, myPointC.y));
|
||||
}
|
||||
}
|
||||
mPath.lineTo(myPointC.x, myPointC.y);
|
||||
canvas.drawPath(mPath,mPaint);
|
||||
mPath.reset();
|
||||
}
|
||||
lastTop.x = myPointC.x;
|
||||
lastTop.y = myPointC.y;
|
||||
lastBottom.x = myPointD.x;
|
||||
lastBottom.y = myPointD.y;
|
||||
drawingStrokes.mLastWidth = currentWidth;
|
||||
drawingStrokes.mLLastX = drawingStrokes.mLastX;
|
||||
drawingStrokes.mLLastY = drawingStrokes.mLastY;
|
||||
drawingStrokes.mLastX = x;
|
||||
drawingStrokes.mLastY = y;
|
||||
drawingStrokes.mLastK = k;
|
||||
drawingStrokes.state = currentState;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 毛笔*/
|
||||
public void drawBrushPen(DrawingStrokes drawingStrokes) {
|
||||
// if(drawingStrokes.debug)
|
||||
int[] colors = new int[] {
|
||||
Color.parseColor("#66111111"),
|
||||
Color.parseColor("#77111111"),
|
||||
Color.parseColor("#88111111")};
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mPaint.setStrokeWidth(1f);
|
||||
blurryPaint.setStrokeWidth(1f);
|
||||
blurryPaint.setColor(Color.RED);
|
||||
//blurryPaint.setColor(drawingStrokes.context.getResources().getColor(R.color.pencil_nine));
|
||||
// blurryPaint.setPathEffect(new DashPathEffect(new float[] {1f, 1f}, 0));
|
||||
blurryPaint.setStyle(Paint.Style.STROKE);
|
||||
//blurryPaint.setAlpha(100);
|
||||
//mPaint.setAlpha(250);
|
||||
// mPaint.setAntiAlias(false);
|
||||
// mPaint.setPathEffect(new DashPathEffect(new float[] {2f, 2f}, 0));
|
||||
//mPaint.setPathEffect(new DiscretePathEffect(3.0f, 5.0f));
|
||||
//mPaint.setPathEffect(new CornerPathEffect(10));
|
||||
// mPaint.setColor(drawingStrokes.context.getResources().getColor(R.color.pencil_two));
|
||||
mPaint.setColor(Color.parseColor("#111111"));
|
||||
//获得笔在两点间不同宽度的差值
|
||||
int drawSteps = (int) Math.floor(splineCurve.length());
|
||||
if (drawingStrokes.isUp) {
|
||||
//curveIndex = 1;
|
||||
if (drawSteps > 2)
|
||||
curveIndex = (drawSteps - 2) / 2;
|
||||
else curveIndex = 1;
|
||||
if (curveIndex < 1) curveIndex = 1;
|
||||
if (drawSteps == 0) drawSteps = 2;
|
||||
} else if (drawingStrokes.isDown) {
|
||||
curveIndex = 1;
|
||||
if (drawSteps == 0) drawSteps = 2;
|
||||
} else {
|
||||
if (drawSteps > 100) curveIndex = 40;
|
||||
else if (drawSteps > 80) curveIndex = 35;
|
||||
else if (drawSteps > 70) curveIndex = 30;
|
||||
else if (drawSteps > 60) curveIndex = 25;
|
||||
else if (drawSteps > 50) curveIndex = 20;
|
||||
else if (drawSteps > 40) curveIndex = 15;
|
||||
else if (drawSteps > 30) curveIndex = 13;
|
||||
else if (drawSteps > 20) curveIndex = 9;
|
||||
else if (drawSteps > 10) curveIndex = 7;
|
||||
else if (drawSteps >= 4) curveIndex = 3;
|
||||
else curveIndex = 1;
|
||||
}
|
||||
float widthDelta = endWidth - startWidth;
|
||||
//两点间实际轨迹距离
|
||||
if (drawSteps == 0) {
|
||||
drawSteps = 1;
|
||||
}
|
||||
Log.i("endWidth", " " + endWidth);
|
||||
// curveIndex = drawSteps/2;
|
||||
// if(curveIndex==0) curveIndex=1;
|
||||
for (float i = 0, num = 1; i < drawSteps; i += 0.5f, num++) {
|
||||
mPath.reset();
|
||||
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 * splineCurve.point1.x / 6.0f;
|
||||
x += (3 * ttt - 6 * tt + 4) * splineCurve.point2.x / 6.0f;
|
||||
x += (-3 * ttt + 3 * tt + 3 * t + 1) * splineCurve.point3.x / 6.0f;
|
||||
x += ttt * splineCurve.point4.x / 6.0f;
|
||||
float y = uuu * splineCurve.point1.y / 6.0f;
|
||||
y += (3 * ttt - 6 * tt + 4) * splineCurve.point2.y / 6.0f;
|
||||
y += (-3 * ttt + 3 * tt + 3 * t + 1) * splineCurve.point3.y / 6.0f;
|
||||
y += ttt * splineCurve.point4.y / 6.0f;
|
||||
float currentWidth = startWidth + t * widthDelta;
|
||||
// if (!drawingStrokes.isUp)
|
||||
// if (Math.abs(t * widthDelta) > 0.4f * num) {
|
||||
// if (t * widthDelta > 0)
|
||||
// currentWidth = startWidth + 0.4f * num;
|
||||
// else currentWidth = startWidth - 0.4f * num;
|
||||
// }
|
||||
// mPaint.setMaskFilter(new BlurMaskFilter(currentWidth, BlurMaskFilter.Blur.SOLID));
|
||||
// mPaint.setShadowLayer(currentWidth / 2, 0, 0, drawingStrokes.context.getResources().getColor(R.color.pencil_nine));
|
||||
if (drawingStrokes.isDown) {
|
||||
// canvas.drawLine(drawingStrokes.mLastX + currentWidth / 2, drawingStrokes.mLastY - currentWidth / 2, x + currentWidth / 2, y - currentWidth/ 2, blurryPaint);
|
||||
// mPaint.setStrokeWidth(1f);
|
||||
// mPaint.setColor(drawingStrokes.context.getResources().getColor(R.color.pencil_two));
|
||||
//canvas.drawOval(new RectF(x - currentWidth / 2, y - currentWidth / 2, x + currentWidth / 2, y + currentWidth / 2), blurryPaint);
|
||||
canvas.drawOval(new RectF(x - currentWidth / 2, y - currentWidth / 2, x + currentWidth / 2, y + currentWidth / 2), mPaint);
|
||||
drawingStrokes.mLastWidth = currentWidth;
|
||||
drawingStrokes.mLastX = x;
|
||||
drawingStrokes.mLastY = y;
|
||||
drawingStrokes.isDown = false;
|
||||
} else {
|
||||
// float width = currentWidth / 2;
|
||||
// while (width < currentWidth) {
|
||||
// canvas.drawLine(drawingStrokes.mLastX + width, drawingStrokes.mLastY - width , x + width, y - width, blurryPaint);
|
||||
// width += 0.5f;
|
||||
// }
|
||||
LinearGradient linearGradient = new LinearGradient(x - currentWidth / 2, y - currentWidth / 2, x + currentWidth / 2, y + currentWidth / 2, colors, null, Shader.TileMode.REPEAT);
|
||||
// RadialGradient radialGradient = new RadialGradient(x, y, currentWidth / 2, colors[1], colors[0], Shader.TileMode.MIRROR);
|
||||
blurryPaint.setShader(linearGradient);
|
||||
//mPaint.setAlpha(0);
|
||||
float k;
|
||||
if( x != drawingStrokes.mLastX) {
|
||||
k = Math.abs((drawingStrokes.mLastY - y) / (drawingStrokes.mLastX - x));
|
||||
Log.d("123","myk: " + k);
|
||||
if(k < 0.005) {
|
||||
canvas.drawLine(x , y - currentWidth, x , y - currentWidth / 4, blurryPaint);
|
||||
} else if(k < 0.05) {
|
||||
canvas.drawLine(x , y - currentWidth * 15 / 16, x , y - currentWidth / 4, blurryPaint);
|
||||
} else if( k < 0.1) {
|
||||
canvas.drawLine(x , y - currentWidth * 14 / 16, x , y - currentWidth / 4, blurryPaint);
|
||||
} else if(k < 0.3) {
|
||||
canvas.drawLine(x , y - currentWidth * 13 / 16, x , y - currentWidth / 4, blurryPaint);
|
||||
} else if(k < 0.5) {
|
||||
canvas.drawLine(x , y - currentWidth * 3 / 4, x , y - currentWidth / 4, blurryPaint);
|
||||
} else if(k > 100) {
|
||||
canvas.drawLine(x + currentWidth, y , x + currentWidth / 4, y, blurryPaint);
|
||||
} else if(k > 50) {
|
||||
canvas.drawLine(x + currentWidth * 15 / 16, y , x + currentWidth / 4, y, blurryPaint);
|
||||
} else if(k > 20) {
|
||||
canvas.drawLine(x + currentWidth * 14 / 16, y , x + currentWidth / 4, y, blurryPaint);
|
||||
} else if(k > 10) {
|
||||
canvas.drawLine(x + currentWidth * 13 / 16, y , x + currentWidth / 4, y, blurryPaint);
|
||||
} else if(k > 5) {
|
||||
canvas.drawLine(x + currentWidth * 3 / 4, y , x + currentWidth / 4, y, blurryPaint);
|
||||
} else {
|
||||
k = (drawingStrokes.mLastY - y) / (drawingStrokes.mLastX - x);
|
||||
//根据斜率计算另一点
|
||||
TimePoint myPointC = new TimePoint( (currentWidth * 11 / 16 )* (-k) / (float) Math.sqrt(k * k + 1) + x,
|
||||
(currentWidth * 11 / 16 ) / (float) Math.sqrt(k * k + 1) + y);
|
||||
TimePoint myPointD = new TimePoint( (-currentWidth * 11 / 16 )* (-k) / (float) Math.sqrt(k * k + 1) + x,
|
||||
(-currentWidth * 11 / 16 ) / (float) Math.sqrt(k * k + 1) + y);
|
||||
canvas.drawLine(myPointC.x, myPointC.y, x, y, blurryPaint);
|
||||
canvas.drawLine(myPointD.x, myPointD.y, x, y, blurryPaint);
|
||||
}
|
||||
} else {
|
||||
canvas.drawLine(x , y - currentWidth, x , y - currentWidth / 4, blurryPaint);
|
||||
}
|
||||
|
||||
//canvas.drawOval(new RectF(x + currentWidth , y - currentWidth , x , y ), blurryPaint);
|
||||
//mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
|
||||
canvas.drawOval(new RectF(x - currentWidth / 2, y - currentWidth / 2, x + currentWidth / 2, y + currentWidth / 2), mPaint);
|
||||
drawingStrokes.mLastWidth = currentWidth;
|
||||
drawingStrokes.mLastX = x;
|
||||
drawingStrokes.mLastY = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
141
baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/Strokes.java
Executable file
141
baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/Strokes.java
Executable file
@ -0,0 +1,141 @@
|
||||
package com.tenlionsoft.baselib.core.widget.pens;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Author:Double
|
||||
* Time:2019/4/22
|
||||
* Description:This is Strokes
|
||||
*/
|
||||
public class Strokes {
|
||||
//当前笔划列表
|
||||
private Vector<Stroke> myPath = null;
|
||||
//保存删除 移动 旋转等更新后回收的笔划
|
||||
private Vector<Stroke> recycleStrokesList = null;
|
||||
//恢复操作保存的笔划
|
||||
private Vector<Stroke> unDoStrokesList = null;
|
||||
public Strokes(){
|
||||
myPath = new Vector<>();
|
||||
recycleStrokesList = new Vector<>();
|
||||
unDoStrokesList = new Vector<>();
|
||||
}
|
||||
public int getRecycleStrokesListSize(){
|
||||
return recycleStrokesList.size();
|
||||
}
|
||||
public int getMyPathSize(){
|
||||
return myPath.size();
|
||||
}
|
||||
public Vector<Stroke> getRecycleStrokesList(){
|
||||
return recycleStrokesList;
|
||||
}
|
||||
public Vector<Stroke> getMyPathList(){
|
||||
return myPath;
|
||||
}
|
||||
public Vector<Stroke> getUnDoStrokesList(){
|
||||
return unDoStrokesList;
|
||||
}
|
||||
|
||||
|
||||
public void addMyPath(int location, int priority) {
|
||||
myPath.add(new Stroke(location,priority));
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas,Paint paint){
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
for(int i = 0;i < myPath.size(); i++){
|
||||
if(myPath.size() == 0) break;
|
||||
Path stroke = myPath.elementAt(i).getStroke();
|
||||
if(!stroke.isEmpty()){
|
||||
canvas.drawPath(stroke,paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void deleteMyPath(int index){
|
||||
myPath.remove(index);
|
||||
}
|
||||
public void deleteRecycleStrokesList(int index){
|
||||
recycleStrokesList.remove(index);
|
||||
}
|
||||
public void deleteUnDoStrokesList(int index){
|
||||
unDoStrokesList.remove(index);
|
||||
}
|
||||
public void clearUnDoStrokesList(){
|
||||
checkUnDoNull();
|
||||
unDoStrokesList.clear();
|
||||
}
|
||||
public void checkUnDoNull(){
|
||||
if(unDoStrokesList==null){
|
||||
unDoStrokesList = new Vector<>();
|
||||
}
|
||||
}
|
||||
public void addUnDoStrokes(Stroke stroke){
|
||||
checkUnDoNull();
|
||||
unDoStrokesList.add(stroke);
|
||||
}
|
||||
public class Stroke{
|
||||
private Path stroke;
|
||||
private int location;//删除笔划原来所在笔划列表中的位置
|
||||
private int priority;//所有笔划执行撤销动作的优先级
|
||||
private Vector<TimePoint> points; //拟合后的几个点
|
||||
private Vector<TimePoint> originPoints;//最原始的几个点
|
||||
private Vector<Float> originWidth;
|
||||
public Stroke(int index,int priority){
|
||||
this.stroke = new Path();
|
||||
this.location = index;
|
||||
this.priority = priority;
|
||||
this.points = new Vector<>();
|
||||
originWidth = new Vector<>();
|
||||
originPoints = new Vector<>();
|
||||
}
|
||||
public Path getStroke(){
|
||||
return stroke;
|
||||
}
|
||||
public void setStroke(Path path){
|
||||
stroke = new Path(path);
|
||||
}
|
||||
public Vector<TimePoint> getOriginPoints(){
|
||||
return originPoints;
|
||||
}
|
||||
public void setOriginPoints(Vector<TimePoint> timePoints){
|
||||
this.originPoints = timePoints;
|
||||
}
|
||||
public void setOriginWidth(Vector<Float> originWidth){
|
||||
this.originWidth = originWidth;
|
||||
}
|
||||
public void addOriginPoint(TimePoint myPoints){
|
||||
originPoints.add(myPoints);
|
||||
}
|
||||
public Vector<Float> getOriginWidth(){
|
||||
return originWidth;
|
||||
}
|
||||
public void addOriginWidth(float width){
|
||||
originWidth.add(width);
|
||||
}
|
||||
public void addPoint(TimePoint point){
|
||||
points.add(point);
|
||||
}
|
||||
public Vector<TimePoint> getPoints(){
|
||||
return points;
|
||||
}
|
||||
public int getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(int location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package com.tenlionsoft.baselib.core.widget.pens;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
/**
|
||||
* Author:Double
|
||||
* Time:2019/4/22
|
||||
* Description:This is StrokesView
|
||||
*/
|
||||
public class StrokesView extends View{
|
||||
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
//笔划
|
||||
private Strokes strokes;
|
||||
private DrawingStrokes mDrawing;
|
||||
private PenType penType;
|
||||
public StrokesView(Context context, AttributeSet attributeSet){
|
||||
super(context,attributeSet);
|
||||
strokes = new Strokes();
|
||||
mDrawing = new DrawingStrokes(this, strokes);
|
||||
mDrawing.setMaxWidth(2);//刚笔
|
||||
penType = new PenType();
|
||||
penType.setPenType(PenType.PEN);
|
||||
mDrawing.setPenType(penType);
|
||||
}
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if(mDrawing != null) {
|
||||
mDrawing.setSize(canvas.getWidth(),canvas.getHeight(),mPaint);
|
||||
mDrawing.draw(canvas, mPaint);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
int action = event.getAction();
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
mDrawing.moveTo(event.getX(), event.getY(), event.getPressure());
|
||||
} else if(action == MotionEvent.ACTION_MOVE){
|
||||
int historySize = event.getHistorySize();
|
||||
for (int i = 0; i < historySize; i++) {
|
||||
float historicalX = event.getHistoricalX(i);
|
||||
float historicalY = event.getHistoricalY(i);
|
||||
//判断两点之间的距离是否太短
|
||||
double distance = Math.sqrt((historicalX - mDrawing.mPoint.get(mDrawing.mPoint.size() - 1).getX())
|
||||
* (historicalX - mDrawing.mPoint.get(mDrawing.mPoint.size() - 1).getX())
|
||||
+ (historicalY - mDrawing.mPoint.get(mDrawing.mPoint.size() - 1).getY())
|
||||
* (historicalY - mDrawing.mPoint.get(mDrawing.mPoint.size() - 1).getY()));
|
||||
if(mDrawing.mPoint.size() > 0 && distance > 0.2)
|
||||
mDrawing.lineTo(historicalX, historicalY, event.getHistoricalPressure(i),false);
|
||||
}
|
||||
}else if(action == MotionEvent.ACTION_UP) {
|
||||
mDrawing.lineTo(event.getX(), event.getY(), event.getPressure(),true);
|
||||
}
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void reDo() {
|
||||
mDrawing.reDo();
|
||||
}
|
||||
|
||||
public void unDo() {
|
||||
mDrawing.unDo();
|
||||
}
|
||||
|
||||
public void recover() {
|
||||
mDrawing.recover();
|
||||
}
|
||||
|
||||
public void setPenType(int penType) {
|
||||
this.penType.setPenType(penType);
|
||||
switch (penType) {
|
||||
case PenType.BRUSH:
|
||||
mDrawing.setMaxWidth(8);//毛笔
|
||||
break;
|
||||
case PenType.PEN:
|
||||
mDrawing.setMaxWidth(2);//刚笔
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
mDrawing.onDestroy();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
package com.tenlionsoft.baselib.core.widget.pens;
|
||||
|
||||
/**
|
||||
* Author:Double
|
||||
* Time:2019/4/22
|
||||
* Description:This is TimePoint
|
||||
*/
|
||||
public class TimePoint {
|
||||
public float x;
|
||||
public float y;
|
||||
public long timestamp;
|
||||
public TimePoint(){};
|
||||
public TimePoint(float x, float y){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
// this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
public TimePoint(float x, float y, long time){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.timestamp = time;
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
//获得两个点间的速度
|
||||
public float velocityFrom(TimePoint start){
|
||||
return distanceTo(start) / (this.timestamp - start.timestamp);
|
||||
}
|
||||
//获得两个点间的距离
|
||||
public float distanceTo(TimePoint point){
|
||||
return (float) Math.sqrt(Math.pow(point.x - this.x, 2) + Math.pow(point.y - this.y, 2));
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ import com.tenlionsoft.baselib.core.retrofit_net.conver.RxTransformer;
|
||||
import com.tenlionsoft.baselib.core.widget.base.BaseFragment;
|
||||
import com.tenlionsoft.baselib.core.widget.base.FragmentUtils;
|
||||
import com.tenlionsoft.baselib.core.widget.base.FunctionTitleNumAdapter;
|
||||
import com.tenlionsoft.baselib.core.widget.views.CustomHandWritingDialog;
|
||||
import com.tenlionsoft.baselib.core.widget.views.CustomStateView;
|
||||
import com.tenlionsoft.baselib.core.widget.views.ItemSplitDivider;
|
||||
import com.tenlionsoft.baselib.utils.ExceptionHandler;
|
||||
|
Loading…
Reference in New Issue
Block a user