diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/BasePen.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/BasePen.java index 96eb49a..b715688 100755 --- a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/BasePen.java +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/BasePen.java @@ -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 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); + } + + } + /** * 绘制 * 当现在的点和触摸点的位置在一起的时候不用去绘制 diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/PaintView.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/PaintView.java index 2d0f4ec..879a740 100755 --- a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/PaintView.java +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/PaintView.java @@ -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(); + } + /** * 释放 diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/SteelPen.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/SteelPen.java index 8fbcdd1..48666a6 100755 --- a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/SteelPen.java +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/handsign/SteelPen.java @@ -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 diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/DrawingStrokes.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/DrawingStrokes.java new file mode 100755 index 0000000..f072dc6 --- /dev/null +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/DrawingStrokes.java @@ -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 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 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)=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(); + } +} diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/PenType.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/PenType.java new file mode 100755 index 0000000..2a7699e --- /dev/null +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/PenType.java @@ -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; + } +} diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/SplineCurve.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/SplineCurve.java new file mode 100755 index 0000000..1afd3ea --- /dev/null +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/SplineCurve.java @@ -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; + } +} diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/SplineCurveStrategy.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/SplineCurveStrategy.java new file mode 100755 index 0000000..c19dcdf --- /dev/null +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/SplineCurveStrategy.java @@ -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; + } + } + } +} diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/Strokes.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/Strokes.java new file mode 100755 index 0000000..0d25ed5 --- /dev/null +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/Strokes.java @@ -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 myPath = null; + //保存删除 移动 旋转等更新后回收的笔划 + private Vector recycleStrokesList = null; + //恢复操作保存的笔划 + private Vector 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 getRecycleStrokesList(){ + return recycleStrokesList; + } + public Vector getMyPathList(){ + return myPath; + } + public Vector 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 points; //拟合后的几个点 + private Vector originPoints;//最原始的几个点 + private Vector 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 getOriginPoints(){ + return originPoints; + } + public void setOriginPoints(Vector timePoints){ + this.originPoints = timePoints; + } + public void setOriginWidth(Vector originWidth){ + this.originWidth = originWidth; + } + public void addOriginPoint(TimePoint myPoints){ + originPoints.add(myPoints); + } + public Vector getOriginWidth(){ + return originWidth; + } + public void addOriginWidth(float width){ + originWidth.add(width); + } + public void addPoint(TimePoint point){ + points.add(point); + } + public Vector 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; + } + } + +} diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/StrokesView.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/StrokesView.java new file mode 100755 index 0000000..1fc3a37 --- /dev/null +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/StrokesView.java @@ -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(); + } +} + diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/TimePoint.java b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/TimePoint.java new file mode 100755 index 0000000..2c5866e --- /dev/null +++ b/baselib/src/main/java/com/tenlionsoft/baselib/core/widget/pens/TimePoint.java @@ -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)); + } +} diff --git a/oamodule/src/main/java/com/tenlionsoft/oamodule/pad/fragments/PadOaMainFragment.java b/oamodule/src/main/java/com/tenlionsoft/oamodule/pad/fragments/PadOaMainFragment.java index 850edf2..c4c87ac 100644 --- a/oamodule/src/main/java/com/tenlionsoft/oamodule/pad/fragments/PadOaMainFragment.java +++ b/oamodule/src/main/java/com/tenlionsoft/oamodule/pad/fragments/PadOaMainFragment.java @@ -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;