From 967913691a2496ac011a72ad1c406467028b5884 Mon Sep 17 00:00:00 2001 From: laixingyu Date: Thu, 1 Dec 2022 15:53:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E5=B7=A5?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SWPosPointcut.cpp | 796 +++++++++++ SWPosPointcut.h | 327 +++++ SignPenAppTablet.pro | 52 + SignPenAppTablet.qrc | 5 + etc/qt.conf | 2 + main.cpp | 11 + mainwindow.cpp | 507 +++++++ mainwindow.h | 97 ++ mainwindow.ui | 73 + signpaintercachethread.cpp | 2167 +++++++++++++++++++++++++++++ signpaintercachethread.h | 125 ++ signpaintercachethread_linux.cpp | 2202 ++++++++++++++++++++++++++++++ signpaintercachethread_linux.h | 127 ++ signpenpainter.cpp | 1312 ++++++++++++++++++ signpenpainter.h | 108 ++ signpenstructs.h | 122 ++ signutils.cpp | 253 ++++ signutils.h | 18 + sw_log.cpp | 114 ++ sw_log.h | 36 + wintab/Utils.cpp | 171 +++ wintab/Utils.h | 97 ++ wintab/WINTAB.H | 930 +++++++++++++ 23 files changed, 9652 insertions(+) create mode 100644 SWPosPointcut.cpp create mode 100644 SWPosPointcut.h create mode 100644 SignPenAppTablet.pro create mode 100644 SignPenAppTablet.qrc create mode 100644 etc/qt.conf create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 signpaintercachethread.cpp create mode 100644 signpaintercachethread.h create mode 100644 signpaintercachethread_linux.cpp create mode 100644 signpaintercachethread_linux.h create mode 100644 signpenpainter.cpp create mode 100644 signpenpainter.h create mode 100644 signpenstructs.h create mode 100644 signutils.cpp create mode 100644 signutils.h create mode 100644 sw_log.cpp create mode 100644 sw_log.h create mode 100644 wintab/Utils.cpp create mode 100644 wintab/Utils.h create mode 100644 wintab/WINTAB.H diff --git a/SWPosPointcut.cpp b/SWPosPointcut.cpp new file mode 100644 index 0000000..f8db738 --- /dev/null +++ b/SWPosPointcut.cpp @@ -0,0 +1,796 @@ +// +// SWPosPointcut.c +// DrawTest +// +// Created by 王阳阳 on 2022/9/6. +// + +#include "SWPosPointcut.h" +#include + +#define MaxPoints 6000.f +#define MaxSegment 100.f +#define MaxWidthScale 1.5f +#define MinRadius 0.3f +#define MaxSteps 0.13f +#define MinShake 130 +#define MaxShake 170 +#define M_PI 3.14159265358979323846264338327950288f +#define RadianTodegrees(x) (x * 180.f / M_PI) + +static SWPosPoint lastePos; +static SWLineSegment *curLeftLine = NULL; +static SWLineSegment *curRightLine = NULL; +static int pointStep = 0; + +void SWPosRest(SWPosPoint pos) { + + lastePos = pos; + pointStep = 0; + SWLineSegment *onSegment = curLeftLine; + if (curLeftLine != NULL) { + + while (onSegment) { + + SWLineSegment *tempSeg = (SWLineSegment *)onSegment->preSegment; + onSegment->preSegment = NULL; + free(onSegment); + if (tempSeg != NULL) { + + onSegment = tempSeg; + + } else { + + onSegment = NULL; + } + + } + } + onSegment = curRightLine; + if (curRightLine != NULL) { + + while (onSegment) { + + SWLineSegment *tempSeg = (SWLineSegment *)onSegment->preSegment; + onSegment->preSegment = NULL; + free(onSegment); + if (tempSeg != NULL) { + + onSegment = tempSeg; + + } else { + + onSegment = NULL; + } + + } + } + curLeftLine = NULL; + curRightLine = NULL; + +} + +SWPosRet SWGetTangentcurPoint(SWPosPoint prevPoint,SWPosPoint curPoint, + SWLineSegment leftLine,SWLineSegment rightLine, + int circle) { + + double distance = GetPointDistance(prevPoint, curPoint); + double radiusDistance = (prevPoint.radius + curPoint.radius); + if ((distance < radiusDistance) || distance < 1) { + + if (prevPoint.realPoint.x != lastePos.realPoint.x && prevPoint.realPoint.y != lastePos.realPoint.y){ + + double rads = SWBetweenLinesrads(lastePos.realPoint, prevPoint.realPoint, + curPoint.realPoint, prevPoint.realPoint); + double angle = RadianTodegrees(rads); + if (angle > 150) { + + SWPosRet retPos; + retPos.prevLeftPoint = SWPointCutMake(0, 0); + retPos.prevLeftIntersectPoint = SWPointCutMake(0, 0); + retPos.prevRightPoint = SWPointCutMake(0, 0); + retPos.prevRightIntersectPoint = SWPointCutMake(0, 0); + retPos.curLeftPoint = SWPointCutMake(0, 0); + retPos.curRightPoint = SWPointCutMake(0, 0); + retPos.circlePoints.clear(); + retPos.circleCount = 0; + retPos.status = SWPosRetFail; + return retPos; + } + + } + + } + if (circle == 1 || pointStep == 0) { + + return getCircleSegments(prevPoint, curPoint, leftLine, rightLine, distance,pointStep); + + } + if (distance > fabs(prevPoint.radius - curPoint.radius)) { + + SWPointcut pointFa= {0,0};//左侧切点 + SWPointcut pointFa1 = {0,0};//右侧切点 + SWPointcut pointFb = {0,0};//左侧切点 + SWPointcut pointFb1 = {0,0};//右侧切点 + + double base = atan2(curPoint.realPoint.y - prevPoint.realPoint.y, curPoint.realPoint.x - prevPoint.realPoint.x); + double ang = acos((prevPoint.radius - curPoint.radius) / distance); + pointFa = GetMaleTangentPointValue(prevPoint, base + ang); + pointFb = GetMaleTangentPointValue(curPoint, base + ang); + pointFb1 = GetMaleTangentPointValue(curPoint, base - ang); + pointFa1 = GetMaleTangentPointValue(prevPoint, base - ang); + SWPointcut pointLeftIntersect = {0,0};//左侧切点 + SWPointcut pointRightIntersect = {0,0};//右侧切点 + if (leftLine.status == SWPosRetFail && rightLine.status == SWPosRetFail) { + + pointStep++; + lastePos = prevPoint; + SWPosRet retPos1; + retPos1.prevLeftPoint = pointFa;//左侧切点 + retPos1.prevLeftIntersectPoint = pointLeftIntersect;//左侧切点交点 + retPos1.prevRightPoint = pointFa1;//右侧切点 + retPos1.prevRightIntersectPoint = pointRightIntersect;//右侧切点交点 + retPos1.curLeftPoint = pointFb;//当前点左侧切点 + retPos1.curRightPoint = pointFb1;//当前点右侧切点 + retPos1.circlePoints.clear(); + retPos1.circleCount = 0; + retPos1.status = SWPosRetSuccess;//计算结果状态 + return retPos1; + } + + pointRightIntersect = SWgetEdgePoint(rightLine.startPoint,rightLine.endPoint,pointFa1,pointFb1,prevPoint.realPoint,0); + pointLeftIntersect = SWgetEdgePoint(leftLine.startPoint,leftLine.endPoint,pointFa,pointFb,prevPoint.realPoint,1); + if ((pointRightIntersect.x == 0 && pointRightIntersect.y ==0) || (pointLeftIntersect.x == 0 && pointLeftIntersect.y == 0)) { + + return getCircleSegments(prevPoint, curPoint, leftLine, rightLine, distance,pointStep); + } + /** + * 处理切点极端情况(0,0) + */ + double lDistance = GetPointDistance(prevPoint,SWPosPointMake(pointLeftIntersect.x,pointLeftIntersect.y,0)); + if (lDistance > prevPoint.radius*10) { + + pointLeftIntersect = SWPointCutMake((leftLine.endPoint.x + pointFa.x)/2.f,(leftLine.endPoint.y + pointFa.y)/2.f); + } + double rDistance = GetPointDistance(prevPoint,SWPosPointMake(pointRightIntersect.x,pointRightIntersect.y,0)); + if (rDistance > prevPoint.radius*10) { + + pointRightIntersect = SWPointCutMake((rightLine.endPoint.x + pointFa1.x)/2.f,(rightLine.endPoint.y + pointFa1.y)/2.f); + } + SWPosRet retPos2; + retPos2.prevLeftPoint = pointFa;//左侧切点 + retPos2.prevLeftIntersectPoint = pointLeftIntersect;//左侧切点交点 + retPos2.prevRightPoint = pointFa1;//右侧切点 + retPos2.prevRightIntersectPoint = pointRightIntersect;//右侧切点交点 + retPos2.curLeftPoint = pointFb;//当前点左侧切点 + retPos2.curRightPoint = pointFb1;//当前点右侧切点 + retPos2.circlePoints.clear(); + retPos2.circleCount = 0; + retPos2.status = SWPosRetSuccess;//计算结果状态 + lastePos = prevPoint; + pointStep++; + return retPos2; + + } + SWPosRet retPos; + retPos.prevLeftPoint = SWPointCutMake(0, 0); + retPos.prevLeftIntersectPoint = SWPointCutMake(0, 0); + retPos.prevRightPoint = SWPointCutMake(0, 0); + retPos.prevRightIntersectPoint = SWPointCutMake(0, 0); + retPos.curLeftPoint = SWPointCutMake(0, 0); + retPos.curRightPoint = SWPointCutMake(0, 0); + retPos.circlePoints.clear(); + retPos.circleCount = 0; + retPos.status = SWPosRetFail; + return retPos; +} + +SWPosRet getCircleSegments(SWPosPoint prevPoint,SWPosPoint curPoint,SWLineSegment leftLine, + SWLineSegment rightLine,double distance,int step) { + + SWPointcut controlPoint = SWPointCutMake(prevPoint.realPoint.x, prevPoint.realPoint.y); + int segements = distance/0.2f; + if (segements < 5) { + + segements = 5; + } + double preRadius = 0; + if (leftLine.status == SWPosRetSuccess && rightLine.status == SWPosRetSuccess) { + + preRadius = GetPointDistance(SWPosPointMake(leftLine.endPoint.x, leftLine.endPoint.y, 0), + SWPosPointMake(rightLine.endPoint.x, rightLine.endPoint.y, 0))/2.f; + + } else { + + preRadius = prevPoint.radius; + } + double circleRadius = curPoint.radius - preRadius; + QList circleAry; + for (int i = 0; i < segements; i ++) { + + if (i == 0) { + + SWCirclePoint cPoint = SWCircleMake(SWPosPointMake(prevPoint.realPoint.x, + prevPoint.realPoint.y, preRadius)); + circleAry.append(cPoint); + + } else if (i == (segements - 1)) { + + SWCirclePoint cPoint = SWCircleMake(SWPosPointMake(curPoint.realPoint.x, + curPoint.realPoint.y, preRadius + circleRadius)); + circleAry.append(cPoint); + + } else { + + double t = (double)i/segements; + double x = pow(1 - t, 2) * prevPoint.realPoint.x + 2.0 * (1 - t) * t * controlPoint.x + t * t * curPoint.realPoint.x; + double y = pow(1 - t, 2) * prevPoint.realPoint.y + 2.0 * (1 - t) * t * controlPoint.y + t * t * curPoint.realPoint.y; + SWCirclePoint cPoint = SWCircleMake(SWPosPointMake(x, y, preRadius + circleRadius*t)); + circleAry.append(cPoint); + } + + } + pointStep++; + SWPosRet retPos; + retPos.prevLeftPoint = SWPointCutMake(0, 0);//左侧切点 + retPos.prevLeftIntersectPoint = SWPointCutMake(0, 0);//左侧切点交点 + retPos.prevRightPoint = SWPointCutMake(0, 0);//右侧切点 + retPos.prevRightIntersectPoint = SWPointCutMake(0, 0);//右侧切点交点 + retPos.curLeftPoint = SWPointCutMake(0, 0);//当前点左侧切点 + retPos.curRightPoint = SWPointCutMake(0, 0);//当前点右侧切点 + retPos.circlePoints = circleAry; + retPos.circleCount = segements; + retPos.status = SWPosRetSuccess;//计算结果状态 + return retPos; +} + + +QList fillPoints(SWPosPoint prevPoint,SWPosPoint curPoint,double distance) { + + SWPointcut controlPoint = SWPointCutMake(prevPoint.realPoint.x, prevPoint.realPoint.y); + int segements = distance/0.5f; + double preRadius = prevPoint.radius; + double circleRadius = curPoint.radius - preRadius; + QList circleAry; + for (int i = 0; i < segements; i ++) { + + double t = (double)i/segements; + double x = pow(1 - t, 2) * prevPoint.realPoint.x + 2.0 * (1 - t) * t * controlPoint.x + t * t * curPoint.realPoint.x; + double y = pow(1 - t, 2) * prevPoint.realPoint.y + 2.0 * (1 - t) * t * controlPoint.y + t * t * curPoint.realPoint.y; + SWPosPoint cPoint = SWPosPointMake(x, y, preRadius + circleRadius*t); + circleAry.append(cPoint); + } + return circleAry; +} + + +SWPosStatus IsPointInMatrix(SWPointcut p1 ,SWPointcut p2,SWPointcut p3 ,SWPointcut p4,SWPointcut p) +{ + if (GetCross(p1,p2,p) * GetCross(p3,p4,p) >= 0 && GetCross(p2,p3,p) * GetCross(p4,p1,p) >= 0) { + + return SWPosRetSuccess; + + } else { + + return SWPosRetFail; + } + +} + +double GetCross(SWPointcut p1, SWPointcut p2,SWPointcut p) +{ + return (p2.x - p1.x) * (p.y - p1.y) -(p.x - p1.x) * (p2.y - p1.y); +} + + +SWPointcut SWratioPoint(SWPointcut startPoint, SWPointcut endPoint, double ratio) { + + SWPointcut ret = {0,0}; + double x = endPoint.x - startPoint.x; + double y = endPoint.y - startPoint.y; + ret.x = x*ratio + startPoint.x; + ret.y = y*ratio + startPoint.y; + return ret; + +} + +SWPointcut SWrotatePoint(SWPointcut point, SWPointcut center, double angle) { + + SWPointcut ret = {0,0}; + double x = point.x - center.x; + double y = point.y - center.y; + ret.x = (x*cos(angle) - y*sin(angle)) + center.x; + ret.y = (x*sin(angle) + y*cos(angle)) + center.y; + return ret; +} + +SWPointcut GetMaleTangentPointValue(SWPosPoint point, double a) +{ + SWPointcut ret = {0,0}; + ret.x = (double) (point.realPoint.x + point.radius * cos(a)); + ret.y = (double) (point.realPoint.y + point.radius * sin(a)); + return ret; +} + +SWPointcut SWgetEdgePoint(SWPointcut a, SWPointcut b, SWPointcut c,SWPointcut d,SWPointcut e,int leftLine) { + + + double dx1 = a.x - b.x; + double dy1 = a.y - b.y; + double dx2 = d.x - c.x; + double dy2 = d.y - c.y; + SWPointcut edgePointf = {0,0}; + SWPointcut pointf = {0,0}; + if (dx1 == 0 && dx2 != 0) {//ab垂直x轴 + double k2 = dy2 / dx2;//第二条直线斜率 + double h2 = d.y - k2 * d.x;//第二条直线截距 + //交点在a.x或者b.x + double x = a.x; + double y = k2 * x + h2; + pointf = SWPointCutMake(x,y); + if (isPointOnLine(x, y, a, b) == 1 && isPointOnLine(x, y, c, d) == 1) {//焦点在线段上 + + edgePointf = pointf; + } + } else if (dx1 != 0 && dx2 == 0) {//cd垂直x轴 + double k1 = dy1 / dx1;//第一条直线斜率 + double h1 = b.y - k1 * b.x;//第一条直线的截距 + //交点在c.x或者d.x + double x = c.x; + double y = k1 * x + h1; + pointf = SWPointCutMake(x,y); + if (isPointOnLine(x, y, a, b) == 1 && isPointOnLine(x, y, c, d) == 1) {//焦点在线段上 + edgePointf = pointf; + } + } else if (dx1 == 0 && dx2 == 0) {//ab cd都垂直x轴 + //无交点 + } else { + double k1 = dy1 / dx1;//第一条直线斜率 + double h1 = b.y - k1 * b.x;//第一条直线的截距 + double k2 = dy2 / dx2;//第二条直线斜率 + double h2 = d.y - k2 * d.x;//第二条直线截距 + if (k1 == k2) {//两直线平行 + if (h1 == h2) {//重合 + + } else {//平行 + + } + } else { + double x = (h1 - h2) / (k2 - k1); + double y = k1 * x + h1; + pointf = SWPointCutMake(x,y); + if (isPointOnLine(x, y, a, b) == 1 && isPointOnLine(x, y, c, d) == 1) {//焦点在线段上 + edgePointf = pointf; + } + } + } + if (edgePointf.x > 0 && edgePointf.y > 0) {//有交点 + return edgePointf; + } else {//无交点 + // // 向量1的坐标:(x1,y1),向量2的坐标:(x2,y2); 则 + double tmpDegree = getAngle(dx1, dy1, dx2, dy2); + if ((pointf.x > 0 && pointf.y > 0) && tmpDegree >= 90 && tmpDegree < 180) { + + return pointf; + } else if (tmpDegree == 180) { + + return b; + } else { + + //角度小于阈值进行补点操作 + if (tmpDegree <= 90) { + + return SWPointCutMake(0,0); + + } else { + + double rads = SWBetweenLinesrads(b, e, c, e); + double angle = RadianTodegrees(rads); + if (leftLine == 1) { + + return SWrotatePoint(b,e,angle/2.f); + + } else { + + return SWrotatePoint(c,e,angle/2.f); + } + + } + } + } + + +} + + +int isPointOnLine(double x, double y, SWPointcut start, SWPointcut end) { + + if (start.x <= end.x) { + if (x < start.x || x > end.x) return 0; + } else { + if (x < end.x || x > start.x) return 0; + } + if (start.y <= end.y) { + if (y < start.y || y > end.y) return 0; + } else { + if (y < end.y || y > start.y) return 0; + } + return 1; +} + +double getAngle(double x1, double y1, double x2, double y2) { + float value = (x1 * x2 + y1 * y2) / (hypot(x1, y1) * hypot(x2, y2)); // 余弦值 + if(value < -1) { + + value = -1; + } + if(value > 1) { + + value = 1; + } + double angle = RadianTodegrees(acos(value)); // 角度 + return angle; +} + + +SWPointcut getSamllAngleVertex(SWPointcut b, SWPointcut c,double cosAngle) { + double dx = c.x - b.x; + double dy = c.y - b.y; + // double disBC = Math.hypot(dx, dy); + // double betweenP = Math.cos((45f / 180f) * Math.PI) * disBC; + double ratio = (double) cos((cosAngle / 180.f) * M_PI); + SWPointcut betweenP = SWPointCutMake(b.x + dx * ratio, b.y + dy * ratio); + SWPointcut anglePointf = calcNewPoint(betweenP, b, (cosAngle / 180.f) * M_PI); + return anglePointf; +} +SWPointcut SWExtendPoint(SWPointcut a, SWPointcut b, SWPointcut c,SWPointcut d) { + + SWPointcut point = {0,0}; + double k1 = 0; + double k2 = 0; + int k1Vaild = 0; + int k2Vaild = 0; + double b1 = 0; + double b2 = 0; + if (b.x != a.x) { + + k1 = (b.y - a.y)/(b.x - a.x); + k1Vaild = 1; + + } + if (d.x != c.x) { + + k2 = (d.y - c.y)/(d.x - c.x); + k2Vaild = 1; + + } + if ( (k1Vaild == k2Vaild) && k1 == k2) { + + return point; + + } + if (k1Vaild == 1) { + + b1 = (b.x*a.y - a.x*b.y)/(b.x - a.x); + } + if (k2Vaild == 1) { + + b2 = (d.x*c.y - c.x*d.y)/(d.x - c.x); + + } + + if (k1Vaild == 0) { + + point.x = a.x; + point.y = k2 * point.x + b2; + + } else if (k2Vaild == 0) { + + point.x = c.x; + point.y = k1 *point.x + b1; + + } else if (k1 == 0) { + + point.x = (a.y - b2)/k2; + point.y = a.y; + + + } else if (k2 == 0) { + + point.x = (c.y - b1)/k1; + point.y = c.y; + + + } else { + + point.x = (double)((b2 - b1) / (k1 - k2)); + point.y = (double)((k2 * b1 - k1 * b2) / (k2 - k1)); + + } + return point; + +} + +double GetPointDistance(SWPosPoint start, SWPosPoint end) { + + return sqrtf(pow((start.realPoint.x - end.realPoint.x), 2) + pow((start.realPoint.y - end.realPoint.y), 2))/1.f; +} + +SWPointcut SWPointCutMake(double x,double y) { + + SWPointcut pointCut = {x,y}; + return pointCut; +} + +SWPosPoint SWPosPointMake(double x,double y,double radius) { + + SWPosPoint posPoint = {{x,y},radius}; + return posPoint; +} + +SWPointcut calcNewPoint(SWPointcut p, SWPointcut pCenter, double theta) { + double cosv = (double) cos(theta); + double sinv = (double) sin(theta); + + // calc new point + double newX = (p.x - pCenter.x) * cosv - (p.y - pCenter.y) * sinv + pCenter.x; + double newY = (p.x - pCenter.x) * sinv + (p.y - pCenter.y) * cosv + pCenter.y; + return SWPointCutMake(newX, newY); +} + +SWLineSegment SWLineMake(double x1,double y1,double x2, double y2) { + + // SWLineSegment linePoint = {{x1,y1},{x2,y2},SWPosRetSuccess,NULL}; + SWLineSegment linePoint; + // linePoint.startPoint = {x1,y1}; + linePoint.startPoint.x = x1; + linePoint.startPoint.y = y1; + // linePoint.endPoint = {x2,y2}; + linePoint.endPoint.x = x2; + linePoint.endPoint.y = y2; + linePoint.status = SWPosRetSuccess; + return linePoint; +} + + +SWLineSegment SWLineMakeZero(void) { + + // SWLineSegment linePoint = {{0,0},{0,0},SWPosRetFail,NULL}; + SWLineSegment linePoint; + // linePoint.startPoint = {0,0}; + linePoint.startPoint.x = 0; + linePoint.startPoint.y = 0; + // linePoint.endPoint = {0,0}; + linePoint.endPoint.x = 0; + linePoint.endPoint.y = 0; + linePoint.status = SWPosRetFail; + return linePoint; +} + + +double SWBetweenLinesrads(SWPointcut line1Start, SWPointcut line1End, SWPointcut line2Start, SWPointcut line2End) { + + double a = line1End.x - line1Start.x; + double b = line1End.y - line1Start.y; + double c = line2End.x - line2Start.x; + double d = line2End.y - line2Start.y; + float value = ((a*c) + (b*d)) / ((sqrt(a*a + b*b)) * (sqrt(c*c + d*d))); + if(value < -1) { + + value = -1; + } + if(value > 1) { + + value = 1; + } + float rads = acos(value); + return rads; +} + +double CalculatePointradius(double speed,double prevPointradius, + double radius,double force ,double maxForce, + double stressSpl,int forceEnable, + double distance) { + + if (speed > MaxPoints) { + + speed = MaxPoints; + } + if (forceEnable == 1) { + + double forceScale = force/maxForce; + forceScale = forceScale * (1 + stressSpl); + double newRadius = radius*forceScale; + double dropSize = newRadius - prevPointradius ; + if (dropSize > prevPointradius *MaxSteps) { + + dropSize = prevPointradius *MaxSteps; + + } + if (dropSize < - prevPointradius *MaxSteps) { + + dropSize = - prevPointradius *MaxSteps; + } + newRadius = prevPointradius + dropSize; + newRadius = newRadius > MaxWidthScale*radius ? MaxWidthScale*radius : newRadius; + if(newRadius < 0.7f) { + + newRadius = 0.7f; + } + return newRadius; + + + } else { + + double speedScale = MaxPoints/MaxSegment; + double fragments = speed/speedScale; + double radiusScale = fragments/MaxSegment; + double newRadius = radius - radius*radiusScale; + double dropSize = prevPointradius - newRadius; + if (dropSize > prevPointradius *MaxSteps) { + + dropSize = prevPointradius *MaxSteps; + + } + if (dropSize < - prevPointradius *MaxSteps) { + + dropSize = - prevPointradius *MaxSteps; + } + newRadius = prevPointradius - dropSize; + newRadius = newRadius < MinRadius*radius ? MinRadius*radius : newRadius; + if(newRadius < 0.7f) { + + newRadius = 0.7f; + } + return newRadius; + } + +} + + +SWPosPoint *CalculateStroke(SWPosPoint posAry[],int length,double preRadius) { + + for (int k = 0; k < length; k ++) { + + SWPosPoint pos = posAry[k]; + double pointRadius = preRadius /(length - 1); + pos.radius = preRadius - pointRadius*k; + if (pos.radius <= 0.4) { + + pos.radius = 0.4f; + } + posAry[k] = pos; + } + return posAry; + +} + + +SWPosStatus CalculateShake(SWPosPoint prePoint,SWPosPoint curPoint,SWPosPoint nextPoint) { + + double distance = GetPointDistance(curPoint, nextPoint); + double rads = SWBetweenLinesrads(SWPointCutMake(prePoint.realPoint.x, prePoint.realPoint.y), + SWPointCutMake(curPoint.realPoint.x, curPoint.realPoint.y), + SWPointCutMake(nextPoint.realPoint.x, nextPoint.realPoint.y), + SWPointCutMake(curPoint.realPoint.x, curPoint.realPoint.y)); + double angle = RadianTodegrees(rads); + if (angle > MinShake && angle < MaxShake && distance < 1) { + + return SWPosRetFail; + } + return SWPosRetFail; +} + + +SWPosStatus SWPosEqualToPos(SWPosPoint pos1,SWPosPoint pos2) { + + if (pos1.realPoint.x == pos2.realPoint.x && pos1.realPoint.y == pos2.realPoint.y) { + + return SWPosRetSuccess; + + } else { + + return SWPosRetFail; + } + +} + +SWPosPoint SWPosPointMakeZero(void) { + + return SWPosPointMake(0, 0, 0); +} + +SWPointcut ExPandLine(SWPointcut pt1,SWPointcut pt2,double nLen) +{ + SWPointcut OutPt = SWPointCutMake(0, 0); + if (pt1.x - pt2.x == 0) + { + OutPt.x = pt1.x; + if (pt1.y - pt2.y > 0) + { + OutPt.y = pt2.y - nLen; + } + else + { + OutPt.y = pt2.y + nLen; + } + } + else if (pt1.y - pt2.y == 0) + { + OutPt.y = pt1.y; + if (pt1.x - pt2.x > 0) + { + OutPt.x = pt2.x - nLen; + } + else + { + OutPt.x = pt2.x + nLen; + } + } + else + { + double k = 0.0; + double b = 0.0; + k = (pt1.y - pt2.y)/(pt1.x-pt2.x); + b = pt1.y - k * pt1.x; + double zoom = 0.0; + zoom = nLen/sqrt((pt2.x-pt1.x)*(pt2.x-pt1.x)+(pt2.y-pt1.y)*(pt2.y-pt1.y)); + + if(k > 0) + { + if (pt1.x-pt2.x > 0) + { + OutPt.x = pt2.x - zoom * (pt1.x-pt2.x); + OutPt.y = k*OutPt.x + b; + } + else + { + OutPt.x = pt2.x + zoom * (pt2.x-pt1.x); + OutPt.y = k*OutPt.x + b; + } + } + else + { + if (pt1.x-pt2.x > 0) + { + OutPt.x = pt2.x - zoom * (pt1.x-pt2.x) ; + OutPt.y = k*OutPt.x + b; + } + else + { + OutPt.x = pt2.x + zoom * (pt2.x - pt1.x); + OutPt.y = k*OutPt.x + b; + } + } + } + return OutPt; +} + +SWCirclePoint SWCircleMake(SWPosPoint center) { + + double radian = 2*M_PI/4.f; + double cosa = cos(radian); + double sina = sin(radian); + double h = center.radius*(4*(1 - cos(radian/2.f)))/(3*sin(radian/2.f)); + + SWPointcut pointA = SWPointCutMake(center.radius + center.realPoint.x, center.realPoint.y); + SWPointcut pointB = SWPointCutMake(center.radius + center.realPoint.x, center.realPoint.y - h); + SWPointcut pointC = SWPointCutMake(center.radius*cosa + h*sina + center.realPoint.x, center.realPoint.y - (center.radius*sina - h*cosa)); + SWPointcut pointD = SWPointCutMake(center.realPoint.x,center.realPoint.y - center.radius); + + SWPointcut pointE = SWPointCutMake(center.realPoint.x - (center.radius*cosa + h*sina), pointC.y); + SWPointcut pointF = SWPointCutMake(center.realPoint.x - center.radius, pointB.y); + SWPointcut pointG = SWPointCutMake(center.realPoint.x - center.radius, center.realPoint.y); + + SWPointcut pointH = SWPointCutMake(pointF.x, center.realPoint.y + h); + SWPointcut pointI = SWPointCutMake(pointE.x, center.realPoint.y + (center.radius*sina - h*cosa)); + SWPointcut pointJ = SWPointCutMake(center.realPoint.x, center.realPoint.y + center.radius); + + SWPointcut pointK = SWPointCutMake(pointC.x, pointI.y); + SWPointcut pointL = SWPointCutMake(pointB.x, pointH.y); + SWPointcut pointM = SWPointCutMake(center.radius + center.realPoint.x, center.realPoint.y); + + SWCirclePoint cPoint = {pointA,pointB,pointC,pointD,pointE,pointF,pointG,pointH,pointI,pointJ,pointK,pointL,pointM}; + + return cPoint; +} diff --git a/SWPosPointcut.h b/SWPosPointcut.h new file mode 100644 index 0000000..5b578ab --- /dev/null +++ b/SWPosPointcut.h @@ -0,0 +1,327 @@ +// +// SWPosPointcut.h +// DrawTest +// +// Created by 王阳阳 on 2022/9/6. +// + +#ifndef SWPosPointcut_h +#define SWPosPointcut_h + +#include +#include +#include +#include + +enum SWPosStatus { + + SWPosRetFail = 0, + SWPosRetSuccess = 1, +}; + +typedef enum SWPosStatus SWPosStatus; + +struct SWPointcut { + + double x; + double y; + +}; +typedef struct SWPointcut SWPointcut; + + +struct SWPosPoint { + + SWPointcut realPoint; + double radius; + +}; +typedef struct SWPosPoint SWPosPoint; + + +struct SWLineSegment { + + SWPointcut startPoint; + SWPointcut endPoint; + SWPosStatus status; + void *preSegment; + + SWLineSegment() + { + preSegment = nullptr; + } + +}; +typedef struct SWLineSegment SWLineSegment; + + +/** + * 三阶贝塞尔构造圆形 + * @brief The SWCirclePoint struct + */ +struct SWCirclePoint { + + + SWPointcut pointA; + SWPointcut pointB; + SWPointcut pointC; + SWPointcut pointD; + + SWPointcut pointE; + SWPointcut pointF; + SWPointcut pointG; + + SWPointcut pointH; + SWPointcut pointI; + SWPointcut pointJ; + + SWPointcut pointK; + SWPointcut pointL; + SWPointcut pointM; + +}; +typedef struct SWCirclePoint SWCirclePoint; + + +struct SWPosRet { + + SWPointcut prevLeftPoint;//左侧切点 + SWPointcut prevLeftIntersectPoint;//左侧切点交点 + + SWPointcut prevRightPoint;//右侧切点 + SWPointcut prevRightIntersectPoint;//右侧切点交点 + + SWPointcut curLeftPoint;//当前点左侧切点 + SWPointcut curRightPoint;//当前点右侧切点 + + QList circlePoints;//补点数据 + int circleCount;//补点数量 + SWPosStatus status;//计算结果状态 + +}; +typedef struct SWPosRet SWPosRet; + +/** + * 初始化 + * @brief SWPosRest + * @param pos + */ +void SWPosRest(SWPosPoint pos); + +/** + * 计算切点 + * @brief SWGetTangentcurPoint + * @param prevPoint 上一个点 + * @param curPoint 当前点 + * @param leftLine 左侧线段 + * @param rightLine 右侧线段 + * @param circle 是否补点(1 true 0 false) + * @return + */ +SWPosRet SWGetTangentcurPoint(SWPosPoint prevPoint,SWPosPoint curPoint,SWLineSegment leftLine,SWLineSegment rightLine,int circle); + +/** + * 获取两点距离 + * @brief GetPointDistance + * @param start 开始点 + * @param end 结束点 + * @return + */ +double GetPointDistance(SWPosPoint start, SWPosPoint end); + +/** + * 获取直线上某点位置 + * @brief SWratioPoint + * @param startPoint 线径开始点 + * @param endPoint 线径结束点 + * @param ratio 指定点所占线径长度百分比 + * @return + */ +SWPointcut SWratioPoint(SWPointcut startPoint, SWPointcut endPoint, double ratio); + +/** + * 根据中心点进行角度旋转 + * @brief SWrotatePoint + * @param point 圆上某一点 + * @param center 圆心点 + * @param angle 旋转角度(逆时针旋转) + * @return + */ + +SWPointcut SWrotatePoint(SWPointcut point, SWPointcut center, double angle); + +/** + * 获取线段交点(线段为向量) + * @brief SWgetEdgePoint + * @param a 第一条线段开始点 + * @param b 第一条线段结束点 + * @param c 第二条线段开始点 + * @param d 第二条线段结束点 + * @param e 设备点 + * @param directionLine 线径方位(1左侧线段0右侧线段) + * @return + */ +SWPointcut SWgetEdgePoint(SWPointcut a, SWPointcut b, SWPointcut c, + SWPointcut d,SWPointcut e,int directionLine); + +/** + * 构造无效线段 + * @brief SWLineMakeZero + * @return + */ +SWLineSegment SWLineMakeZero(void); + +/** + * 构造无效设备点 + * @brief SWPosPointMakeZero + * @return + */ +SWPosPoint SWPosPointMakeZero(void); + +/** + * 构造有效线段 + * @brief SWLineMake + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @return + */ +SWLineSegment SWLineMake(double x1,double y1,double x2, double y2); + +/** + * 构造点 + * @brief SWPointCutMake + * @param x + * @param y + * @return + */ +SWPointcut SWPointCutMake(double x,double y); + +/** + * 构造设备点 + * @brief SWPosPointMake + * @param x + * @param y + * @param radius + * @return + */ +SWPosPoint SWPosPointMake(double x,double y,double radius); + +/** + * 获取延长线交点(线段为向量) + * @brief SWExtendPoint + * @param a 第一条线段开始点 + * @param b 第一条线段结束点 + * @param c 第二条线段开始点 + * @param d 第二条线段结束点 + * @return + */ +SWPointcut SWExtendPoint(SWPointcut a, SWPointcut b, SWPointcut c,SWPointcut d); + +/** + * 计算两条直线夹角(弧度,线段为向量) + * @brief SWBetweenLinesrads + * @param line1Start 第一条线段开始点 + * @param line1End 第一条线段结束点 + * @param line2Start 第二条线段开始点 + * @param line2End 第二条线段结束点 + * @return + */\ +double SWBetweenLinesrads(SWPointcut line1Start, SWPointcut line1End, + SWPointcut line2Start, SWPointcut line2End); + +/** + * 根据速度 压感 计算点半径 + * @brief CalculatePointradius + * @param speed 速度 + * @param prevPointradius 上一个半径值 + * @param radius 半径 + * @param force 实时压感 + * @param maxForce 最大压感 + * @param stressSpl 压力灵敏度 + * @param forceEnable 是否开启(1开启0关闭) + * @param distance 点距离 + * @return + */ + +double CalculatePointradius(double speed,double prevPointradius,double radius, + double force ,double maxForce,double stressSpl, + int forceEnable,double distance); + +/** + * 计算笔锋 + * @brief CalculateStroke + * @param posAry 线径点集合 + * @param length + * @param preRadius 上一个半径 + * @return + */ +SWPosPoint * CalculateStroke(SWPosPoint posAry[],int length,double preRadius); + +/** + * 防抖处理 + * @brief CalculateShake + * @param prePoint + * @param curPoint + * @param nextPoint + * @return + */ +SWPosStatus CalculateShake(SWPosPoint prePoint,SWPosPoint curPoint,SWPosPoint nextPoint); + +/** + * 坐标点比较 + * @brief SWPosEqualToPos + * @param pos1 + * @param pos2 + * @return + */ +SWPosStatus SWPosEqualToPos(SWPosPoint pos1,SWPosPoint pos2); + +SWPointcut GetMaleTangentPointValue(SWPosPoint point, double a); +/** + 判断落点是否在矩形内 + */ +SWPosStatus IsPointInMatrix(SWPointcut p1 ,SWPointcut p2,SWPointcut p3 ,SWPointcut p4,SWPointcut p); +double GetCross(SWPointcut p1, SWPointcut p2,SWPointcut p); +SWPointcut ExPandLine(SWPointcut pt1,SWPointcut pt2,double nLen); + +/** + 构建圆形贝塞尔曲线 + */ +SWCirclePoint SWCircleMake(SWPosPoint center); + +double getAngle(double x1, double y1, double x2, double y2); + +SWPointcut getSamllAngleVertex(SWPointcut b, SWPointcut c,double cosAngle); + +SWPointcut calcNewPoint(SWPointcut p, SWPointcut pCenter, double theta); + + /** + * 获取线径补充圆点 + * @brief getCircleSegments + * @param prevPoint + * @param curPoint + * @param leftLine + * @param rightLine + * @param distance + * @param step + * @return + */ +SWPosRet getCircleSegments(SWPosPoint prevPoint,SWPosPoint curPoint, + SWLineSegment leftLine,SWLineSegment rightLine, + double distance,int step); +int isPointOnLine(double x, double y, SWPointcut start, SWPointcut end); + + /** + * 填充设备点 + * @brief fillPoints + * @param prevPoint + * @param curPoint + * @param distance + * @return + */ +QList fillPoints(SWPosPoint prevPoint,SWPosPoint curPoint,double distance); + +#endif /* SWPosPointcut_h */ + diff --git a/SignPenAppTablet.pro b/SignPenAppTablet.pro new file mode 100644 index 0000000..a4dded5 --- /dev/null +++ b/SignPenAppTablet.pro @@ -0,0 +1,52 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + SWPosPointcut.cpp \ + main.cpp \ + mainwindow.cpp \ + signpaintercachethread.cpp \ + signpaintercachethread_linux.cpp \ + signpenpainter.cpp \ + signutils.cpp \ + sw_log.cpp \ + wintab/Utils.cpp + +HEADERS += \ + SWPosPointcut.h \ + mainwindow.h \ + signpaintercachethread.h \ + signpaintercachethread_linux.h \ + signpenpainter.h \ + signpenstructs.h \ + signutils.h \ + sw_log.h \ + wintab/Utils.h \ + wintab/WINTAB.H + +FORMS += \ + mainwindow.ui + +LIBS+= -lUser32 + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +RESOURCES += \ + SignPenAppTablet.qrc diff --git a/SignPenAppTablet.qrc b/SignPenAppTablet.qrc new file mode 100644 index 0000000..a4b2786 --- /dev/null +++ b/SignPenAppTablet.qrc @@ -0,0 +1,5 @@ + + + etc/qt.conf + + diff --git a/etc/qt.conf b/etc/qt.conf new file mode 100644 index 0000000..6205dc3 --- /dev/null +++ b/etc/qt.conf @@ -0,0 +1,2 @@ +[Platforms] +WindowsArguments = dpiawareness=0 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..8349220 --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..e23cd91 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,507 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +#include +#include + +#ifdef Q_OS_WIN32 +#include +#include +#include +#include "wintab/WINTAB.H" +#include "wintab/Utils.h" +#include "Dbt.h" +#include "devguid.h" +#endif +#include "signpenpainter.h" + +//#include +using namespace std; + +//inline long long vk_timestamp() +//{ +// return chrono::duration_cast(chrono::high_resolution_clock::now().time_since_epoch()).count(); +//} + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + m_pImage = nullptr; + m_pPainter = nullptr;//后台绘图器 + m_wintab_handle = 0; + m_mouse_pressed = false; + + isUsedMouse = false; + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + isUsedInk = false; + ui->checkBox_ink->setVisible(false); +#else + ui->checkBox_ink->setVisible(false); +#endif + ui->plainTextEdit->setVisible(true); + + ResetBufferImage(); + + //动态加载Wintab库 + if(!LoadWintab()) + { + QMessageBox::warning(nullptr,"Load Wintab","加载Wintab32.dll失败"); + } + else + { + gpWTInfoW(0, 0, NULL); + +// AXIS axis{0}; + AXIS axis; + +// //获取x范围 +// gpWTInfoW(WTI_DEVICES,DVC_X,&axis); +// m_tablet_ctx.max_x = axis.axMax; + +// //获取y范围 +// memset(&axis,0,sizeof(AXIS)); +// gpWTInfoW(WTI_DEVICES,DVC_Y,&axis); +// m_tablet_ctx.max_y = axis.axMax; + + //获取压力范围 + memset(&axis,0,sizeof(AXIS)); + gpWTInfoW(WTI_DEVICES,DVC_NPRESSURE,&axis); + m_tablet_ctx.max_p = axis.axMax; + +// LOGCONTEXTW wintab_ctx{}; + LOGCONTEXTW wintab_ctx; + gpWTInfoW(WTI_DEFCONTEXT, 0, &wintab_ctx); + //关心的数据项x y 压力 + wintab_ctx.lcPktData = PK_X |PK_Y |PK_NORMAL_PRESSURE; + wintab_ctx.lcOptions = CXO_MESSAGES | CXO_CSRMESSAGES; + + //设置Wintab的输出坐标范围 = 数位板设备的逻辑范围 + //默认情况下lcOutExtX lcOutExtY 为系统桌面大小 + //wintab_ctx.lcOutExtX = wintab_ctx.lcInExtX; + // wintab_ctx.lcOutExtY =wintab_ctx.lcInExtY*-1; + wintab_ctx.lcOutExtY *=-1; + //Wintab返回的系统桌面区域,wintab_ctx.lcSysExtX wintab_ctx.lcSysExtY 受系统显示缩放影响 + //同时受调用进程的DPI感知特性影响 + + m_tablet_ctx.sys_x = wintab_ctx.lcSysOrgX; + m_tablet_ctx.sys_y = wintab_ctx.lcSysOrgY; + m_tablet_ctx.sys_w = wintab_ctx.lcSysExtX; + m_tablet_ctx.sys_h = wintab_ctx.lcSysExtY; + + //lcInExtX lcInExtY 为设备的输入最大范围 + m_tablet_ctx.max_x = wintab_ctx.lcOutExtX; + m_tablet_ctx.max_y = qAbs(wintab_ctx.lcOutExtY); + + HWND hwnd = (HWND)this->winId(); + m_wintab_handle = (unsigned int)gpWTOpenW((HWND)this->winId(),&wintab_ctx,TRUE); + } + + m_SignPenpainter = new SignPenPainter; + m_SignPenpainter->SetPainterRect(this->rect()); + + penRadius = 1.7; + + connect(m_SignPenpainter,SIGNAL(NeedsDisplay(QRect)),this,SLOT(NeedToUpdate(QRect))); +// connect(m_SignPenpainter,SIGNAL(log(QString)),this,SLOT(log(QString))); +} + +MainWindow::~MainWindow() +{ + delete ui; +} +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) +{ + if(QString(eventType)=="windows_generic_MSG") + { + PMSG msg = static_cast(message); + switch(msg->message) + { + case WT_CTXOPEN: + { + qDebug()<<"Tablet wintab open."<lParam; + DWORD num = msg->wParam; + if(gpWTPacket(hctx,num,buf)) + { + unsigned x = *(unsigned*)&buf[0]; + unsigned y = *(unsigned*)&buf[4]; + unsigned p = *(unsigned*)&buf[8]; + // qDebug()<<"x:"<wParam); + //获取系统指针设备类型 + POINTER_INPUT_TYPE pointerType = PT_POINTER; + if(GetPointerType(pointerId,&pointerType)) + { + //判断当前系统指针是否是为笔设备 + if(pointerType==PT_PEN) + { + POINTER_PEN_INFO ppi{}; + //获取与数字笔相关的信息 + if(GetPointerPenInfo(pointerId,&ppi)) + { + //获取桌面坐标和笔压力 + int x = GET_X_LPARAM(msg->lParam); + int y = GET_Y_LPARAM(msg->lParam); + + int pressure = ppi.pressure*8; //统一转化为8192级压力 + \ + //通常绘图软件会使用Wintab/Windows Ink其中一种进行绘图,取决于系统环境支持和绘图软件设计 + //Windows Ink的返回坐标与鼠标的全局坐标一致,不关心屏幕摆放位置,只要光标能到 + //**注意:手写板/手写屏在未安装驱动的情况下,光标默认到不了扩展屏幕,通常是由驱动控制到达扩展屏幕或通过系统设置映射到扩展屏。 + DrawSign_Ink(x,y,pressure); + //qDebug()<<"ink x:"<(message); + switch(msg->message) + { + case WT_CTXOPEN: + { + qDebug()<<"Tablet wintab open."<lParam; + DWORD num = msg->wParam; + if(gpWTPacket(hctx,num,buf)) + { + unsigned x = *(unsigned*)&buf[0]; + unsigned y = *(unsigned*)&buf[4]; + unsigned p = *(unsigned*)&buf[8]; + // qDebug()<<"x:"<wParam); +// //获取系统指针设备类型 +// POINTER_INPUT_TYPE pointerType = PT_POINTER; +// if(GetPointerType(pointerId,&pointerType)) +// { +// //判断当前系统指针是否是为笔设备 +// if(pointerType==PT_PEN) +// { +// POINTER_PEN_INFO ppi{}; +// //获取与数字笔相关的信息 +// if(GetPointerPenInfo(pointerId,&ppi)) +// { +// //获取桌面坐标和笔压力 +// int x = GET_X_LPARAM(msg->lParam); +// int y = GET_Y_LPARAM(msg->lParam); + +// int pressure = ppi.pressure*8; //统一转化为8192级压力 +// \ +// //通常绘图软件会使用Wintab/Windows Ink其中一种进行绘图,取决于系统环境支持和绘图软件设计 +// //Windows Ink的返回坐标与鼠标的全局坐标一致,不关心屏幕摆放位置,只要光标能到 +// //**注意:手写板/手写屏在未安装驱动的情况下,光标默认到不了扩展屏幕,通常是由驱动控制到达扩展屏幕或通过系统设置映射到扩展屏。 +// // DrawSign_Ink(x,y,pressure); +// //qDebug()<<"ink x:"<ClearDraw(); + ui->plainTextEdit->clear(); + update(); +} + +void MainWindow::NeedToUpdate(QRect rect) +{ +// this->update(QRect(0,0,120,120)); + this->update(rect); +} + +void MainWindow::paintEvent(QPaintEvent *event) +{ +// QPainter painter(this); +// painter.setRenderHints(QPainter::SmoothPixmapTransform +// |QPainter::TextAntialiasing |QPainter::HighQualityAntialiasing); +// if(m_pImage) +// painter.drawImage(rect(),*m_pImage,m_pImage->rect()); + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + m_SignPenpainter->DrawRect(&painter,this->rect()); + QWidget::paintEvent(event); +} + +void MainWindow::resizeEvent(QResizeEvent *event) +{ + ResetBufferImage(); + QMainWindow::resizeEvent(event); + m_SignPenpainter->SetPainterRect(this->rect()); + m_SignPenpainter->SetPenType(1); +} + +void MainWindow::mousePressEvent(QMouseEvent *event) +{ +// qDebug() << __FUNCTION__ << event->pos(); + if(!isUsedMouse) + return; + QPoint pt1 = event->pos(); + QPoint p2 = mapToGlobal(pt1); + + m_mouse_pressed = false; + + m_SignPenpainter->SetStressSwitch(false); + m_SignPenpainter->MousePressed(event->pos(),penRadius * 1.3,10,10); +} + +void MainWindow::mouseMoveEvent(QMouseEvent *event) +{ +// qDebug() << __FUNCTION__ << event->pos(); + if(!isUsedMouse) + return; + QString msg = QString("use ink. pos: %1 %2").arg(event->pos().x()).arg(event->pos().y()); + ui->plainTextEdit->appendPlainText(msg); + ui->plainTextEdit->appendPlainText("use mouse."); + m_SignPenpainter->SetStressSwitch(false); + m_SignPenpainter->MouseMoved(event->pos(),penRadius * 1.3,10,10); +} + +void MainWindow::mouseReleaseEvent(QMouseEvent *event) +{ +// qDebug() << __FUNCTION__ << event->pos(); + if(!isUsedMouse) + return; + m_mouse_pressed = true; + + m_SignPenpainter->MouseReleased(event->pos(),penRadius); + m_SignPenpainter->SetStressSwitch(false); +} + +void MainWindow::ResetBufferImage() +{ + int w = width(); + int h = height(); + if(w<0 || h<0) + return; + + if(m_pPainter!=nullptr) + { + delete m_pPainter; + } + + if(m_pImage!=nullptr) + { + delete m_pImage; + } + + //重新创建新的后台缓冲图像对象 +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + m_pImage = new QImage(w,h,QImage::Format_RGBA8888); +#else + m_pImage = new QImage(w,h,QImage::Format_ARGB32_Premultiplied); +#endif + m_pImage->fill(Qt::transparent); + + //重新创建新的绘图器 + m_pPainter = new QPainter(m_pImage); + m_pPainter->setRenderHints(QPainter::SmoothPixmapTransform + |QPainter::TextAntialiasing |QPainter::HighQualityAntialiasing); +} + +void MainWindow::DrawSign_Base(int x, int y, int p,bool is_ink) +{ + if(isUsedMouse) + return; + if(m_pImage==nullptr ) + return; + if(m_tablet_ctx.max_x==0 || m_tablet_ctx.sys_w==0) + return ; + static QPoint last_pt(0,0); + static unsigned last_pressure = 0; + + static bool down = false; + + + //接触时第一个点只保存不画 + if(last_pressure==0 && p>0) + { + down = true; + last_pressure = p; + last_pt = QPoint(x,y); + MousePressed(last_pt,p,m_tablet_ctx.max_p,true); + return; + } + + //离开时 + if(last_pressure>0 && p==0) + { + last_pressure = 0; + MouseReleased(last_pt); + //抬笔时强制更新 + update(); + down = false; + return; + } + + if(p==0) + { + return; + } + + int ps = 6; //笔宽 + int pw = (int)(ps*(p*1.0/m_tablet_ctx.max_p)+0.5); + QPen pen(is_ink?Qt::blue:Qt::red,pw,Qt::SolidLine); + pen.setCapStyle(Qt::RoundCap); + m_pPainter->setPen(pen); + + QPoint cur_pt(x,y); +// m_pPainter->drawLine(last_pt, cur_pt); + + MouseMoved(cur_pt,p,m_tablet_ctx.max_p,true); + + + //todo 刷新机制 +// static long long t1 = vk_timestamp(); + +// long long t2 = vk_timestamp(); + +// if(t2-t1>33) +// { +// //FPS=30 +// update(); +// t1 = t2; +// } + update(); + + last_pressure = p; + + //保存当前点 + last_pt = cur_pt; +} + +void MainWindow::DrawSign_Wintab(const TabletDataPacket &pkt) +{ + if(isUsedMouse) + return; + qDebug() << __FUNCTION__ << "wintab."; + ui->plainTextEdit->appendPlainText("wintab."); + //计算Wintab坐标--->全局桌面屏幕坐标 + //当扩展屏幕摆放在左边时,系统起始坐标为负,加上系统原始点得到正确的桌面坐标dx dy + double dx = (pkt.x*1.0/m_tablet_ctx.max_x)*m_tablet_ctx.sys_w+m_tablet_ctx.sys_x; + double dy = (pkt.y*1.0/m_tablet_ctx.max_y)*m_tablet_ctx.sys_h+m_tablet_ctx.sys_y; + QPoint wpt = mapFromGlobal(QPoint(dx,dy)); + DrawSign_Base(wpt.x(),wpt.y(),pkt.p,false); + qDebug()<< __FUNCTION__ << "pkt.x:"<plainTextEdit->appendPlainText(msg); + QPoint pt = mapFromGlobal(QPoint(ink_x,ink_y)); + + DrawSign_Base(pt.x(),pt.y(),ink_p,true); +} + +void MainWindow::MousePressed(QPointF currentPoint, double force, double maxForce,bool isStressSwitch) +{ + m_SignPenpainter->SetStressSwitch(isStressSwitch); + m_SignPenpainter->MousePressed(currentPoint,penRadius * 1.3,force,maxForce); +} + +void MainWindow::MouseMoved(QPointF currentPoint, double force, double maxForce,bool isStressSwitch) +{ + m_SignPenpainter->SetStressSwitch(isStressSwitch); + m_SignPenpainter->MouseMoved(currentPoint,penRadius * 1.3,force,maxForce); +} + +void MainWindow::MouseReleased(QPointF currentPoint) +{ + m_SignPenpainter->MouseReleased(currentPoint,penRadius); + m_SignPenpainter->SetStressSwitch(false); +} + + +void MainWindow::on_checkBox_stateChanged(int arg1) +{ + if(ui->checkBox->isChecked()) + isUsedMouse = true; + else + isUsedMouse = false; + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + isUsedInk = ui->checkBox_ink->isChecked(); +#endif +} + diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..88c4b96 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,97 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + + + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +struct TabletContext +{ + int max_x; + int max_y; + int max_p; + + int sys_x; + int sys_y; + int sys_w; + int sys_h; +}; + +struct TabletDataPacket +{ + unsigned int x; //Wintab X + unsigned int y; //Wintab Y + unsigned int p; //压力 +}; + +class QImage; +class SignPenPainter; +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +public slots: + void on_pushButton_clicked(); + void NeedToUpdate(QRect rect); + +protected: +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result); +#else + virtual bool winEvent(MSG *message, long *result); +#endif + virtual void paintEvent(QPaintEvent *event) override; + virtual void resizeEvent(QResizeEvent *event) override; + + virtual void mousePressEvent(QMouseEvent *event) override; + + virtual void mouseMoveEvent(QMouseEvent *event) override; + + virtual void mouseReleaseEvent(QMouseEvent *event) override; +private slots: + void on_checkBox_stateChanged(int arg1); + +private: + //初始化后台缓冲区 + void ResetBufferImage(); + + //绘制笔迹 + void DrawSign_Base(int x,int y,int p,bool is_ink=false); + void DrawSign_Wintab(const TabletDataPacket &pkt); + void DrawSign_Ink(int ink_x,int ink_y,int ink_p); + + void MousePressed(QPointF currentPoint,double force,double maxForce,bool isStressSwitch);//force 压感力度 + void MouseMoved(QPointF currentPoint,double force,double maxForce,bool isStressSwitch); + void MouseReleased(QPointF currentPoint); + +private: + Ui::MainWindow *ui; + +// QImage *m_pImage{nullptr}; +// QPainter *m_pPainter{nullptr};//后台绘图器 +// TabletContext m_tablet_ctx{0}; +// unsigned int m_wintab_handle{0}; +// bool m_mouse_pressed{false}; + QImage *m_pImage; + QPainter *m_pPainter;//后台绘图器 + TabletContext m_tablet_ctx; + unsigned int m_wintab_handle; + bool m_mouse_pressed; + // QList m_list_buffer; + + SignPenPainter* m_SignPenpainter; + + float penRadius; + + bool isUsedMouse; + bool isUsedInk; +}; +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..01c0406 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,73 @@ + + + MainWindow + + + + 0 + 0 + 1279 + 787 + + + + false + + + MainWindow + + + + + + 20 + 590 + 1241 + 181 + + + + + + + 30 + 10 + 80 + 22 + + + + 清空 + + + + + + 180 + 10 + 181 + 21 + + + + 是否使用鼠标 + + + + + + 330 + 10 + 171 + 21 + + + + 是否使用ink + + + + + + + diff --git a/signpaintercachethread.cpp b/signpaintercachethread.cpp new file mode 100644 index 0000000..9db71c5 --- /dev/null +++ b/signpaintercachethread.cpp @@ -0,0 +1,2167 @@ +#include "signpaintercachethread.h" +#include "signpenpainter.h" +#include "signutils.h" +#include "sw_log.h" + +#include +#include +#include +SignPainterCacheThread::SignPainterCacheThread() +{ +#ifdef Q_OS_WIN + drawCount = 100;//todo 截断后续需要在切点处 200点后进行截断缓存 +#else + drawCount = 200;//todo 截断后续需要在切点处 200点后进行截断缓存 +#endif + drawCountOffset = 40;// 200点后,截断到160 +// drawCount = 200; +// drawCountOffset = 40; + drawStartIndex = 0; + stressSwitch = 0; + stressSpl = 0;//灵敏度 + strokeSpl = 2; + curAnnotPath = nullptr; + m_BaseBuf = nullptr; + m_PaintingBuf = nullptr; + isPressed = false; + m_fPixmapZoom = 1; + m_fPixmaps = 3; + currentPageIndex = -1; + + penType = 2; + + lasttimestamp = QDateTime::currentMSecsSinceEpoch(); + lastPaintTimestamp = lasttimestamp; + paintFreq = 20; + + m_PaintRect = QRect(0,0,0,0); + m_OriRect = QRect(0,0,0,0); + m_ScrollH = 0; + +} + +void SignPainterCacheThread::SetPainterRect(QRect rect) +{ + m_Size = rect.size(); + m_PaintRect = rect; +// m_PaintRect = QRect(0,0,rect.width(),rect.height()); + if(m_OriRect.width() > 0) + { + m_ScrollH = m_PaintRect.top() - m_OriRect.top(); + } +} + + +void SignPainterCacheThread::Init() +{ + drawStartIndex = 0; + //压力灵敏度 + stressSpl = 0; + strokeSpl = 2; + stressSwitch = 0; + pointSpeed = 10; + curAnnotPath = nullptr; + + m_lastSectionIndex = 0; + m_lastSectionPoint = SWRealPoint(); +} + +void SignPainterCacheThread::AddPoint(QPointF currPoint,int type,float radius,double force,double maxForce) +{ +// SW_Log::Get()->info(QString("====AddPoint x: %1 y: %2 type: %3 radius: %4 force: %5 maxForce: %6 ts: %7" ) +// .arg(currPoint.x()).arg(currPoint.y()).arg(type).arg(radius).arg(force).arg(maxForce).arg(QDateTime::currentMSecsSinceEpoch())); + + qDebug() << __FUNCTION__ << "====AddPoint : " << currPoint << " type: " << type << " force: " << force << " maxForce: " << maxForce; + SWRealPoint realpoint; + realpoint.realPoint = currPoint; + realpoint.pointType = type; + realpoint.radius = radius; + realpoint.finalRadius = radius; + realpoint.force = force; + realpoint.maxForce = maxForce; + realpoint.timestamp = QDateTime::currentMSecsSinceEpoch(); + if(lasttimestamp == realpoint.timestamp && type == 0) + { + return; + } + if(type == 2 && currPoint.x() == 0 && currPoint.y() == 0) + { + if(curAnnotPath) + { + realpoint = curAnnotPath->realPoints.last(); + realpoint.pointType = type; + } + } + lasttimestamp = realpoint.timestamp; + QMutexLocker locker(&m_mutex); + m_RealPoints.append(realpoint); + m_Sem.release(); +} + +//只绘当前笔 +void SignPainterCacheThread::PaintWithPainter(QPainter* painter,QRect currentVisibleRect) +{ + if(!curAnnotPath) + return; + if(curAnnotPath->currentPathsList.count() <= 0) + return; + painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + + QList paths = curAnnotPath->currentPathsList.back(); + + qDebug() << __FUNCTION__ << " count: " << paths.count(); + for(int i = 0 ; i < paths.count();i++) + { + QPainterPath path = paths.at(i); + path.setFillRule(Qt::WindingFill); + painter->fillPath(path,QBrush(m_PenColor)); +// painter->fillPath(path,QBrush(Qt::red)); + } + +} + + +void SignPainterCacheThread::SwPenSectionPathDraw(QList points,SWRealPoint endRealPoint,int endFlag) +{ + QPaintDevice* device = PaintingDevice(); + QPainterPath BezierPath; + QPainter bufPainter(device); +// bufPainter.setBrush(Qt::black); + bufPainter.setBrush(m_PenColor); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + bufPainter.setPen(QPen(Qt::NoPen)); + + QTransform transform; + transform.scale(m_fPixmapZoom, m_fPixmapZoom); + bufPainter.setTransform(transform); +// bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); + bufPainter.translate(-m_OriRect.left(), -m_OriRect.top()+m_Size.height()); + + QList bezierPaths; //绘制的Path + QList bezierEles; //绘制 + +// annotPath->bezierPaths.clear(); +// annotPath->bezierEles.clear(); + + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int endIndex = points.count(); + for (int i = 0 ; i < endIndex; i++) + { + SWRealPoint penPoint = points[i]; + if (GetPointValid(penPoint)) + { + + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + bool isBeging = rightPoints.first().timestamp == points.first().timestamp; + SwPenSectionPathDrawRightWithBezier(&pathBizer, bezierEles, prevPoint, rightPoints,endRealPoint,endFlag,false,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,false); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(pp.x()).arg(pp.y())); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointB.x).arg(circleP.pointB.y).arg(circleP.pointC.x).arg(circleP.pointC.y).arg(circleP.pointD.x).arg(circleP.pointD.y)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointE.x).arg(circleP.pointE.y).arg(circleP.pointF.x).arg(circleP.pointF.y).arg(circleP.pointG.x).arg(circleP.pointG.y)); + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointH.x).arg(circleP.pointH.y).arg(circleP.pointI.x).arg(circleP.pointI.y).arg(circleP.pointJ.x).arg(circleP.pointJ.y)); + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointK.x).arg(circleP.pointK.y).arg(circleP.pointL.x).arg(circleP.pointL.y).arg(circleP.pointM.x).arg(circleP.pointM.y)); + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); +// bufPainter.drawPath(circleBizer); + DrawSignPath(&bufPainter,circleBizer,false); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { + rightPoints.clear(); + prevPoint = CGPointZero; +// bufPainter.drawPath(pathBizer); +// if(i != 0) +// { +// DrawSignPath(&bufPainter,pathBizer,false); +// } + + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); + if (i == 0 ) { + + if(endFlag == 1) { + + CGPoint endPoint = CGPointMake((endRealPoint.PLeftIntersectPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, + (endRealPoint.PLeftIntersectPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + + pathBizer.moveTo(endPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + rightPoints.append(penPoint); + + } else { + + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + } + + } else { + + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + + } + +// bezierPaths.append(pathBizer); + } + else + { + rightPoints.append(penPoint); + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero) ) + { + // qDebug() << __FUNCTION__ << " cursor != 0 and PLeftIntersectPoint is null"; + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint and pLeftBottomPoint is not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo1 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo2 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } + + } + else + { + // qDebug() << __FUNCTION__ << " cursor != 0 PLeftIntersectPoint not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + // SW_Log::Get()->info(QString("====SwPenPathDraw quadTo3 cx: %1 cy: %2 ex:%3 ey: %4" ) + // .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + //qDebug() << __FUNCTION__ << " PLeftIntersectPoint: " << penPoint.PLeftIntersectPoint.x() << penPoint.PLeftIntersectPoint.y(); + } + if(i == endIndex-1) + { + + bool isBeging = rightPoints.first().timestamp == points.first().timestamp; + SwPenSectionPathDrawRightWithBezier(&pathBizer,bezierEles, prevPoint, rightPoints,endRealPoint,endFlag,true,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,false); + } + + + } + cursor ++; + + } + + } + + } + +// m_PaintingBuf->save(QString("d:/painting_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); +} + +void SignPainterCacheThread::SwPenSectionPathDrawRightWithBezier(QPainterPath *bPath, QList &elementList, + CGPoint prevPoint, QList rPoints,SWRealPoint endRealPoint,int endFlag,bool isEnd,bool isBegin) +{ + for (int k = (rPoints.count() - 1); k >= 0 ; k --) + { + + SWRealPoint penPoint = rPoints.at(k); + if (GetPointValid(penPoint)) + { + if (k == (rPoints.count() - 1)) + { + if (isEnd == true) { + + SWRealPoint prePenPoint = rPoints.at(k - 1); + CGPoint endPoint = CGPointMake((prePenPoint.PRightIntersectPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, + (prePenPoint.PRightIntersectPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(endPoint,endPoint); + AddQuadToElement(elementList,endPoint,endPoint); + prevPoint = prePenPoint.PRightIntersectPoint; + + } else { + + + + bPath->quadTo(prevPoint,penPoint.pLeftTopPoint); + AddQuadToElement(elementList,prevPoint,penPoint.pLeftTopPoint); + prevPoint = penPoint.pLeftTopPoint; + + bPath->quadTo(prevPoint,penPoint.pRightTopPoint); + AddQuadToElement(elementList,prevPoint,penPoint.pRightTopPoint); + prevPoint = penPoint.pRightTopPoint; + } + + + } else { + + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PRightIntersectPoint, CGPointZero)) { + + if (!CGPointEqualToPoint(penPoint.pRightTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pRightBottomPoint, CGPointZero)) { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pRightBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pRightBottomPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightBottomPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pRightTopPoint.x())/2.f, (prevPoint.y()+penPoint.pRightTopPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + } + + } + else + { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.PRightIntersectPoint; + + } + if (k == 0 ) { + + if(endFlag == 1 && isBegin == true) { + + CGPoint endPoint = CGPointMake((penPoint.PRightIntersectPoint.x() + endRealPoint.PRightIntersectPoint.x())/2.f, + (penPoint.PRightIntersectPoint.y() + endRealPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + + prevPoint = endPoint; + endPoint = CGPointMake((penPoint.PLeftIntersectPoint.x() + endRealPoint.PLeftIntersectPoint.x())/2.f, + (penPoint.PLeftIntersectPoint.y() + endRealPoint.PLeftIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + + + + } else { + + CGPoint endPoint = CGPointMake((penPoint.pRightBottomPoint.x() + prevPoint.x())/2.f, (penPoint.pRightBottomPoint.y() + prevPoint.y())/2.f); + + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + bPath->quadTo(penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + AddQuadToElement(elementList,penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + prevPoint = penPoint.pRightBottomPoint; + //绘制开始连接点 + SWRealPoint firstPen = rPoints.first(); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + + } + } + + } + } +} + +void SignPainterCacheThread::Paint(QPainter* painter,QRect currentVisibleRect) +{ + //使用缓冲画布+实时渲染 + PaintWithPainter(painter,currentVisibleRect); + if(m_PaintingBuf) + { +// bufPainter.translate(-m_OriRect.left(), -m_OriRect.top()+m_Size.height()+m_ScrollH); + qDebug() << __FUNCTION__ << " 1111111 start Paint: m_PaintRect: " << m_PaintRect << " m_OriRect: " << m_OriRect << " m_ScrollH: " << m_ScrollH; + painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + painter->drawImage(m_PaintRect.left(), m_PaintRect.top(),*m_PaintingBuf,0,m_Size.height()+m_ScrollH,m_Size.width(),m_Size.height()); + +// if(m_drawMutex.tryLock(1)) +// { +// if((int)abs(m_ScrollH) >= m_PaintRect.height()) +// { +// delete m_PaintingBuf; +// m_PaintingBuf = NULL; +// } +// else +// { +// qDebug() << __FUNCTION__ << " 1111111 start Paint: m_PaintRect: " << m_PaintRect << " m_OriRect: " << m_OriRect << " m_ScrollH: " << m_ScrollH; +// painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing +// painter->drawImage(m_PaintRect.left(), m_PaintRect.top(),*m_PaintingBuf,0,m_Size.height()+m_ScrollH,m_Size.width(),m_Size.height()); + +// } +// m_drawMutex.unlock(); +// } + } + return; + //全部使用缓冲画布 +// qDebug() << __FUNCTION__ ; + if(m_PaintingBuf != nullptr && painter) + { +// QMutexLocker locker(&m_drawMutex); + +// if(m_drawMutex.tryLock(1)) +// { + // QImage img = *m_PaintingBuf; + painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing +// painter->setPen(Qt::NoPen); +// painter->drawImage(m_PaintRect.left(),m_PaintRect.top(),*m_PaintingBuf); + int viewOffSetW = m_PaintRect.left()-currentVisibleRect.left(); + int viewOffSetH = m_PaintRect.top()-currentVisibleRect.top(); + if((int)abs(viewOffSetH) >= m_PaintRect.height()) + { + delete m_PaintingBuf; + m_PaintingBuf = NULL; + emit NeedsToRefresh(m_PaintRect); + } + else + { +// m_PaintingBuf->save(QString("point_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); +// painter->drawImage(m_PaintRect.left()+viewOffSetW,m_PaintRect.top()+viewOffSetH,*m_PaintingBuf); + painter->drawImage(m_PaintRect.left(),m_PaintRect.top(),*m_PaintingBuf); + } +// m_drawMutex.unlock(); +// } + +// if(!isPressed) +// { +// if(m_drawMutex.tryLock(1)) +// { +// // QImage img = *m_PaintingBuf; +// painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing +// painter->setPen(Qt::NoPen); +// painter->drawImage(m_PaintingBuf->rect(),*m_PaintingBuf); +// // painter->drawImage(img.rect(),img); +// m_drawMutex.unlock(); +// } +// } +// else +// { +// painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing +// painter->setPen(Qt::NoPen); +// if(!curAnnotPath) +// return; +// QList paths = curAnnotPath->bezierPaths; +// for(int i = 0 ; i < paths.count(); i++) +// { +// paths[i].setFillRule(Qt::WindingFill); +// painter->fillPath(paths[i],QBrush(Qt::black)); +// } +// } + } +} + +void SignPainterCacheThread::ClearDraw() +{ +// SW_Log::Get()->info(QString("to ClearDraw")); + m_AnnotMutex.lock(); + if(!isPressed) + { + SW_Log::Get()->info(QString("!isPressed to ClearDraw")); +// if(curAnnotPath != nullptr) +// delete curAnnotPath; + curAnnotPath = nullptr; + for(int i = 0 ; i < drawPaths.count();i++) + { + drawPaths[i]->bezierEles.clear(); + drawPaths[i]->bezierPaths.clear(); + drawPaths[i]->currentPathsList.clear(); + delete drawPaths[i]; + drawPaths[i] = nullptr; + } + drawPaths.clear(); + + if(m_BaseBuf != nullptr) + { + delete m_BaseBuf; + m_BaseBuf = nullptr; + } + if(m_PaintingBuf != nullptr) + { + delete m_PaintingBuf; + m_PaintingBuf = nullptr; + } + + m_lastSectionIndex = 0; + } + m_AnnotMutex.unlock(); + emit NeedsToRefresh(m_PaintRect); +} + +void SignPainterCacheThread::run() +{ + while(true) + { + m_Sem.acquire(); + + if (m_RealPoints.isEmpty()) + { + continue; + } + m_mutex.lock(); + QList points; + points.swap(m_RealPoints); + m_RealPoints.clear(); + m_mutex.unlock(); + + bool isEnd = false; + //计算点 + for(int i = 0 ; i < points.count(); i++) + { + SWRealPoint realPoint = points[i]; + if(realPoint.pointType == 0) + { + if(!isPressed) + continue; + MouseMoved(realPoint); + } + else if(realPoint.pointType == 1) + { + if(isPressed) + continue; + //press + isPressed = true; + MousePressd(realPoint); +// emit NeedsToRefresh(m_PaintRect); +// if(isEnd) +// emit ReleasedExcuted(); + } + else + { + if(!isPressed) + continue; + isPressed = false; + MouseReleased(realPoint); + isEnd = true; + + QPainterPath path = SwPenPathDraw(isEnd,false); + QRectF rect = path.boundingRect(); + if(curAnnotPath && curAnnotPath->points.count() <= 2) + emit NeedsToRefresh(m_PaintRect); + else + emit NeedsToRefresh(QRect(rect.x()-5,rect.y()-5,rect.width()+10,rect.height()+10)); + if(isEnd) + emit ReleasedExcuted(); + } + } + //检查是否快速写导致部分数据没有刷新到缓存,进行缓存 + for(int i = 0 ; i < drawPaths.count();i++) + { + if(drawPaths.at(i)->bezierEles.isEmpty() && drawPaths.at(i)->realPoints.count()>2 + && !drawPaths.at(i)->isPainted&& curAnnotPath!=drawPaths.at(i)) + { + //需要重绘 + SwPenPathDraw(drawPaths[i],true,false); + } + drawPaths[i]->isPainted = true; + } + //画到缓冲 + if(curAnnotPath) + { + if(!isEnd) + { + QPainterPath path; + if(curAnnotPath->points.count() > drawStartIndex + drawCount) + { + drawStartIndex += (drawCount-drawCountOffset); + path = SwPenPathDraw(isEnd,true); + } + else + { + path = SwPenPathDraw(isEnd,false); + } + + qint64 currentTs = QDateTime::currentMSecsSinceEpoch(); +// if(currentTs - lastPaintTimestamp < paintFreq) +// continue; + lastPaintTimestamp = currentTs; + QRectF rect = path.boundingRect(); + qDebug() << __FUNCTION__ << " ts: " << QDateTime::currentMSecsSinceEpoch(); +// emit NeedsToRefresh(QRect(rect.x()-5,rect.y()-5,rect.width()+10,rect.height()+10)); + emit NeedsToRefresh(m_PaintRect); + } + } + } +} + +void SignPainterCacheThread::MouseMoved(const SWRealPoint& realPoint) +{ +// qDebug() << __FUNCTION__ <realPoints.count() <= 0) + { + SWRealPoint curPenPoint; + curPenPoint.realPoint = currentPoint; + curPenPoint.radius = realPoint.radius; + curPenPoint.finalRadius = realPoint.radius; + curPenPoint.force = realPoint.force; + curPenPoint.maxForce = realPoint.maxForce; + curPenPoint.timestamp = realPoint.timestamp; + curAnnotPath->realPoints.append(curPenPoint); + curAnnotPath->points.append(curPenPoint); + return; + } + /** + 判断临近相同点,并过滤 + */ + if (!CGPointEqualToPoint(currentPoint, curAnnotPath->realPoints.last().realPoint) || GetDistanceBetweenPoint(currentPoint, curAnnotPath->realPoints.last().realPoint) > 500) { + + /** + 计算速度半径 + */ + //todo 计算速度 + float penRadius = realPoint.radius; + float finalRadius = realPoint.finalRadius; + double force = realPoint.force; + double maxForce = realPoint.maxForce; + + float newLineRadius = 0; + if (penType == 2) { + + newLineRadius = penRadius; + + } else { + + qint64 currentTimestamp = realPoint.timestamp; + float distance = GetDistanceBetweenPoint(curAnnotPath->points.last().realPoint, currentPoint); + pointSpeed = distance / ((currentTimestamp - previousTimestamp)) * 1000; + newLineRadius = CalculatePointradius(pointSpeed > 0 ? pointSpeed : 0, preLineRadius, penRadius,force,maxForce,stressSpl,stressSwitch,distance); + previousTimestamp = realPoint.timestamp; + preLineRadius = newLineRadius; +// SW_Log::Get()->info(QString("====currentPoint x: %6 y: %7 pointSpeed: %1 newLineRadius: %2 penRadius: %3 stressSwitch: %8 force: %4 maxForce: %5 ") +// .arg(pointSpeed).arg(newLineRadius).arg(penRadius).arg(force).arg(maxForce).arg(currentPoint.x()).arg(currentPoint.y()).arg(stressSwitch)); + } + + SWRealPoint curPenPoint; + curPenPoint.realPoint = currentPoint; + curPenPoint.radius = newLineRadius; + curPenPoint.timestamp = realPoint.timestamp; + curAnnotPath->realPoints.append(curPenPoint); + + /** + * 对原始点进行预贝塞尔加工处理 + */ + int realPointCount = curAnnotPath->realPoints.count(); + if (realPointCount == 2) { + + CGPoint onePoint = curAnnotPath->realPoints.at(0).realPoint; + CGPoint twoPoint = curAnnotPath->realPoints.at(1).realPoint; + CGPoint centerPoint = CGPointMake((onePoint.x()+twoPoint.x())/2.f,(onePoint.y()+twoPoint.y())/2.f); + CalculatePointcutWihtPoint(curAnnotPath,centerPoint, newLineRadius, true, false,curAnnotPath->realPoints.at(1).timestamp); + preBezierPoint = centerPoint; + + } else { + + CGPoint onePoint = curAnnotPath->points.last().realPoint; + CGPoint ctrPoint = curAnnotPath->realPoints.at(realPointCount - 2).realPoint; + CGPoint twoPoint = curAnnotPath->realPoints.at(realPointCount - 1).realPoint; + double t = 0.5f; + double x = pow(1 - t, 2) * onePoint.x() + 2.0 * (1 - t) * t * ctrPoint.x() + t * t * twoPoint.x(); + double y = pow(1 - t, 2) * onePoint.y() + 2.0 * (1 - t) * t * ctrPoint.y() + t * t * twoPoint.y(); + CalculatePointcutWihtPoint(curAnnotPath,CGPointMake(x,y), newLineRadius, true, false,curAnnotPath->realPoints.at(realPointCount - 1).timestamp); + } + +// qDebug() << __FUNCTION__ << "after: " << QDateTime::currentMSecsSinceEpoch(); +// [self swPenPathDraw]; +// SwPenPathDraw(false); + //移动过程中,只进行部分绘制 +// SwPenPathDraw2(false); + } +} + +void SignPainterCacheThread::MousePressd(const SWRealPoint& realPoint) +{ + qDebug() << __FUNCTION__ <points.append(rPoint); + annotPath->realPoints.append(rPoint); + annotPath->isShake = false; + annotPath->pageIndex = currentPageIndex; + annotPath->paintRect = m_PaintRect; + m_AnnotMutex.lock(); + curAnnotPath = annotPath; + m_AnnotMutex.unlock(); + SWPosRest(SWPosPointMake(currentPoint.x(), currentPoint.y(), preLineRadius)); +} + +void SignPainterCacheThread::MouseReleased(const SWRealPoint& realPoint) +{ + qDebug() << __FUNCTION__ <isEnd = true; + int pointCount = curAnnotPath->points.count(); + if(pointCount == 0) + { + curAnnotPath->points.append(realPoint); + curAnnotPath->realPoints.append(realPoint); + pointCount = 1; + } + if (pointCount == 1) { + if(!CGPointEqualToPoint(realPoint.realPoint,CGPointZero)) + { + SwPenPathDrawPoint(curAnnotPath->points.last()); + } + else + { + curAnnotPath = nullptr; + } + } + else + { + if (pointSpeed >= MinSpeed && pointCount > 3 && penType == 1) { + + int tempStrokeSpl = pointCount > strokeSpl ? strokeSpl : (pointCount - 1); + + SWRealPoint lastPenPoint = curAnnotPath->points.at(pointCount - tempStrokeSpl - 1); + lastPenPoint.PRightIntersectPoint = CGPointZero; + lastPenPoint.PLeftIntersectPoint = CGPointZero; + SWPosPoint *posAry = (SWPosPoint *)malloc(tempStrokeSpl*sizeof(SWPosPoint)); + QList pointPack; + int j = 0; + for (int k = (pointCount - tempStrokeSpl); k < pointCount; k ++) { + + SWRealPoint tempPoint = curAnnotPath->points.at(k); + tempPoint.circleCount = 0; + posAry [j] = SWPosPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y(), tempPoint.radius); + j ++; + pointPack.append(tempPoint); + + } + SWPosPoint *newposAry = CalculateStroke(posAry, (int)tempStrokeSpl,lastPenPoint.radius); + // [curAnnotPath->points removeObjectsInArray:pointPack]; + //todo 删除相同点 + int pointPackCount = pointPack.count(); + for(int i = 0 ; i < pointPackCount; i++) + { + for(int m = curAnnotPath->points.count() - 1; m >=0 ; m--) + { + if(CGPointEqualToPoint(curAnnotPath->points.at(m).realPoint,pointPack.at(i).realPoint)) + { + curAnnotPath->points.removeAt(m); + break; + } + } + } + + + for (int k = 0; k < pointPack.count(); k ++) + { + + SWPosPoint postPoint = newposAry[k]; + SWRealPoint tempPoint = pointPack[k]; + tempPoint.radius = postPoint.radius; + CalculatePointcutWihtPoint(curAnnotPath,CGPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y()), tempPoint.radius ,false,false,pointPack[k].timestamp); + } + //todo refresh + // [self swPenPathDraw]; + //从头从新绘制 + // SwPenPathDraw(true); + drawPaths.append(curAnnotPath); + free( posAry); + + } else { + + if (pointCount > 1) + { + + SWRealPoint firstPoint = curAnnotPath->points.at(pointCount - 2); + SWRealPoint secondPoint = curAnnotPath->points.at(pointCount - 1); + double distance = GetDistanceBetweenPoint(firstPoint.realPoint,secondPoint.realPoint); + if (distance < (firstPoint.radius + secondPoint.radius)*2 && firstPoint.circleCount == 0) { + + SWRealPoint tempPoint = curAnnotPath->points.at(pointCount - 1); + tempPoint.circleCount = 0; + curAnnotPath->points.removeAt(pointCount - 1); + CalculatePointcutWihtPoint(curAnnotPath,CGPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y()), tempPoint.radius,false,true,tempPoint.timestamp); + } + } + //todo refresh + // [self swPenPathDraw]; + // SwPenPathDraw(true); + drawPaths.append(curAnnotPath); + } + + } +} + +QPaintDevice *SignPainterCacheThread::PaintingDevice() +{ + QSize size(m_Size.width() * m_fPixmapZoom,m_Size.height() * m_fPixmapZoom *m_fPixmaps); + //绘制buffer + if (m_PaintingBuf == NULL) + { + m_PaintingBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); + m_PaintingBuf->fill(Qt::transparent); + m_OriRect = m_PaintRect; + m_ScrollH = 0; + } + else if(m_PaintingBuf->size() != size) + { + delete m_PaintingBuf; + m_PaintingBuf = NULL; + m_PaintingBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); + m_PaintingBuf->fill(Qt::transparent); + m_OriRect = m_PaintRect; + m_ScrollH = 0; + } +// else +// { +// delete m_PaintingBuf; +// m_PaintingBuf = NULL; +// m_PaintingBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); +// m_PaintingBuf->fill(Qt::transparent); +// } + if (m_BaseBuf == NULL) + { + m_BaseBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); // + m_BaseBuf->fill(Qt::transparent); + + } + else if(m_BaseBuf->size() != size) + { + delete m_BaseBuf; + m_BaseBuf = NULL; + // m_Buf = new QPixmap(m_Size);//new QImage(ur.size(),QImage::Format_ARGB32);// + m_BaseBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied);// + m_BaseBuf->fill(Qt::transparent); + } +// QMutexLocker locker(&m_drawMutex); +// *m_PaintingBuf = m_BaseBuf->copy(); +// m_PaintingBuf = new QImage(m_Size, QImage::Format_ARGB32_Premultiplied); +// m_PaintingBuf->fill(Qt::transparent); + + return m_PaintingBuf; +} + +QPaintDevice *SignPainterCacheThread::PaintedDevice() +{ + return PaintingDevice();//TODO 不使用二级缓存,减少频闪,存在锯齿大问题 + QSize size(m_Size.width() * m_fPixmapZoom,m_Size.height() * m_fPixmapZoom); + //绘制buffer + if (m_BaseBuf == NULL) + { + m_BaseBuf = new QImage(m_Size, QImage::Format_ARGB32_Premultiplied); + m_BaseBuf->fill(Qt::transparent); + } + else if(m_BaseBuf->size() != size) + { + delete m_BaseBuf; + m_BaseBuf = NULL; + m_BaseBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); + m_BaseBuf->fill(Qt::transparent); + } + + return m_BaseBuf; +} + +void SignPainterCacheThread::DrawSignPath(QPainter *painter, const QPainterPath &path,bool isEnd) +{ + if(isEnd || painter == NULL) + return; + painter->fillPath(path,QBrush(m_PenColor)); +// painter->fillPath(path,QBrush(Qt::red)); +} + +void SignPainterCacheThread::SwPenPathDrawPoint(SWRealPoint point) { + + QPaintDevice* device = PaintingDevice(); + QPainterPath BezierPath; + //todo + QPainter bufPainter(device); +// bufPainter.setBrush(Qt::black); + bufPainter.setBrush(m_PenColor); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + bufPainter.setPen(QPen(Qt::NoPen)); + + QTransform transform; + transform.scale(m_fPixmapZoom, m_fPixmapZoom); + bufPainter.setTransform(transform); + + bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); + m_AnnotMutex.lock(); + SWAnnotPath* annotPath = curAnnotPath; + m_AnnotMutex.unlock(); + + annotPath->bezierPaths.clear(); + annotPath->bezierEles.clear(); + //构建顿笔点 + int pathCount = 4; + int leftCount = rand()%5 + 2; + CGPoint endPoint = CGPointMake(point.realPoint.x() + leftCount,point.realPoint.y()+pathCount); + //设置路径点数 + int segments = 5; + + CGPoint onePoint = point.realPoint; + CGPoint twoPoint = endPoint; + CGPoint ctrPoint = CGPointMake((onePoint.x()+twoPoint.x())/2.f, (onePoint.y()+twoPoint.y())/2.f); + for (int i = 0;i < segments;i++) { + + double t = (double)i/segments; + double x = pow(1 - t, 2) * onePoint.x() + 2.0 * (1 - t) * t * ctrPoint.x() + t * t * twoPoint.x(); + double y = pow(1 - t, 2) * onePoint.y() + 2.0 * (1 - t) * t * ctrPoint.y() + t * t * twoPoint.y(); + SWCirclePoint circleP = SWCircleMake(SWPosPointMake(x, y, point.radius)); + QPainterPath circleBizer; + circleBizer.setFillRule(Qt::WindingFill); + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(annotPath->bezierEles); + AddMoveToElement(annotPath->bezierEles,ConvertToCGPoint(circleP.pointA)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + annotPath->bezierPaths.append(circleBizer); + DrawSignPath(&bufPainter,circleBizer,false);//todo + } + drawPaths.append(curAnnotPath); + if(m_PaintingBuf != NULL && m_BaseBuf != NULL) + { + QMutexLocker locker(&m_drawMutex); +// *m_PaintingBuf = m_BaseBuf->copy();//TODO 不使用二级缓存,减少频闪,存在锯齿大问题 + } + +} + +void SignPainterCacheThread::SwPenPathDrawRightPoint(QPainterPath *bPath, QList &elementList,SWRealPoint prePenPoint, + CGPoint prevPoint, QList rPoints,SWRealPoint lastPoint) { + + CGPoint endPoint = CGPointZero; + if (penType == 1) { + + endPoint = CGPointMake((prePenPoint.pLeftTopPoint.x() + prevPoint.x())/2.f, (prePenPoint.pLeftTopPoint.y() + prevPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { + + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + + } else { + + endPoint = prePenPoint.pLeftTopPoint; + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + + } + prevPoint = prePenPoint.pLeftTopPoint; + for (int k = (rPoints.count() - 1); k >= 0 ; k --) + { + + SWRealPoint penPoint = rPoints.at(k); + if (GetPointValid(penPoint)) + { + if (k == (rPoints.count() - 1)) + { + + if (penType == 1) + { + CGPoint endPoint = CGPointMake((prevPoint.x() + penPoint.pRightTopPoint.x())/2.f, (prevPoint.y() + penPoint.pRightTopPoint.y())/2.f); + + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { + + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + SWRealPoint thirdPoint = rPoints.at(k - 1); + if (!CGPointEqualToPoint(thirdPoint.PRightIntersectPoint, CGPointZero)) { + + endPoint = CGPointMake((prevPoint.x() + thirdPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y() + thirdPoint.PRightIntersectPoint.y())/2.f); + + } + else + { + + endPoint = CGPointMake((prevPoint.x() + thirdPoint.pRightBottomPoint.x())/2.f, (prevPoint.y() + thirdPoint.pRightBottomPoint.y())/2.f); + } + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = CGPointEqualToPoint(thirdPoint.PRightIntersectPoint, CGPointZero) ? thirdPoint.pRightBottomPoint : thirdPoint.PRightIntersectPoint; + k--; + /** + * 判断是否到结尾 + */ +// if (k == startIndex) { + if (k == 0) { + + //绘制开始连接点 + if(thirdPoint.pRightBottomPoint.x() != 0 && thirdPoint.pRightBottomPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo8 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(thirdPoint.pRightBottomPoint.x()).arg(thirdPoint.pRightBottomPoint.y()).arg(thirdPoint.pRightBottomPoint.x()).arg(thirdPoint.pRightBottomPoint.y())); + bPath->quadTo(thirdPoint.pRightBottomPoint,thirdPoint.pRightBottomPoint); + } + AddQuadToElement(elementList,thirdPoint.pRightBottomPoint,thirdPoint.pRightBottomPoint); + prevPoint = thirdPoint.pRightBottomPoint; + + SWRealPoint firstPen = rPoints.first(); + if(firstPen.pRightBottomPoint.x() != 0 && firstPen.pRightBottomPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo9 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(firstPen.pRightBottomPoint.x()).arg(firstPen.pRightBottomPoint.y()).arg(firstPen.pLeftBottomPoint.x()).arg(firstPen.pRightBottomPoint.y())); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + } + else + { + CGPoint endPoint = penPoint.pRightTopPoint; + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + } + + } else { + + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PRightIntersectPoint, CGPointZero)) { + + if (!CGPointEqualToPoint(penPoint.pRightTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pRightBottomPoint, CGPointZero)) { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pRightBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pRightBottomPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightBottomPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pRightTopPoint.x())/2.f, (prevPoint.y()+penPoint.pRightTopPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + } + else + { + + CGPoint endPoint = CGPointMake((penPoint.pRightBottomPoint.x() + prevPoint.x())/2.f, (penPoint.pRightBottomPoint.y() + prevPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + bPath->quadTo(penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + AddQuadToElement(elementList,penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + prevPoint = penPoint.pRightBottomPoint; + //绘制开始连接点 + SWRealPoint firstPen = rPoints.first(); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + + } + + } + else + { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.PRightIntersectPoint; + if (!CGPointEqualToPoint(lastPoint.realPoint, CGPointZero) && k == 0) + { + SWRealPoint firstPen = rPoints.first(); + endPoint = CGPointMake((lastPoint.PRightIntersectPoint.x()+firstPen.PRightIntersectPoint.x())/2.f, + (lastPoint.PRightIntersectPoint.y()+firstPen.PRightIntersectPoint.y())/2.f); + bPath->quadTo(penPoint.PRightIntersectPoint,endPoint); + AddQuadToElement(elementList,penPoint.PRightIntersectPoint,endPoint); + + endPoint = CGPointMake((penPoint.PLeftIntersectPoint.x() + lastPoint.PLeftIntersectPoint.x())/2.f, + (penPoint.PLeftIntersectPoint.y() + lastPoint.PLeftIntersectPoint.y())/2.f); + bPath->quadTo(endPoint,endPoint); + } + + } + } + + } + } + +} + + +void SignPainterCacheThread::SwPenPathDrawLeftPoint(QList points,SWRealPoint endRealPoint){ + + QPaintDevice* device = PaintingDevice(); + QPainterPath BezierPath; + QPainter bufPainter(device); + bufPainter.setBrush(m_PenColor); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + bufPainter.setPen(QPen(Qt::NoPen)); + + QTransform transform; + transform.scale(m_fPixmapZoom, m_fPixmapZoom); + bufPainter.setTransform(transform); +// bufPainter.translate(-m_PaintRect.left()-m_ScrollH, -m_PaintRect.top()-m_ScrollH); +// bufPainter.translate(-m_OriRect.left(), -m_OriRect.top()+m_Size.height()+m_ScrollH); + bufPainter.translate(-m_OriRect.left(), -m_OriRect.top()+m_Size.height()); + qDebug() << __FUNCTION__ << " 1111111 start SwPenPathDrawLeftPoint: m_PaintRect: " << m_PaintRect << " m_OriRect: " << m_OriRect << " m_ScrollH: " << m_ScrollH; + + + QList bezierPaths; //绘制的Path + QList bezierEles; //绘制 + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int endIndex = points.count(); + for (int i = 0 ; i < endIndex; i++) + { + SWRealPoint penPoint = points[i]; + if (GetPointValid(penPoint)) + { + + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + SwPenPathDrawRightPoint(&pathBizer, bezierEles,penPoint, prevPoint, rightPoints,endRealPoint); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,false); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(pp.x()).arg(pp.y())); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointB.x).arg(circleP.pointB.y).arg(circleP.pointC.x).arg(circleP.pointC.y).arg(circleP.pointD.x).arg(circleP.pointD.y)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointE.x).arg(circleP.pointE.y).arg(circleP.pointF.x).arg(circleP.pointF.y).arg(circleP.pointG.x).arg(circleP.pointG.y)); + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointH.x).arg(circleP.pointH.y).arg(circleP.pointI.x).arg(circleP.pointI.y).arg(circleP.pointJ.x).arg(circleP.pointJ.y)); + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointK.x).arg(circleP.pointK.y).arg(circleP.pointL.x).arg(circleP.pointL.y).arg(circleP.pointM.x).arg(circleP.pointM.y)); + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); +// bufPainter.drawPath(circleBizer); + DrawSignPath(&bufPainter,circleBizer,false); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { + rightPoints.clear(); + prevPoint = CGPointZero; + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); + if (i == 0 ) { + + CGPoint endPoint = CGPointMake((endRealPoint.PLeftIntersectPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, + (endRealPoint.PLeftIntersectPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.moveTo(endPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + rightPoints.append(penPoint); + + } else { + + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + + } + + } + else + { + rightPoints.append(penPoint); + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero) ) + { + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } else { + + SwPenPathDrawRightPoint(&pathBizer,bezierEles, penPoint,prevPoint, rightPoints,endRealPoint); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,false); + } + + } + else + { + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + } + + } + cursor ++; + + } + + } + + } + +// m_PaintingBuf->save(QString("d:/painting_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); + +} + +// 进行实时的方法 +QPainterPath SignPainterCacheThread::SwPenPathDraw(bool isEnd,bool flushSection) +{ + m_AnnotMutex.lock(); + SWAnnotPath* annotPath = curAnnotPath; + m_AnnotMutex.unlock(); + +// QPaintDevice* device; +// if(isEnd) +// { +// device = PaintedDevice(); +// } +// else +// { +// device = PaintingDevice(); +// } +// device = PaintingDevice(); + QPainterPath BezierPath; + //todo +// QPainter bufPainter(device); +//// bufPainter.setBrush(Qt::black); +// bufPainter.setBrush(m_PenColor); +// bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing +// bufPainter.setPen(QPen(Qt::NoPen)); + +// QTransform transform; +// transform.scale(m_fPixmapZoom, m_fPixmapZoom); +// bufPainter.setTransform(transform); + +// bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); + + if(!annotPath) + return BezierPath; + if (annotPath->points.count() < 2) + { + return BezierPath; + } + + QList bezierPaths; //绘制的Path + QList bezierEles; //绘制 + +// annotPath->bezierPaths.clear(); +// annotPath->bezierEles.clear(); + + int cutPointFlag = 0; + int cutOffSet = 5; + if(!isEnd && annotPath) + { + int pointsCount = annotPath->points.count(); + if(pointsCount - m_lastSectionIndex > drawCount) + { + int cutIndex = -1; + //进行截断处判断是否为补点 + for(int i = (m_lastSectionIndex + drawCount - cutOffSet - 1);i >= 0 ;i --) { + + if (i > 0) { + + SWRealPoint cutPoint = annotPath->points.at(i); + SWRealPoint endRealPoint = annotPath->points.at(i - 1); + if(cutPoint.circleCount == 0 && !CGPointEqualToPoint(cutPoint.PLeftIntersectPoint, CGPointZero) && + endRealPoint.circleCount == 0 && !CGPointEqualToPoint(endRealPoint.PLeftIntersectPoint, CGPointZero)) { + + cutIndex = i; + break; + } + } + + } + if (cutIndex != -1) { + + QList points = annotPath->points.mid(m_lastSectionIndex,cutIndex - m_lastSectionIndex +1); + m_lastSectionPoint = annotPath->points.at(cutIndex - 1); + if (m_lastSectionIndex == 0) { + + SwPenSectionPathDraw(points,SWRealPoint(),0); + + } else { + + SWRealPoint endRealPoint = annotPath->points.at(m_lastSectionIndex - 1); + SwPenSectionPathDraw(points,endRealPoint,1); + } + m_lastSectionIndex = cutIndex; + } + + + } + } + else if(isEnd && annotPath) + { + + QList points = annotPath->points.mid(m_lastSectionIndex,annotPath->points.count() - m_lastSectionIndex); + if (m_lastSectionIndex == 0) { + + SwPenPathDrawLeftPoint(points,SWRealPoint()); + + } else { + + SWRealPoint endRealPoint = annotPath->points.at(m_lastSectionIndex - 1); + SwPenPathDrawLeftPoint(points,endRealPoint); + } + + } + + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int endIndex = annotPath->points.count(); + int startIndex = m_lastSectionIndex; + if(isEnd) + { + startIndex = 0; + m_lastSectionIndex = 0; + m_lastSectionPoint = SWRealPoint(); + + } + for (int i = startIndex ; i < endIndex; i++) + { + SWRealPoint penPoint = annotPath->points[i]; + if (GetPointValid(penPoint)) + { + /** + 判断是否为圆形贝塞尔 + */ + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + + bool isBeging = rightPoints.first().timestamp == annotPath->points.at(startIndex).timestamp; + SwPenPathDrawRightWithBezier(&pathBizer, bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,m_lastSectionPoint,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); +// DrawSignPath(&bufPainter,pathBizer,isEnd); + DrawSignPath(NULL,pathBizer,isEnd); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; +// circleBizer.lineWidth = 0.3f; + CGPoint pp = ConvertToCGPoint(circleP.pointA); + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(pp.x()).arg(pp.y())); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointB.x).arg(circleP.pointB.y).arg(circleP.pointC.x).arg(circleP.pointC.y).arg(circleP.pointD.x).arg(circleP.pointD.y)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointE.x).arg(circleP.pointE.y).arg(circleP.pointF.x).arg(circleP.pointF.y).arg(circleP.pointG.x).arg(circleP.pointG.y)); + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointH.x).arg(circleP.pointH.y).arg(circleP.pointI.x).arg(circleP.pointI.y).arg(circleP.pointJ.x).arg(circleP.pointJ.y)); + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointK.x).arg(circleP.pointK.y).arg(circleP.pointL.x).arg(circleP.pointL.y).arg(circleP.pointM.x).arg(circleP.pointM.y)); + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); +// bufPainter.drawPath(circleBizer); +// DrawSignPath(&bufPainter,circleBizer,isEnd); + DrawSignPath(NULL,circleBizer,isEnd); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { + rightPoints.clear(); + prevPoint = CGPointZero; +// bufPainter.drawPath(pathBizer); + if(i != startIndex) + { +// bezierPaths.append(pathBizer); +// BezierPath.addPath(pathBizer); +// DrawSignPath(&bufPainter,pathBizer,isEnd); + DrawSignPath(NULL,pathBizer,isEnd); + } + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); + if(i != endIndex-1) + { + //最后一个点不进行添加 +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(penPoint.pLeftBottomPoint.x()).arg(penPoint.pLeftBottomPoint.y())); + + } + if (!CGPointEqualToPoint(m_lastSectionPoint.realPoint, CGPointZero) && i == m_lastSectionIndex) { + + CGPoint endPoint = CGPointMake((m_lastSectionPoint.PLeftIntersectPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, + (m_lastSectionPoint.PLeftIntersectPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.moveTo(endPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + rightPoints.append(penPoint); + + } else { + + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + } + +// bezierPaths.append(pathBizer); + } + else + { +// qDebug() << __FUNCTION__ << " cursor != 0 "; + rightPoints.append(penPoint); + if(/*flushSection &&*/ i == endIndex-1 && endIndex != annotPath->points.count()) + { + bool isBeging = rightPoints.first().timestamp == annotPath->points.at(startIndex).timestamp; + SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,m_lastSectionPoint,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); +// bufPainter.drawPath(pathBizer); +// DrawSignPath(&bufPainter,pathBizer,isEnd); + DrawSignPath(NULL,pathBizer,isEnd); +// bufPainter.setPen(QPen(Qt::green, 10, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); +// bufPainter.drawPoint(penPoint.realPoint); + } + else + { + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero) ) + { + // qDebug() << __FUNCTION__ << " cursor != 0 and PLeftIntersectPoint is null"; + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint and pLeftBottomPoint is not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo1 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo2 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } + else + { + + bool isBeging = rightPoints.first().timestamp == annotPath->points.at(startIndex).timestamp; + SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,m_lastSectionPoint,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + // bufPainter.drawPath(pathBizer); +// DrawSignPath(&bufPainter,pathBizer,isEnd); + DrawSignPath(NULL,pathBizer,isEnd); + if(!isEnd) + { + SWCirclePoint circleP = SWCircleMake(SWPosPointMake(penPoint.realPoint.x(), penPoint.realPoint.y(), penPoint.radius)); + QPainterPath circleBizer; + CGPoint pp = ConvertToCGPoint(circleP.pointA); +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(pp.x()).arg(pp.y())); + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointB.x).arg(circleP.pointB.y).arg(circleP.pointC.x).arg(circleP.pointC.y).arg(circleP.pointD.x).arg(circleP.pointD.y)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointE.x).arg(circleP.pointE.y).arg(circleP.pointF.x).arg(circleP.pointF.y).arg(circleP.pointG.x).arg(circleP.pointG.y)); + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointH.x).arg(circleP.pointH.y).arg(circleP.pointI.x).arg(circleP.pointI.y).arg(circleP.pointJ.x).arg(circleP.pointJ.y)); + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointK.x).arg(circleP.pointK.y).arg(circleP.pointL.x).arg(circleP.pointL.y).arg(circleP.pointM.x).arg(circleP.pointM.y)); + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + + // bufPainter.drawPath(circleBizer); +// DrawSignPath(&bufPainter,circleBizer,isEnd); + DrawSignPath(NULL,circleBizer,isEnd); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint or pLeftBottomPoint is null ,to write right."; + // SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // bezierPaths.append(pathBizer); + + // SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // bezierPaths.append(pathBizer); + } + } + + } + else + { + // qDebug() << __FUNCTION__ << " cursor != 0 PLeftIntersectPoint not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo3 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + // qDebug() << __FUNCTION__ << " PLeftIntersectPoint: " << penPoint.PLeftIntersectPoint.x() << penPoint.PLeftIntersectPoint.y(); + } + } + + } + cursor ++; + + } + + } + + } + cutPointFlag = 0; + + //如果抬笔,则进行同步 + if(isEnd) + { + if(annotPath) + { + annotPath->bezierEles = bezierEles; + annotPath->bezierPaths = bezierPaths; + + annotPath->currentPathsList.clear(); + } + + +// if(m_PaintingBuf) +// m_PaintingBuf->save(QString("d:/painting_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); + } + else + { + annotPath->currentPathsList.append(bezierPaths); + } +// else // todo 非抬笔,不更新缓存 +// { +// if(annotPath) +// { +// annotPath->bezierPaths = bezierPaths; +// annotPath->bezierEles = bezierEles; +// } +// } + + return BezierPath; + +// if(isContinue) +// { +// if(m_PaintingBuf != NULL && m_BaseBuf != NULL) +// { +// *m_PaintingBuf = m_BaseBuf->copy(); +// } +// } +} + +// 进行缓存的方法(速度过快没有渲染上的) +QPainterPath SignPainterCacheThread::SwPenPathDraw(SWAnnotPath *annotPath,bool isEnd,bool flushSection) +{ + return QPainterPath(); + qDebug() << __FUNCTION__ << "===========================8888888888888888888899999999999999999999999999999999999"; + QPaintDevice* device; +// if(!flushSection) +// { +// device = PaintedDevice(); +//// qDebug() << __FUNCTION__ << "=========================================="; +// } +// else +// { +// device = PaintingDevice(); +//// qDebug() << __FUNCTION__ << "******************************************"; +// } + if(isEnd) + { + device = PaintedDevice(); + } + else + { + device = PaintingDevice(); + } +// device = PaintingDevice(); + QPainterPath BezierPath; + //todo + QPainter bufPainter(device); +// bufPainter.setBrush(Qt::black); + bufPainter.setBrush(m_PenColor); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing +// bufPainter.setPen(QPen(Qt::NoPen)); + + QTransform transform; + transform.scale(m_fPixmapZoom, m_fPixmapZoom); + bufPainter.setTransform(transform); + + bufPainter.translate(-annotPath->paintRect.left(), -annotPath->paintRect.top()); + if(!annotPath) + return BezierPath; + if (annotPath->points.count() < 2) + { + return BezierPath; + } + + QList bezierPaths; //绘制的Path + QList bezierEles; //绘制 + +// annotPath->bezierPaths.clear(); +// annotPath->bezierEles.clear(); + + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int endIndex = flushSection&&!isEnd ? annotPath->points.count() - drawCount/2 : annotPath->points.count(); +// int endIndex = annotPath->points.count(); + if(flushSection) + { + endIndex = (drawCount-drawCountOffset); + qDebug() << __FUNCTION__ << " startInde: " << drawStartIndex << " endIndex: " << endIndex; + } + int startIndex = drawStartIndex; + if(isEnd) + { + startIndex = 0; + endIndex = annotPath->points.count(); + } + for (int i = startIndex ; i < endIndex; i++) + { + SWRealPoint penPoint = annotPath->points[i]; + if (GetPointValid(penPoint)) + { + /** + 判断是否为圆形贝塞尔 + */ + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + SwPenPathDrawRightWithBezier(&pathBizer, bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,SWRealPoint(),false); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,isEnd); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; +// circleBizer.lineWidth = 0.3f; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); +// bufPainter.drawPath(circleBizer); + DrawSignPath(&bufPainter,circleBizer,isEnd); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { +// pathBizer.lineWidth = 0.3f; + + rightPoints.clear(); + prevPoint = CGPointZero; +// bufPainter.drawPath(pathBizer); + if(i != startIndex) + DrawSignPath(&bufPainter,pathBizer,isEnd); + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); +// pathBizer.moveTo(penPoint.pLeftBottomPoint); +// if(i != annotPath->points.count()-1) + if(i != endIndex-1) + { + //最后一个点不进行添加 + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + } + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + +// bezierPaths.append(pathBizer); + } + else + { +// qDebug() << __FUNCTION__ << " cursor != 0 "; + rightPoints.append(penPoint); + if(/*flushSection &&*/ i == endIndex-1 && endIndex != annotPath->points.count()) + { + SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,SWRealPoint(),false); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); +// bufPainter.drawPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,isEnd); + bufPainter.setPen(QPen(Qt::green, 10, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + bufPainter.drawPoint(penPoint.realPoint); +// SWCirclePoint circleP = SWCircleMake(SWPosPointMake(penPoint.realPoint.x(), penPoint.realPoint.y(), penPoint.radius)); +// QPainterPath circleBizer; +// circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); +// AddStartPathElement(bezierEles); +// AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); +// circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); +// AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); +// AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); +// AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); +// AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + +//// bufPainter.drawPath(circleBizer); +// DrawSignPath(&bufPainter,circleBizer); +// bezierPaths.append(circleBizer); +// BezierPath.addPath(circleBizer); + } + else + { + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero) ) + { + // qDebug() << __FUNCTION__ << " cursor != 0 and PLeftIntersectPoint is null"; + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint and pLeftBottomPoint is not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } + else + { + + SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,SWRealPoint(),false); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + // bufPainter.drawPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,isEnd); + + SWCirclePoint circleP = SWCircleMake(SWPosPointMake(penPoint.realPoint.x(), penPoint.realPoint.y(), penPoint.radius)); + QPainterPath circleBizer; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + + // bufPainter.drawPath(circleBizer); + DrawSignPath(&bufPainter,circleBizer,isEnd); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint or pLeftBottomPoint is null ,to write right."; + // SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // bezierPaths.append(pathBizer); + + // SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // bezierPaths.append(pathBizer); + } + + } + else + { + // qDebug() << __FUNCTION__ << " cursor != 0 PLeftIntersectPoint not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + // qDebug() << __FUNCTION__ << " PLeftIntersectPoint: " << penPoint.PLeftIntersectPoint.x() << penPoint.PLeftIntersectPoint.y(); + } + } + + } + cursor ++; + + } + + } + + } + + //如果抬笔,则进行同步 + if(isEnd) + { + annotPath->bezierEles = bezierEles; + annotPath->bezierPaths = bezierPaths; + } + + return BezierPath; +} + +/** + 绘制右侧路径 + */ +void SignPainterCacheThread::SwPenPathDrawRightWithBezier(QPainterPath* bPath ,QList& elementList, + SWRealPoint prePenPoint,CGPoint prevPoint,QList rPoints,bool end, + bool isContinue,SWRealPoint lastPoint,bool isBegin) +{ + CGPoint endPoint = CGPointZero; + if (end && penType == 1) { + + endPoint = CGPointMake((prePenPoint.pLeftTopPoint.x() + prevPoint.x())/2.f, (prePenPoint.pLeftTopPoint.y() + prevPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo4 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + + } else { + + endPoint = prePenPoint.pLeftTopPoint; + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo5 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + + } + prevPoint = prePenPoint.pLeftTopPoint; + for (int k = (rPoints.count() - 1); k >= 0 ; k --) + { + + SWRealPoint penPoint = rPoints.at(k); + if (GetPointValid(penPoint)) + { + if (k == (rPoints.count() - 1)) + { + + if (end && penType == 1) + { + CGPoint endPoint = CGPointMake((prevPoint.x() + penPoint.pRightTopPoint.x())/2.f, (prevPoint.y() + penPoint.pRightTopPoint.y())/2.f); + + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo6 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + SWRealPoint lastPoint = rPoints.at(k - 1); + if (!CGPointEqualToPoint(lastPoint.PRightIntersectPoint, CGPointZero)) { + + endPoint = CGPointMake((prevPoint.x() + lastPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y() + lastPoint.PRightIntersectPoint.y())/2.f); + + } + else + { + + endPoint = CGPointMake((prevPoint.x() + lastPoint.pRightBottomPoint.x())/2.f, (prevPoint.y() + lastPoint.pRightBottomPoint.y())/2.f); + } + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo7 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = CGPointEqualToPoint(lastPoint.PRightIntersectPoint, CGPointZero) ? lastPoint.pRightBottomPoint : lastPoint.PRightIntersectPoint; + + k--; + /** + * 判断是否到结尾 + */ +// if (k == startIndex) { + if (k == 0) { + + //绘制开始连接点 + if(lastPoint.pRightBottomPoint.x() != 0 && lastPoint.pRightBottomPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo8 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(lastPoint.pRightBottomPoint.x()).arg(lastPoint.pRightBottomPoint.y()).arg(lastPoint.pRightBottomPoint.x()).arg(lastPoint.pRightBottomPoint.y())); + bPath->quadTo(lastPoint.pRightBottomPoint,lastPoint.pRightBottomPoint); + } + AddQuadToElement(elementList,lastPoint.pRightBottomPoint,lastPoint.pRightBottomPoint); + prevPoint = lastPoint.pRightBottomPoint; + + SWRealPoint firstPen = rPoints.first(); + if(firstPen.pRightBottomPoint.x() != 0 && firstPen.pRightBottomPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo9 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(firstPen.pRightBottomPoint.x()).arg(firstPen.pRightBottomPoint.y()).arg(firstPen.pLeftBottomPoint.x()).arg(firstPen.pRightBottomPoint.y())); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + } + else + { + CGPoint endPoint = penPoint.pRightTopPoint; + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + } + + } else { + + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PRightIntersectPoint, CGPointZero)) { + + if (!CGPointEqualToPoint(penPoint.pRightTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pRightBottomPoint, CGPointZero)) { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pRightBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pRightBottomPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightBottomPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pRightTopPoint.x())/2.f, (prevPoint.y()+penPoint.pRightTopPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + } + else + { + + CGPoint endPoint = CGPointMake((penPoint.pRightBottomPoint.x() + prevPoint.x())/2.f, (penPoint.pRightBottomPoint.y() + prevPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + bPath->quadTo(penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + AddQuadToElement(elementList,penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + prevPoint = penPoint.pRightBottomPoint; + //绘制开始连接点 + SWRealPoint firstPen = rPoints.first(); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + + } + + } + else + { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.PRightIntersectPoint; + if (!CGPointEqualToPoint(lastPoint.realPoint, CGPointZero) && k == 0 && isBegin == true) + { + SWRealPoint firstPen = rPoints.first(); + endPoint = CGPointMake((lastPoint.PRightIntersectPoint.x()+firstPen.PRightIntersectPoint.x())/2.f, + (lastPoint.PRightIntersectPoint.y()+firstPen.PRightIntersectPoint.y())/2.f); + bPath->quadTo(penPoint.PRightIntersectPoint,endPoint); + AddQuadToElement(elementList,penPoint.PRightIntersectPoint,endPoint); + + endPoint = CGPointMake((penPoint.PLeftIntersectPoint.x() + lastPoint.PLeftIntersectPoint.x())/2.f, + (penPoint.PLeftIntersectPoint.y() + lastPoint.PLeftIntersectPoint.y())/2.f); + bPath->quadTo(endPoint,endPoint); + } + + } + } + + } + } + +} + diff --git a/signpaintercachethread.h b/signpaintercachethread.h new file mode 100644 index 0000000..6a6eb03 --- /dev/null +++ b/signpaintercachethread.h @@ -0,0 +1,125 @@ +#ifndef SIGNPAINTERCACHETHREAD_H +#define SIGNPAINTERCACHETHREAD_H + +#include +#include +#include +#include +#include +#include +#include "signpenstructs.h" + +class SignPainterCacheThread : public QThread +{ + Q_OBJECT +public: + SignPainterCacheThread(); + void SetPainterRect(QRect rect); + void SetCurrentPageIndex(int page){currentPageIndex = page;} + void AddPoint(QPointF currPoint,int type,float radius,double force,double maxForce); + void Paint(QPainter* painter,QRect currentVisibleRect); + void ClearDraw(); + QList GetAnnotPathLists(){return drawPaths;} + void SetStressSwitch(bool isStressSwitch) { stressSwitch = isStressSwitch; } + bool GetStressSwitch(){return stressSwitch;} + + void SetPenType(int type){penType = type;} + + void SetPenColor(QColor penColor){m_PenColor = penColor;} + +protected: + void run(); + +private: + void PaintWithPainter(QPainter* painter,QRect currentVisibleRect); + + void SwPenSectionPathDraw(QList points,SWRealPoint endRealPoint,int endFlag); + void SwPenSectionPathDrawRightWithBezier(QPainterPath* bPath ,QList& elementList,CGPoint prevPoint,QList rPoints, + SWRealPoint endRealPoint,int endFlag,bool isEnd,bool isBegin); + + + void SwPenPathDrawPoint(SWRealPoint point); + + QPainterPath SwPenPathDraw(bool isEnd,bool flushSection); + QPainterPath SwPenPathDraw(SWAnnotPath *annotPath,bool isEnd,bool flushSection); + void SwPenPathDrawRightWithBezier(QPainterPath* bPath ,QList& elementList,SWRealPoint prePenPoint, + CGPoint prevPoint,QList rPoints,bool end,bool isContinue,SWRealPoint lastPoint,bool isBegin); + + void SwPenPathDrawLeftPoint(QList points,SWRealPoint endRealPoint); + void SwPenPathDrawRightPoint(QPainterPath *bPath, QList &elementList,SWRealPoint prePenPoint, + CGPoint prevPoint, QList rPoints,SWRealPoint endRealPoint); + + void MouseMoved(const SWRealPoint& realPoint); + void MousePressd(const SWRealPoint& realPoint); + void MouseReleased(const SWRealPoint& realPoint); + + void Init(); + + QPaintDevice *PaintingDevice(); + QPaintDevice *PaintedDevice(); + + void DrawSignPath(QPainter* painter,const QPainterPath &path,bool isEnd); + +signals: + void NeedsToRefresh(QRect rect); + void ReleasedExcuted(); + +private: + QList m_RealPoints; + //原始点的互斥锁 + QMutex m_mutex; + QSemaphore m_Sem; + + float preLineRadius; + int strokeSpl; + int stressSwitch;//是否开启压感 1开启 0关闭 + float stressSpl; + + int currentPageIndex; + + qint64 previousTimestamp; + float pointSpeed; + + SWAnnotPath *curAnnotPath; + qint64 lastPaintTimestamp; + int paintFreq; + + //currentAnnot mutex + QMutex m_AnnotMutex; + + QList drawPaths; + + QImage* m_BaseBuf; + //渲染bug,基于m_BaseBuf从上一次倒数10个点开始绘制,绘制到倒数10个点时,数据保存回m_BaseBuf + QImage* m_PaintingBuf; + + QSize m_Size; + QRect m_PaintRect; + QRect m_OriRect;//新建画布原始 + int m_ScrollH; + + int drawStartIndex; + QMutex m_drawMutex; + + int drawCount; + int drawCountOffset; + + //标记上次计算贝塞尔点 + CGPoint preBezierPoint; + + bool isPressed; + float m_fPixmapZoom; + int m_fPixmaps; + + int penType;//画笔类型1软笔2签字笔 + QColor m_PenColor; + + qint64 lasttimestamp; + + int m_BufZoomWidth; + + int m_lastSectionIndex; + SWRealPoint m_lastSectionPoint; +}; + +#endif // SIGNPAINTERCACHETHREAD_H diff --git a/signpaintercachethread_linux.cpp b/signpaintercachethread_linux.cpp new file mode 100644 index 0000000..d613ba5 --- /dev/null +++ b/signpaintercachethread_linux.cpp @@ -0,0 +1,2202 @@ +#include "signpaintercachethread_linux.h" +#include "signpenpainter.h" +#include "signutils.h" +#include "sw_log.h" + +#include +#include +#include +SignPainterCacheThread_Linux::SignPainterCacheThread_Linux() +{ +#ifdef Q_OS_WIN + drawCount = 100;//todo 截断后续需要在切点处 200点后进行截断缓存 +#else + drawCount = 200;//todo 截断后续需要在切点处 200点后进行截断缓存 +#endif + drawCountOffset = 40;// 200点后,截断到160 +// drawCount = 200; +// drawCountOffset = 40; + drawStartIndex = 0; + stressSwitch = 0; + stressSpl = 0;//灵敏度 + strokeSpl = 2; + curAnnotPath = nullptr; + m_BaseBuf = nullptr; + m_PaintingBuf = nullptr; + isPressed = false; + m_fPixmapZoom = 1; + currentPageIndex = -1; + m_fPixmaps = 3; + + penType = 2; + + lasttimestamp = QDateTime::currentMSecsSinceEpoch(); + lastPaintTimestamp = lasttimestamp; + paintFreq = 20; + + m_PaintRect = QRect(0,0,0,0); + m_OriRect = QRect(0,0,0,0); + m_ScrollH = 0; + +} + +void SignPainterCacheThread_Linux::SetPainterRect(QRect rect) +{ + m_Size = rect.size(); + m_PaintRect = rect; +// m_PaintRect = QRect(0,0,rect.width(),rect.height()); + if(m_OriRect.width() > 0) + { + m_ScrollH = m_PaintRect.top() - m_OriRect.top(); + } +} + + +void SignPainterCacheThread_Linux::Init() +{ + drawStartIndex = 0; + //压力灵敏度 + stressSpl = 0; + strokeSpl = 2; + stressSwitch = 0; + pointSpeed = 10; + curAnnotPath = nullptr; + + m_lastSectionIndex = 0; + m_lastSectionPoint = SWRealPoint(); +} + +void SignPainterCacheThread_Linux::AddPoint(QPointF currPoint,int type,float radius,double force,double maxForce) +{ +// SW_Log::Get()->info(QString("====AddPoint x: %1 y: %2 type: %3 radius: %4 force: %5 maxForce: %6 ts: %7" ) +// .arg(currPoint.x()).arg(currPoint.y()).arg(type).arg(radius).arg(force).arg(maxForce).arg(QDateTime::currentMSecsSinceEpoch())); + +// qDebug() << __FUNCTION__ << "====AddPoint : " << currPoint << " type: " << type << " force: " << force << " maxForce: " << maxForce; + SWRealPoint realpoint; + realpoint.realPoint = currPoint; + realpoint.pointType = type; + realpoint.radius = radius; + realpoint.finalRadius = radius; + realpoint.force = force; + realpoint.maxForce = maxForce; + realpoint.timestamp = QDateTime::currentMSecsSinceEpoch(); + if(type == 0) + { + if(lasttimestamp == realpoint.timestamp) + { + if(tempPresspoint.timestamp == -1) + return; + QMutexLocker locker(&m_mutex); + m_RealPoints.append(tempPresspoint); + tempPresspoint.timestamp = -1; + lasttimestamp = realpoint.timestamp; + return; + } + } + if(type == 2 && currPoint.x() == 0 && currPoint.y() == 0) + { + if(curAnnotPath) + { + if(tempPresspoint.timestamp != -1) + { + QMutexLocker locker(&m_mutex); + m_RealPoints.append(tempPresspoint); + tempPresspoint.timestamp = -1; + } + if(curAnnotPath->realPoints.count() > 0) + { + realpoint = curAnnotPath->realPoints.last(); + realpoint.pointType = type; + } + } + } + else if(type == 1) + { + if(tempPresspoint.timestamp == -1) + { + tempPresspoint = realpoint; + return; + } + } + lasttimestamp = realpoint.timestamp; + QMutexLocker locker(&m_mutex); + m_RealPoints.append(realpoint); + m_Sem.release(); +} + +//只绘当前笔 +void SignPainterCacheThread_Linux::PaintWithPainter(QPainter* painter,QRect currentVisibleRect) +{ + if(!curAnnotPath) + return; + if(curAnnotPath->currentPathsList.count() <= 0) + return; + painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + + QList paths = curAnnotPath->currentPathsList.back(); + + qDebug() << __FUNCTION__ << " count: " << paths.count(); + for(int i = 0 ; i < paths.count();i++) + { + QPainterPath path = paths.at(i); + path.setFillRule(Qt::WindingFill); + painter->fillPath(path,QBrush(m_PenColor)); +// painter->fillPath(path,QBrush(Qt::red)); + } + +} + + +void SignPainterCacheThread_Linux::SwPenSectionPathDraw(QList points,SWRealPoint endRealPoint,int endFlag) +{ + QPaintDevice* device = PaintingDevice(); + QPainterPath BezierPath; + QPainter bufPainter(device); +// bufPainter.setBrush(Qt::black); + bufPainter.setBrush(m_PenColor); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + bufPainter.setPen(QPen(Qt::NoPen)); + + QTransform transform; + transform.scale(m_fPixmapZoom, m_fPixmapZoom); + bufPainter.setTransform(transform); +// bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); + bufPainter.translate(-m_OriRect.left(), -m_OriRect.top()+m_Size.height()); + + QList bezierPaths; //绘制的Path + QList bezierEles; //绘制 + +// annotPath->bezierPaths.clear(); +// annotPath->bezierEles.clear(); + + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int endIndex = points.count(); + for (int i = 0 ; i < endIndex; i++) + { + SWRealPoint penPoint = points[i]; + if (GetPointValid(penPoint)) + { + + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + bool isBeging = rightPoints.first().timestamp == points.first().timestamp; + SwPenSectionPathDrawRightWithBezier(&pathBizer, bezierEles, prevPoint, rightPoints,endRealPoint,endFlag,false,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,false); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(pp.x()).arg(pp.y())); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointB.x).arg(circleP.pointB.y).arg(circleP.pointC.x).arg(circleP.pointC.y).arg(circleP.pointD.x).arg(circleP.pointD.y)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointE.x).arg(circleP.pointE.y).arg(circleP.pointF.x).arg(circleP.pointF.y).arg(circleP.pointG.x).arg(circleP.pointG.y)); + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointH.x).arg(circleP.pointH.y).arg(circleP.pointI.x).arg(circleP.pointI.y).arg(circleP.pointJ.x).arg(circleP.pointJ.y)); + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointK.x).arg(circleP.pointK.y).arg(circleP.pointL.x).arg(circleP.pointL.y).arg(circleP.pointM.x).arg(circleP.pointM.y)); + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); +// bufPainter.drawPath(circleBizer); + DrawSignPath(&bufPainter,circleBizer,false); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { + rightPoints.clear(); + prevPoint = CGPointZero; +// bufPainter.drawPath(pathBizer); +// if(i != 0) +// { +// DrawSignPath(&bufPainter,pathBizer,false); +// } + + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); + if (i == 0 ) { + + if(endFlag == 1) { + + CGPoint endPoint = CGPointMake((endRealPoint.PLeftIntersectPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, + (endRealPoint.PLeftIntersectPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + + pathBizer.moveTo(endPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + rightPoints.append(penPoint); + + } else { + + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + } + + } else { + + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + + } + +// bezierPaths.append(pathBizer); + } + else + { + rightPoints.append(penPoint); + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero) ) + { + // qDebug() << __FUNCTION__ << " cursor != 0 and PLeftIntersectPoint is null"; + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint and pLeftBottomPoint is not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo1 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo2 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } + + } + else + { + // qDebug() << __FUNCTION__ << " cursor != 0 PLeftIntersectPoint not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + // SW_Log::Get()->info(QString("====SwPenPathDraw quadTo3 cx: %1 cy: %2 ex:%3 ey: %4" ) + // .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + //qDebug() << __FUNCTION__ << " PLeftIntersectPoint: " << penPoint.PLeftIntersectPoint.x() << penPoint.PLeftIntersectPoint.y(); + } + if(i == endIndex-1) + { + + bool isBeging = rightPoints.first().timestamp == points.first().timestamp; + SwPenSectionPathDrawRightWithBezier(&pathBizer,bezierEles, prevPoint, rightPoints,endRealPoint,endFlag,true,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,false); + } + + + } + cursor ++; + + } + + } + + } + +// m_PaintingBuf->save(QString("d:/painting_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); +} + +void SignPainterCacheThread_Linux::SwPenSectionPathDrawRightWithBezier(QPainterPath *bPath, QList &elementList, + CGPoint prevPoint, QList rPoints,SWRealPoint endRealPoint,int endFlag,bool isEnd,bool isBegin) +{ + for (int k = (rPoints.count() - 1); k >= 0 ; k --) + { + + SWRealPoint penPoint = rPoints.at(k); + if (GetPointValid(penPoint)) + { + if (k == (rPoints.count() - 1)) + { + if (isEnd == true) { + + SWRealPoint prePenPoint = rPoints.at(k - 1); + CGPoint endPoint = CGPointMake((prePenPoint.PRightIntersectPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, + (prePenPoint.PRightIntersectPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(endPoint,endPoint); + AddQuadToElement(elementList,endPoint,endPoint); + prevPoint = prePenPoint.PRightIntersectPoint; + + } else { + + + + bPath->quadTo(prevPoint,penPoint.pLeftTopPoint); + AddQuadToElement(elementList,prevPoint,penPoint.pLeftTopPoint); + prevPoint = penPoint.pLeftTopPoint; + + bPath->quadTo(prevPoint,penPoint.pRightTopPoint); + AddQuadToElement(elementList,prevPoint,penPoint.pRightTopPoint); + prevPoint = penPoint.pRightTopPoint; + } + + + } else { + + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PRightIntersectPoint, CGPointZero)) { + + if (!CGPointEqualToPoint(penPoint.pRightTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pRightBottomPoint, CGPointZero)) { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pRightBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pRightBottomPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightBottomPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pRightTopPoint.x())/2.f, (prevPoint.y()+penPoint.pRightTopPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + } + + } + else + { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.PRightIntersectPoint; + + } + if (k == 0 ) { + + if(endFlag == 1 && isBegin == true) { + + CGPoint endPoint = CGPointMake((penPoint.PRightIntersectPoint.x() + endRealPoint.PRightIntersectPoint.x())/2.f, + (penPoint.PRightIntersectPoint.y() + endRealPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + + prevPoint = endPoint; + endPoint = CGPointMake((penPoint.PLeftIntersectPoint.x() + endRealPoint.PLeftIntersectPoint.x())/2.f, + (penPoint.PLeftIntersectPoint.y() + endRealPoint.PLeftIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + + + + } else { + + CGPoint endPoint = CGPointMake((penPoint.pRightBottomPoint.x() + prevPoint.x())/2.f, (penPoint.pRightBottomPoint.y() + prevPoint.y())/2.f); + + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + bPath->quadTo(penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + AddQuadToElement(elementList,penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + prevPoint = penPoint.pRightBottomPoint; + //绘制开始连接点 + SWRealPoint firstPen = rPoints.first(); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + + } + } + + } + } +} + +void SignPainterCacheThread_Linux::Paint(QPainter* painter,QRect currentVisibleRect) +{ + //使用缓冲画布+实时渲染 + qDebug() << __FUNCTION__ << " start Paint: " << QDateTime::currentMSecsSinceEpoch(); + PaintWithPainter(painter,currentVisibleRect); + if(m_PaintingBuf) + { +// painter->drawImage(m_PaintRect.left(),m_PaintRect.top(),*m_PaintingBuf); + qDebug() << __FUNCTION__ << " 1111111 start Paint: m_PaintRect: " << m_PaintRect << " m_OriRect: " << m_OriRect << " m_ScrollH: " << m_ScrollH; + painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + painter->drawImage(m_PaintRect.left(), m_PaintRect.top(),*m_PaintingBuf,0,m_Size.height()+m_ScrollH,m_Size.width(),m_Size.height()); + +// if(m_drawMutex.tryLock(1)) +// { +// if((int)abs(m_ScrollH) >= m_PaintRect.height()) +// { +// delete m_PaintingBuf; +// m_PaintingBuf = NULL; +// } +// else +// { +// qDebug() << __FUNCTION__ << " 1111111 start Paint: m_PaintRect: " << m_PaintRect << " m_OriRect: " << m_OriRect << " m_ScrollH: " << m_ScrollH; +// painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing +// painter->drawImage(m_PaintRect.left(), m_PaintRect.top(),*m_PaintingBuf,0,m_Size.height()+m_ScrollH,m_Size.width(),m_Size.height()); + +// } +// m_drawMutex.unlock(); +// } + + } + qDebug() << __FUNCTION__ << " end Paint: " << QDateTime::currentMSecsSinceEpoch(); + return; + //全部使用缓冲画布 +// qDebug() << __FUNCTION__ ; + if(m_PaintingBuf != nullptr && painter) + { +// QMutexLocker locker(&m_drawMutex); + +// if(m_drawMutex.tryLock(1)) +// { + // QImage img = *m_PaintingBuf; + painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing +// painter->setPen(Qt::NoPen); +// painter->drawImage(m_PaintRect.left(),m_PaintRect.top(),*m_PaintingBuf); + int viewOffSetW = m_PaintRect.left()-currentVisibleRect.left(); + int viewOffSetH = m_PaintRect.top()-currentVisibleRect.top(); + if((int)abs(viewOffSetH) >= m_PaintRect.height()) + { + delete m_PaintingBuf; + m_PaintingBuf = NULL; + emit NeedsToRefresh(m_PaintRect); + } + else + { +// m_PaintingBuf->save(QString("point_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); +// painter->drawImage(m_PaintRect.left()+viewOffSetW,m_PaintRect.top()+viewOffSetH,*m_PaintingBuf); + painter->drawImage(m_PaintRect.left(),m_PaintRect.top(),*m_PaintingBuf); + } + m_drawMutex.unlock(); +// } + +// if(!isPressed) +// { +// if(m_drawMutex.tryLock(1)) +// { +// // QImage img = *m_PaintingBuf; +// painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing +// painter->setPen(Qt::NoPen); +// painter->drawImage(m_PaintingBuf->rect(),*m_PaintingBuf); +// // painter->drawImage(img.rect(),img); +// m_drawMutex.unlock(); +// } +// } +// else +// { +// painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing +// painter->setPen(Qt::NoPen); +// if(!curAnnotPath) +// return; +// QList paths = curAnnotPath->bezierPaths; +// for(int i = 0 ; i < paths.count(); i++) +// { +// paths[i].setFillRule(Qt::WindingFill); +// painter->fillPath(paths[i],QBrush(Qt::black)); +// } +// } + } +} + +void SignPainterCacheThread_Linux::ClearDraw() +{ +// SW_Log::Get()->info(QString("to ClearDraw")); + m_AnnotMutex.lock(); + if(!isPressed) + { + SW_Log::Get()->info(QString("!isPressed to ClearDraw")); +// if(curAnnotPath != nullptr) +// delete curAnnotPath; + curAnnotPath = nullptr; + for(int i = 0 ; i < drawPaths.count();i++) + { + drawPaths[i]->bezierEles.clear(); + drawPaths[i]->bezierPaths.clear(); + drawPaths[i]->currentPathsList.clear(); + delete drawPaths[i]; + drawPaths[i] = nullptr; + } + drawPaths.clear(); + + if(m_BaseBuf != nullptr) + { + delete m_BaseBuf; + m_BaseBuf = nullptr; + } + if(m_PaintingBuf != nullptr) + { + delete m_PaintingBuf; + m_PaintingBuf = nullptr; + } + + m_lastSectionIndex = 0; + } + m_AnnotMutex.unlock(); + emit NeedsToRefresh(m_PaintRect); +} + +void SignPainterCacheThread_Linux::run() +{ + while(true) + { + m_Sem.acquire(); + + if (m_RealPoints.isEmpty()) + { + continue; + } + m_mutex.lock(); + QList points; + points.swap(m_RealPoints); + m_RealPoints.clear(); + m_mutex.unlock(); + + bool isEnd = false; + //计算点 + for(int i = 0 ; i < points.count(); i++) + { + SWRealPoint realPoint = points[i]; + if(realPoint.pointType == 0) + { + if(!isPressed) + continue; + MouseMoved(realPoint); + } + else if(realPoint.pointType == 1) + { + if(isPressed) + continue; + //press + isPressed = true; + MousePressd(realPoint); +// emit NeedsToRefresh(m_PaintRect); +// if(isEnd) +// emit ReleasedExcuted(); + } + else + { + if(!isPressed) + continue; + isPressed = false; + MouseReleased(realPoint); + isEnd = true; + + QPainterPath path = SwPenPathDraw(isEnd,false); + QRectF rect = path.boundingRect(); + if(curAnnotPath && curAnnotPath->points.count() <= 2) + emit NeedsToRefresh(m_PaintRect); + else + emit NeedsToRefresh(QRect(rect.x()-5,rect.y()-5,rect.width()+10,rect.height()+10)); + if(isEnd) + emit ReleasedExcuted(); + } + } + //检查是否快速写导致部分数据没有刷新到缓存,进行缓存 + for(int i = 0 ; i < drawPaths.count();i++) + { + if(drawPaths.at(i)->bezierEles.isEmpty() && drawPaths.at(i)->realPoints.count()>2 + && !drawPaths.at(i)->isPainted&& curAnnotPath!=drawPaths.at(i)) + { + //需要重绘 + SwPenPathDraw(drawPaths[i],true,false); + } + drawPaths[i]->isPainted = true; + } + //画到缓冲 + if(curAnnotPath) + { + if(!isEnd) + { + QPainterPath path; + if(curAnnotPath->points.count() > drawStartIndex + drawCount) + { + drawStartIndex += (drawCount-drawCountOffset); + path = SwPenPathDraw(isEnd,true); + } + else + { + path = SwPenPathDraw(isEnd,false); + } + + qint64 currentTs = QDateTime::currentMSecsSinceEpoch(); +// if(currentTs - lastPaintTimestamp < paintFreq) +// continue; + lastPaintTimestamp = currentTs; + QRectF rect = path.boundingRect(); + qDebug() << __FUNCTION__ << " ts: " << QDateTime::currentMSecsSinceEpoch(); +// emit NeedsToRefresh(QRect(rect.x()-5,rect.y()-5,rect.width()+10,rect.height()+10)); + emit NeedsToRefresh(m_PaintRect); + } + } + } +} + +void SignPainterCacheThread_Linux::MouseMoved(const SWRealPoint& realPoint) +{ +// qDebug() << __FUNCTION__ <realPoints.count() <= 0) + { + SWRealPoint curPenPoint; + curPenPoint.realPoint = currentPoint; + curPenPoint.radius = realPoint.radius; + curPenPoint.finalRadius = realPoint.radius; + curPenPoint.force = realPoint.force; + curPenPoint.maxForce = realPoint.maxForce; + curPenPoint.timestamp = realPoint.timestamp; + curAnnotPath->realPoints.append(curPenPoint); + curAnnotPath->points.append(curPenPoint); + return; + } + /** + 判断临近相同点,并过滤 + */ + if (!CGPointEqualToPoint(currentPoint, curAnnotPath->realPoints.last().realPoint) || GetDistanceBetweenPoint(currentPoint, curAnnotPath->realPoints.last().realPoint) > 500) { + + /** + 计算速度半径 + */ + //todo 计算速度 + float penRadius = realPoint.radius; + float finalRadius = realPoint.finalRadius; + double force = realPoint.force; + double maxForce = realPoint.maxForce; + + float newLineRadius = 0; + if (penType == 2) { + + newLineRadius = penRadius; + + } else { + + qint64 currentTimestamp = realPoint.timestamp; + float distance = GetDistanceBetweenPoint(curAnnotPath->points.last().realPoint, currentPoint); + pointSpeed = distance / ((currentTimestamp - previousTimestamp)) * 1000; + newLineRadius = CalculatePointradius(pointSpeed > 0 ? pointSpeed : 0, preLineRadius, penRadius,force,maxForce,stressSpl,stressSwitch,distance); + previousTimestamp = realPoint.timestamp; + preLineRadius = newLineRadius; +// SW_Log::Get()->info(QString("====currentPoint x: %6 y: %7 pointSpeed: %1 newLineRadius: %2 penRadius: %3 stressSwitch: %8 force: %4 maxForce: %5 ") +// .arg(pointSpeed).arg(newLineRadius).arg(penRadius).arg(force).arg(maxForce).arg(currentPoint.x()).arg(currentPoint.y()).arg(stressSwitch)); + } + + SWRealPoint curPenPoint; + curPenPoint.realPoint = currentPoint; + curPenPoint.radius = newLineRadius; + curPenPoint.timestamp = realPoint.timestamp; + curAnnotPath->realPoints.append(curPenPoint); + + /** + * 对原始点进行预贝塞尔加工处理 + */ + int realPointCount = curAnnotPath->realPoints.count(); + if (realPointCount == 2) { + + CGPoint onePoint = curAnnotPath->realPoints.at(0).realPoint; + CGPoint twoPoint = curAnnotPath->realPoints.at(1).realPoint; + CGPoint centerPoint = CGPointMake((onePoint.x()+twoPoint.x())/2.f,(onePoint.y()+twoPoint.y())/2.f); + CalculatePointcutWihtPoint(curAnnotPath,centerPoint, newLineRadius, true, false,curAnnotPath->realPoints.at(1).timestamp); + preBezierPoint = centerPoint; + + } else { + + CGPoint onePoint = curAnnotPath->points.last().realPoint; + CGPoint ctrPoint = curAnnotPath->realPoints.at(realPointCount - 2).realPoint; + CGPoint twoPoint = curAnnotPath->realPoints.at(realPointCount - 1).realPoint; + double t = 0.5f; + double x = pow(1 - t, 2) * onePoint.x() + 2.0 * (1 - t) * t * ctrPoint.x() + t * t * twoPoint.x(); + double y = pow(1 - t, 2) * onePoint.y() + 2.0 * (1 - t) * t * ctrPoint.y() + t * t * twoPoint.y(); + CalculatePointcutWihtPoint(curAnnotPath,CGPointMake(x,y), newLineRadius, true, false,curAnnotPath->realPoints.at(realPointCount - 1).timestamp); + } + +// qDebug() << __FUNCTION__ << "after: " << QDateTime::currentMSecsSinceEpoch(); +// [self swPenPathDraw]; +// SwPenPathDraw(false); + //移动过程中,只进行部分绘制 +// SwPenPathDraw2(false); + } +} + +void SignPainterCacheThread_Linux::MousePressd(const SWRealPoint& realPoint) +{ + qDebug() << __FUNCTION__ <points.append(rPoint); + annotPath->realPoints.append(rPoint); + annotPath->isShake = false; + annotPath->pageIndex = currentPageIndex; + annotPath->paintRect = m_PaintRect; + m_AnnotMutex.lock(); + curAnnotPath = annotPath; + m_AnnotMutex.unlock(); + SWPosRest(SWPosPointMake(currentPoint.x(), currentPoint.y(), preLineRadius)); +} + +void SignPainterCacheThread_Linux::MouseReleased(const SWRealPoint& realPoint) +{ + SW_Log::Get()->info(QString("SignPainterCacheThread_Linux::MouseReleased: point: %1 %2 ") + .arg(realPoint.realPoint.x()).arg(realPoint.realPoint.y())); + qDebug() << __FUNCTION__ <isEnd = true; + int pointCount = curAnnotPath->points.count(); + SW_Log::Get()->info(QString("SignPainterCacheThread_Linux::MouseReleased: before count: %1 ").arg(pointCount)); + if(pointCount == 0) + { + curAnnotPath->points.append(realPoint); + curAnnotPath->realPoints.append(realPoint); + pointCount = 1; + } + if (pointCount == 1) { + SW_Log::Get()->info(QString("SignPainterCacheThread_Linux::MouseReleased: count: %1 point: %2 %3 ").arg(pointCount) + .arg(realPoint.realPoint.x()).arg(realPoint.realPoint.y())); + if(!CGPointEqualToPoint(realPoint.realPoint,CGPointZero)) + { + SwPenPathDrawPoint(curAnnotPath->points.last()); + } + else + { + curAnnotPath = nullptr; + } + } + else + { + if (pointSpeed >= MinSpeed && pointCount > 3 && penType == 1) { + + int tempStrokeSpl = pointCount > strokeSpl ? strokeSpl : (pointCount - 1); + + SWRealPoint lastPenPoint = curAnnotPath->points.at(pointCount - tempStrokeSpl - 1); + lastPenPoint.PRightIntersectPoint = CGPointZero; + lastPenPoint.PLeftIntersectPoint = CGPointZero; + SWPosPoint *posAry = (SWPosPoint *)malloc(tempStrokeSpl*sizeof(SWPosPoint)); + QList pointPack; + int j = 0; + for (int k = (pointCount - tempStrokeSpl); k < pointCount; k ++) { + + SWRealPoint tempPoint = curAnnotPath->points.at(k); + tempPoint.circleCount = 0; + posAry [j] = SWPosPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y(), tempPoint.radius); + j ++; + pointPack.append(tempPoint); + + } + SWPosPoint *newposAry = CalculateStroke(posAry, (int)tempStrokeSpl,lastPenPoint.radius); + // [curAnnotPath->points removeObjectsInArray:pointPack]; + //todo 删除相同点 + int pointPackCount = pointPack.count(); + for(int i = 0 ; i < pointPackCount; i++) + { + for(int m = curAnnotPath->points.count() - 1; m >=0 ; m--) + { + if(CGPointEqualToPoint(curAnnotPath->points.at(m).realPoint,pointPack.at(i).realPoint)) + { + curAnnotPath->points.removeAt(m); + break; + } + } + } + + + for (int k = 0; k < pointPack.count(); k ++) + { + + SWPosPoint postPoint = newposAry[k]; + SWRealPoint tempPoint = pointPack[k]; + tempPoint.radius = postPoint.radius; + CalculatePointcutWihtPoint(curAnnotPath,CGPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y()), tempPoint.radius ,false,false,pointPack[k].timestamp); + } + //todo refresh + // [self swPenPathDraw]; + //从头从新绘制 + // SwPenPathDraw(true); + drawPaths.append(curAnnotPath); + free( posAry); + + } else { + + if (pointCount > 1) + { + + SWRealPoint firstPoint = curAnnotPath->points.at(pointCount - 2); + SWRealPoint secondPoint = curAnnotPath->points.at(pointCount - 1); + double distance = GetDistanceBetweenPoint(firstPoint.realPoint,secondPoint.realPoint); + if (distance < (firstPoint.radius + secondPoint.radius)*2 && firstPoint.circleCount == 0) { + + SWRealPoint tempPoint = curAnnotPath->points.at(pointCount - 1); + tempPoint.circleCount = 0; + curAnnotPath->points.removeAt(pointCount - 1); + CalculatePointcutWihtPoint(curAnnotPath,CGPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y()), tempPoint.radius,false,true,tempPoint.timestamp); + } + } + //todo refresh + // [self swPenPathDraw]; + // SwPenPathDraw(true); + drawPaths.append(curAnnotPath); + } + + } +} + +QPaintDevice *SignPainterCacheThread_Linux::PaintingDevice() +{ + QSize size(m_Size.width() * m_fPixmapZoom,m_Size.height() * m_fPixmapZoom *m_fPixmaps); + //绘制buffer + if (m_PaintingBuf == NULL) + { + m_PaintingBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); + m_PaintingBuf->fill(Qt::transparent); + m_OriRect = m_PaintRect; + m_ScrollH = 0; + } + else if(m_PaintingBuf->size() != size) + { + delete m_PaintingBuf; + m_PaintingBuf = NULL; + m_PaintingBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); + m_PaintingBuf->fill(Qt::transparent); + m_OriRect = m_PaintRect; + m_ScrollH = 0; + } +// else +// { +// delete m_PaintingBuf; +// m_PaintingBuf = NULL; +// m_PaintingBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); +// m_PaintingBuf->fill(Qt::transparent); +// } + if (m_BaseBuf == NULL) + { + m_BaseBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); // + m_BaseBuf->fill(Qt::transparent); + + } + else if(m_BaseBuf->size() != size) + { + delete m_BaseBuf; + m_BaseBuf = NULL; + // m_Buf = new QPixmap(m_Size);//new QImage(ur.size(),QImage::Format_ARGB32);// + m_BaseBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied);// + m_BaseBuf->fill(Qt::transparent); + } +// QMutexLocker locker(&m_drawMutex); +// *m_PaintingBuf = m_BaseBuf->copy(); +// m_PaintingBuf = new QImage(m_Size, QImage::Format_ARGB32_Premultiplied); +// m_PaintingBuf->fill(Qt::transparent); + + return m_PaintingBuf; +} + +QPaintDevice *SignPainterCacheThread_Linux::PaintedDevice() +{ + return PaintingDevice();//TODO 不使用二级缓存,减少频闪,存在锯齿大问题 + QSize size(m_Size.width() * m_fPixmapZoom,m_Size.height() * m_fPixmapZoom); + //绘制buffer + if (m_BaseBuf == NULL) + { + m_BaseBuf = new QImage(m_Size, QImage::Format_ARGB32_Premultiplied); + m_BaseBuf->fill(Qt::transparent); + } + else if(m_BaseBuf->size() != size) + { + delete m_BaseBuf; + m_BaseBuf = NULL; + m_BaseBuf = new QImage(size, QImage::Format_ARGB32_Premultiplied); + m_BaseBuf->fill(Qt::transparent); + } + + return m_BaseBuf; +} + +void SignPainterCacheThread_Linux::DrawSignPath(QPainter *painter, const QPainterPath &path,bool isEnd) +{ + if(isEnd || painter == NULL) + return; + painter->fillPath(path,QBrush(m_PenColor)); +// painter->fillPath(path,QBrush(Qt::red)); +} + +void SignPainterCacheThread_Linux::SwPenPathDrawPoint(SWRealPoint point) { + + QPaintDevice* device = PaintingDevice(); + QPainterPath BezierPath; + //todo + QPainter bufPainter(device); +// bufPainter.setBrush(Qt::black); + bufPainter.setBrush(m_PenColor); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + bufPainter.setPen(QPen(Qt::NoPen)); + + QTransform transform; + transform.scale(m_fPixmapZoom, m_fPixmapZoom); + bufPainter.setTransform(transform); + + bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); + m_AnnotMutex.lock(); + SWAnnotPath* annotPath = curAnnotPath; + m_AnnotMutex.unlock(); + + annotPath->bezierPaths.clear(); + annotPath->bezierEles.clear(); + //构建顿笔点 + int pathCount = 4; + int leftCount = rand()%5 + 2; + CGPoint endPoint = CGPointMake(point.realPoint.x() + leftCount,point.realPoint.y()+pathCount); + //设置路径点数 + int segments = 5; + + CGPoint onePoint = point.realPoint; + CGPoint twoPoint = endPoint; + CGPoint ctrPoint = CGPointMake((onePoint.x()+twoPoint.x())/2.f, (onePoint.y()+twoPoint.y())/2.f); + for (int i = 0;i < segments;i++) { + + double t = (double)i/segments; + double x = pow(1 - t, 2) * onePoint.x() + 2.0 * (1 - t) * t * ctrPoint.x() + t * t * twoPoint.x(); + double y = pow(1 - t, 2) * onePoint.y() + 2.0 * (1 - t) * t * ctrPoint.y() + t * t * twoPoint.y(); + SWCirclePoint circleP = SWCircleMake(SWPosPointMake(x, y, point.radius)); + QPainterPath circleBizer; + circleBizer.setFillRule(Qt::WindingFill); + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(annotPath->bezierEles); + AddMoveToElement(annotPath->bezierEles,ConvertToCGPoint(circleP.pointA)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + annotPath->bezierPaths.append(circleBizer); + DrawSignPath(&bufPainter,circleBizer,false);//todo + } + drawPaths.append(curAnnotPath); + if(m_PaintingBuf != NULL && m_BaseBuf != NULL) + { + QMutexLocker locker(&m_drawMutex); +// *m_PaintingBuf = m_BaseBuf->copy();//TODO 不使用二级缓存,减少频闪,存在锯齿大问题 + } + +} + +void SignPainterCacheThread_Linux::SwPenPathDrawRightPoint(QPainterPath *bPath, QList &elementList,SWRealPoint prePenPoint, + CGPoint prevPoint, QList rPoints,SWRealPoint lastPoint) { + + CGPoint endPoint = CGPointZero; + if (penType == 1) { + + endPoint = CGPointMake((prePenPoint.pLeftTopPoint.x() + prevPoint.x())/2.f, (prePenPoint.pLeftTopPoint.y() + prevPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { + + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + + } else { + + endPoint = prePenPoint.pLeftTopPoint; + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + + } + prevPoint = prePenPoint.pLeftTopPoint; + for (int k = (rPoints.count() - 1); k >= 0 ; k --) + { + + SWRealPoint penPoint = rPoints.at(k); + if (GetPointValid(penPoint)) + { + if (k == (rPoints.count() - 1)) + { + + if (penType == 1) + { + CGPoint endPoint = CGPointMake((prevPoint.x() + penPoint.pRightTopPoint.x())/2.f, (prevPoint.y() + penPoint.pRightTopPoint.y())/2.f); + + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { + + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + SWRealPoint thirdPoint = rPoints.at(k - 1); + if (!CGPointEqualToPoint(thirdPoint.PRightIntersectPoint, CGPointZero)) { + + endPoint = CGPointMake((prevPoint.x() + thirdPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y() + thirdPoint.PRightIntersectPoint.y())/2.f); + + } + else + { + + endPoint = CGPointMake((prevPoint.x() + thirdPoint.pRightBottomPoint.x())/2.f, (prevPoint.y() + thirdPoint.pRightBottomPoint.y())/2.f); + } + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = CGPointEqualToPoint(thirdPoint.PRightIntersectPoint, CGPointZero) ? thirdPoint.pRightBottomPoint : thirdPoint.PRightIntersectPoint; + k--; + /** + * 判断是否到结尾 + */ +// if (k == startIndex) { + if (k == 0) { + + //绘制开始连接点 + if(thirdPoint.pRightBottomPoint.x() != 0 && thirdPoint.pRightBottomPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo8 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(thirdPoint.pRightBottomPoint.x()).arg(thirdPoint.pRightBottomPoint.y()).arg(thirdPoint.pRightBottomPoint.x()).arg(thirdPoint.pRightBottomPoint.y())); + bPath->quadTo(thirdPoint.pRightBottomPoint,thirdPoint.pRightBottomPoint); + } + AddQuadToElement(elementList,thirdPoint.pRightBottomPoint,thirdPoint.pRightBottomPoint); + prevPoint = thirdPoint.pRightBottomPoint; + + SWRealPoint firstPen = rPoints.first(); + if(firstPen.pRightBottomPoint.x() != 0 && firstPen.pRightBottomPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo9 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(firstPen.pRightBottomPoint.x()).arg(firstPen.pRightBottomPoint.y()).arg(firstPen.pLeftBottomPoint.x()).arg(firstPen.pRightBottomPoint.y())); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + } + else + { + CGPoint endPoint = penPoint.pRightTopPoint; + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + } + + } else { + + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PRightIntersectPoint, CGPointZero)) { + + if (!CGPointEqualToPoint(penPoint.pRightTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pRightBottomPoint, CGPointZero)) { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pRightBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pRightBottomPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightBottomPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pRightTopPoint.x())/2.f, (prevPoint.y()+penPoint.pRightTopPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + } + else + { + + CGPoint endPoint = CGPointMake((penPoint.pRightBottomPoint.x() + prevPoint.x())/2.f, (penPoint.pRightBottomPoint.y() + prevPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + bPath->quadTo(penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + AddQuadToElement(elementList,penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + prevPoint = penPoint.pRightBottomPoint; + //绘制开始连接点 + SWRealPoint firstPen = rPoints.first(); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + + } + + } + else + { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.PRightIntersectPoint; + if (!CGPointEqualToPoint(lastPoint.realPoint, CGPointZero) && k == 0) + { + SWRealPoint firstPen = rPoints.first(); + endPoint = CGPointMake((lastPoint.PRightIntersectPoint.x()+firstPen.PRightIntersectPoint.x())/2.f, + (lastPoint.PRightIntersectPoint.y()+firstPen.PRightIntersectPoint.y())/2.f); + bPath->quadTo(penPoint.PRightIntersectPoint,endPoint); + AddQuadToElement(elementList,penPoint.PRightIntersectPoint,endPoint); + + endPoint = CGPointMake((penPoint.PLeftIntersectPoint.x() + lastPoint.PLeftIntersectPoint.x())/2.f, + (penPoint.PLeftIntersectPoint.y() + lastPoint.PLeftIntersectPoint.y())/2.f); + bPath->quadTo(endPoint,endPoint); + } + + } + } + + } + } + +} + + +void SignPainterCacheThread_Linux::SwPenPathDrawLeftPoint(QList points,SWRealPoint endRealPoint){ + + QPaintDevice* device = PaintingDevice(); + QPainterPath BezierPath; + QPainter bufPainter(device); + bufPainter.setBrush(m_PenColor); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing + bufPainter.setPen(QPen(Qt::NoPen)); + + QTransform transform; + transform.scale(m_fPixmapZoom, m_fPixmapZoom); + bufPainter.setTransform(transform); +// bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); + bufPainter.translate(-m_OriRect.left(), -m_OriRect.top()+m_Size.height()); + qDebug() << __FUNCTION__ << " 1111111 start SwPenPathDrawLeftPoint: m_PaintRect: " << m_PaintRect << " m_OriRect: " << m_OriRect << " m_ScrollH: " << m_ScrollH; + +// SW_Log::Get()->info(QString("SwPenPathDrawLeftPoint : m_PaintRect: %1,%2,%3,%4 m_OriRect: %5 %6 %7 %8 m_ScrollH: %9") +// .arg(m_PaintRect.left()).arg(m_PaintRect.top()).arg(m_PaintRect.width()).arg(m_PaintRect.height()) +// .arg(m_OriRect.left()).arg(m_OriRect.top()).arg(m_OriRect.width()).arg(m_OriRect.height()).arg(m_ScrollH)); + QList bezierPaths; //绘制的Path + QList bezierEles; //绘制 + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int endIndex = points.count(); + for (int i = 0 ; i < endIndex; i++) + { + SWRealPoint penPoint = points[i]; + if (GetPointValid(penPoint)) + { + + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + SwPenPathDrawRightPoint(&pathBizer, bezierEles,penPoint, prevPoint, rightPoints,endRealPoint); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,false); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(pp.x()).arg(pp.y())); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointB.x).arg(circleP.pointB.y).arg(circleP.pointC.x).arg(circleP.pointC.y).arg(circleP.pointD.x).arg(circleP.pointD.y)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointE.x).arg(circleP.pointE.y).arg(circleP.pointF.x).arg(circleP.pointF.y).arg(circleP.pointG.x).arg(circleP.pointG.y)); + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointH.x).arg(circleP.pointH.y).arg(circleP.pointI.x).arg(circleP.pointI.y).arg(circleP.pointJ.x).arg(circleP.pointJ.y)); + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointK.x).arg(circleP.pointK.y).arg(circleP.pointL.x).arg(circleP.pointL.y).arg(circleP.pointM.x).arg(circleP.pointM.y)); + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); +// bufPainter.drawPath(circleBizer); + DrawSignPath(&bufPainter,circleBizer,false); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { + rightPoints.clear(); + prevPoint = CGPointZero; + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); + if (i == 0 ) { + + CGPoint endPoint = CGPointMake((endRealPoint.PLeftIntersectPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, + (endRealPoint.PLeftIntersectPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.moveTo(endPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + rightPoints.append(penPoint); + + } else { + + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + + } + + } + else + { + rightPoints.append(penPoint); + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero) ) + { + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } else { + + SwPenPathDrawRightPoint(&pathBizer,bezierEles, penPoint,prevPoint, rightPoints,endRealPoint); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,false); + } + + } + else + { + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + } + + } + cursor ++; + + } + + } + + } + +// m_PaintingBuf->save(QString("d:/painting_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); + +} + +// 进行实时的方法 +QPainterPath SignPainterCacheThread_Linux::SwPenPathDraw(bool isEnd,bool flushSection) +{ + m_AnnotMutex.lock(); + SWAnnotPath* annotPath = curAnnotPath; + m_AnnotMutex.unlock(); + +// QPaintDevice* device; +// if(isEnd) +// { +// device = PaintedDevice(); +// } +// else +// { +// device = PaintingDevice(); +// } +// device = PaintingDevice(); + QPainterPath BezierPath; + //todo +// QPainter bufPainter(device); +//// bufPainter.setBrush(Qt::black); +// bufPainter.setBrush(m_PenColor); +// bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing +// bufPainter.setPen(QPen(Qt::NoPen)); + +// QTransform transform; +// transform.scale(m_fPixmapZoom, m_fPixmapZoom); +// bufPainter.setTransform(transform); + +// bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); + + if(!annotPath) + return BezierPath; + if (annotPath->points.count() < 2) + { + return BezierPath; + } + + QList bezierPaths; //绘制的Path + QList bezierEles; //绘制 + +// annotPath->bezierPaths.clear(); +// annotPath->bezierEles.clear(); + + int cutPointFlag = 0; + int cutOffSet = 5; + if(!isEnd && annotPath) + { + int pointsCount = annotPath->points.count(); + if(pointsCount - m_lastSectionIndex > drawCount) + { + int cutIndex = -1; + //进行截断处判断是否为补点 + for(int i = (m_lastSectionIndex + drawCount - cutOffSet - 1);i >= 0 ;i --) { + + if (i > 0) { + + SWRealPoint cutPoint = annotPath->points.at(i); + SWRealPoint endRealPoint = annotPath->points.at(i - 1); + if(cutPoint.circleCount == 0 && !CGPointEqualToPoint(cutPoint.PLeftIntersectPoint, CGPointZero) && + endRealPoint.circleCount == 0 && !CGPointEqualToPoint(endRealPoint.PLeftIntersectPoint, CGPointZero)) { + + cutIndex = i; + break; + } + } + + } + if (cutIndex != -1) { + + QList points = annotPath->points.mid(m_lastSectionIndex,cutIndex - m_lastSectionIndex +1); + m_lastSectionPoint = annotPath->points.at(cutIndex - 1); + if (m_lastSectionIndex == 0) { + + SwPenSectionPathDraw(points,SWRealPoint(),0); + + } else { + + SWRealPoint endRealPoint = annotPath->points.at(m_lastSectionIndex - 1); + SwPenSectionPathDraw(points,endRealPoint,1); + } + m_lastSectionIndex = cutIndex; + } + + + } + } + else if(isEnd && annotPath) + { + + QList points = annotPath->points.mid(m_lastSectionIndex,annotPath->points.count() - m_lastSectionIndex); + if (m_lastSectionIndex == 0) { + + SwPenPathDrawLeftPoint(points,SWRealPoint()); + + } else { + + SWRealPoint endRealPoint = annotPath->points.at(m_lastSectionIndex - 1); + SwPenPathDrawLeftPoint(points,endRealPoint); + } + + } + + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int endIndex = annotPath->points.count(); + int startIndex = m_lastSectionIndex; + if(isEnd) + { + startIndex = 0; + m_lastSectionIndex = 0; + m_lastSectionPoint = SWRealPoint(); + + } + for (int i = startIndex ; i < endIndex; i++) + { + SWRealPoint penPoint = annotPath->points[i]; + if (GetPointValid(penPoint)) + { + /** + 判断是否为圆形贝塞尔 + */ + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + + bool isBeging = rightPoints.first().timestamp == annotPath->points.at(startIndex).timestamp; + SwPenPathDrawRightWithBezier(&pathBizer, bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,m_lastSectionPoint,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); +// DrawSignPath(&bufPainter,pathBizer,isEnd); + DrawSignPath(NULL,pathBizer,isEnd); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; +// circleBizer.lineWidth = 0.3f; + CGPoint pp = ConvertToCGPoint(circleP.pointA); + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(pp.x()).arg(pp.y())); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointB.x).arg(circleP.pointB.y).arg(circleP.pointC.x).arg(circleP.pointC.y).arg(circleP.pointD.x).arg(circleP.pointD.y)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointE.x).arg(circleP.pointE.y).arg(circleP.pointF.x).arg(circleP.pointF.y).arg(circleP.pointG.x).arg(circleP.pointG.y)); + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointH.x).arg(circleP.pointH.y).arg(circleP.pointI.x).arg(circleP.pointI.y).arg(circleP.pointJ.x).arg(circleP.pointJ.y)); + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointK.x).arg(circleP.pointK.y).arg(circleP.pointL.x).arg(circleP.pointL.y).arg(circleP.pointM.x).arg(circleP.pointM.y)); + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); +// bufPainter.drawPath(circleBizer); +// DrawSignPath(&bufPainter,circleBizer,isEnd); + DrawSignPath(NULL,circleBizer,isEnd); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { + rightPoints.clear(); + prevPoint = CGPointZero; +// bufPainter.drawPath(pathBizer); + if(i != startIndex) + { +// bezierPaths.append(pathBizer); +// BezierPath.addPath(pathBizer); +// DrawSignPath(&bufPainter,pathBizer,isEnd); + DrawSignPath(NULL,pathBizer,isEnd); + } + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); + if(i != endIndex-1) + { + //最后一个点不进行添加 +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(penPoint.pLeftBottomPoint.x()).arg(penPoint.pLeftBottomPoint.y())); + + } + if (!CGPointEqualToPoint(m_lastSectionPoint.realPoint, CGPointZero) && i == m_lastSectionIndex) { + + CGPoint endPoint = CGPointMake((m_lastSectionPoint.PLeftIntersectPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, + (m_lastSectionPoint.PLeftIntersectPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.moveTo(endPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + rightPoints.append(penPoint); + + } else { + + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + } + +// bezierPaths.append(pathBizer); + } + else + { +// qDebug() << __FUNCTION__ << " cursor != 0 "; + rightPoints.append(penPoint); + if(/*flushSection &&*/ i == endIndex-1 && endIndex != annotPath->points.count()) + { + bool isBeging = rightPoints.first().timestamp == annotPath->points.at(startIndex).timestamp; + SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,m_lastSectionPoint,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); +// bufPainter.drawPath(pathBizer); +// DrawSignPath(&bufPainter,pathBizer,isEnd); + DrawSignPath(NULL,pathBizer,isEnd); +// bufPainter.setPen(QPen(Qt::green, 10, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); +// bufPainter.drawPoint(penPoint.realPoint); + } + else + { + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero) ) + { + // qDebug() << __FUNCTION__ << " cursor != 0 and PLeftIntersectPoint is null"; + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint and pLeftBottomPoint is not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo1 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo2 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } + else + { + + bool isBeging = rightPoints.first().timestamp == annotPath->points.at(startIndex).timestamp; + SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,m_lastSectionPoint,isBeging); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + // bufPainter.drawPath(pathBizer); +// DrawSignPath(&bufPainter,pathBizer,isEnd); + DrawSignPath(NULL,pathBizer,isEnd); + if(!isEnd) + { + SWCirclePoint circleP = SWCircleMake(SWPosPointMake(penPoint.realPoint.x(), penPoint.realPoint.y(), penPoint.radius)); + QPainterPath circleBizer; + CGPoint pp = ConvertToCGPoint(circleP.pointA); +// SW_Log::Get()->info(QString("====SwPenPathDraw moveTo x: %1 y: %2" ) +// .arg(pp.x()).arg(pp.y())); + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointB.x).arg(circleP.pointB.y).arg(circleP.pointC.x).arg(circleP.pointC.y).arg(circleP.pointD.x).arg(circleP.pointD.y)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointE.x).arg(circleP.pointE.y).arg(circleP.pointF.x).arg(circleP.pointF.y).arg(circleP.pointG.x).arg(circleP.pointG.y)); + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointH.x).arg(circleP.pointH.y).arg(circleP.pointI.x).arg(circleP.pointI.y).arg(circleP.pointJ.x).arg(circleP.pointJ.y)); + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// SW_Log::Get()->info(QString("====SwPenPathDraw cubicTo cx1: %1 cy: %2 cx2: %3 cy2: %4 ex:%5 ey: %6" ) +// .arg(circleP.pointK.x).arg(circleP.pointK.y).arg(circleP.pointL.x).arg(circleP.pointL.y).arg(circleP.pointM.x).arg(circleP.pointM.y)); + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + + // bufPainter.drawPath(circleBizer); +// DrawSignPath(&bufPainter,circleBizer,isEnd); + DrawSignPath(NULL,circleBizer,isEnd); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint or pLeftBottomPoint is null ,to write right."; + // SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // bezierPaths.append(pathBizer); + + // SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // bezierPaths.append(pathBizer); + } + } + + } + else + { + // qDebug() << __FUNCTION__ << " cursor != 0 PLeftIntersectPoint not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo3 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + pathBizer.quadTo(prevPoint,endPoint); + } + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + // qDebug() << __FUNCTION__ << " PLeftIntersectPoint: " << penPoint.PLeftIntersectPoint.x() << penPoint.PLeftIntersectPoint.y(); + } + } + + } + cursor ++; + + } + + } + + } + cutPointFlag = 0; + + //如果抬笔,则进行同步 + if(isEnd) + { + if(annotPath) + { + annotPath->bezierEles = bezierEles; + annotPath->bezierPaths = bezierPaths; + + annotPath->currentPathsList.clear(); + } + + +// if(m_PaintingBuf) +// m_PaintingBuf->save(QString("d:/painting_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); + } + else + { + annotPath->currentPathsList.append(bezierPaths); + } +// else // todo 非抬笔,不更新缓存 +// { +// if(annotPath) +// { +// annotPath->bezierPaths = bezierPaths; +// annotPath->bezierEles = bezierEles; +// } +// } + + return BezierPath; + +// if(isContinue) +// { +// if(m_PaintingBuf != NULL && m_BaseBuf != NULL) +// { +// *m_PaintingBuf = m_BaseBuf->copy(); +// } +// } +} + +// 进行缓存的方法(速度过快没有渲染上的) +QPainterPath SignPainterCacheThread_Linux::SwPenPathDraw(SWAnnotPath *annotPath,bool isEnd,bool flushSection) +{ + return QPainterPath(); + qDebug() << __FUNCTION__ << "===========================8888888888888888888899999999999999999999999999999999999"; + QPaintDevice* device; +// if(!flushSection) +// { +// device = PaintedDevice(); +//// qDebug() << __FUNCTION__ << "=========================================="; +// } +// else +// { +// device = PaintingDevice(); +//// qDebug() << __FUNCTION__ << "******************************************"; +// } + if(isEnd) + { + device = PaintedDevice(); + } + else + { + device = PaintingDevice(); + } +// device = PaintingDevice(); + QPainterPath BezierPath; + //todo + QPainter bufPainter(device); +// bufPainter.setBrush(Qt::black); + bufPainter.setBrush(m_PenColor); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::NonCosmeticDefaultPen | QPainter::NonCosmeticDefaultPen,true); //QPainter::Antialiasing +// bufPainter.setPen(QPen(Qt::NoPen)); + + QTransform transform; + transform.scale(m_fPixmapZoom, m_fPixmapZoom); + bufPainter.setTransform(transform); + + bufPainter.translate(-annotPath->paintRect.left(), -annotPath->paintRect.top()); + if(!annotPath) + return BezierPath; + if (annotPath->points.count() < 2) + { + return BezierPath; + } + + QList bezierPaths; //绘制的Path + QList bezierEles; //绘制 + +// annotPath->bezierPaths.clear(); +// annotPath->bezierEles.clear(); + + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int endIndex = flushSection&&!isEnd ? annotPath->points.count() - drawCount/2 : annotPath->points.count(); +// int endIndex = annotPath->points.count(); + if(flushSection) + { + endIndex = (drawCount-drawCountOffset); + qDebug() << __FUNCTION__ << " startInde: " << drawStartIndex << " endIndex: " << endIndex; + } + int startIndex = drawStartIndex; + if(isEnd) + { + startIndex = 0; + endIndex = annotPath->points.count(); + } + for (int i = startIndex ; i < endIndex; i++) + { + SWRealPoint penPoint = annotPath->points[i]; + if (GetPointValid(penPoint)) + { + /** + 判断是否为圆形贝塞尔 + */ + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + SwPenPathDrawRightWithBezier(&pathBizer, bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,SWRealPoint(),false); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,isEnd); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; +// circleBizer.lineWidth = 0.3f; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); +// bufPainter.drawPath(circleBizer); + DrawSignPath(&bufPainter,circleBizer,isEnd); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { +// pathBizer.lineWidth = 0.3f; + + rightPoints.clear(); + prevPoint = CGPointZero; +// bufPainter.drawPath(pathBizer); + if(i != startIndex) + DrawSignPath(&bufPainter,pathBizer,isEnd); + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); +// pathBizer.moveTo(penPoint.pLeftBottomPoint); +// if(i != annotPath->points.count()-1) + if(i != endIndex-1) + { + //最后一个点不进行添加 + pathBizer.moveTo(penPoint.pLeftBottomPoint); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,penPoint.pLeftBottomPoint); + } + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + +// bezierPaths.append(pathBizer); + } + else + { +// qDebug() << __FUNCTION__ << " cursor != 0 "; + rightPoints.append(penPoint); + if(/*flushSection &&*/ i == endIndex-1 && endIndex != annotPath->points.count()) + { + SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,SWRealPoint(),false); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); +// bufPainter.drawPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,isEnd); + bufPainter.setPen(QPen(Qt::green, 10, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + bufPainter.drawPoint(penPoint.realPoint); +// SWCirclePoint circleP = SWCircleMake(SWPosPointMake(penPoint.realPoint.x(), penPoint.realPoint.y(), penPoint.radius)); +// QPainterPath circleBizer; +// circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); +// AddStartPathElement(bezierEles); +// AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); +// circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); +// AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + +// circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); +// AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + +// circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); +// AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + +// circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); +// AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + +//// bufPainter.drawPath(circleBizer); +// DrawSignPath(&bufPainter,circleBizer); +// bezierPaths.append(circleBizer); +// BezierPath.addPath(circleBizer); + } + else + { + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero) ) + { + // qDebug() << __FUNCTION__ << " cursor != 0 and PLeftIntersectPoint is null"; + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint and pLeftBottomPoint is not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } + else + { + + SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd,flushSection,SWRealPoint(),false); + bezierPaths.append(pathBizer); + BezierPath.addPath(pathBizer); + // bufPainter.drawPath(pathBizer); + DrawSignPath(&bufPainter,pathBizer,isEnd); + + SWCirclePoint circleP = SWCircleMake(SWPosPointMake(penPoint.realPoint.x(), penPoint.realPoint.y(), penPoint.radius)); + QPainterPath circleBizer; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(bezierEles); + AddMoveToElement(bezierEles,ConvertToCGPoint(circleP.pointA)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + + // bufPainter.drawPath(circleBizer); + DrawSignPath(&bufPainter,circleBizer,isEnd); + bezierPaths.append(circleBizer); + BezierPath.addPath(circleBizer); + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint or pLeftBottomPoint is null ,to write right."; + // SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // bezierPaths.append(pathBizer); + + // SwPenPathDrawRightWithBezier(&pathBizer,bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // bezierPaths.append(pathBizer); + } + + } + else + { + // qDebug() << __FUNCTION__ << " cursor != 0 PLeftIntersectPoint not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + // qDebug() << __FUNCTION__ << " PLeftIntersectPoint: " << penPoint.PLeftIntersectPoint.x() << penPoint.PLeftIntersectPoint.y(); + } + } + + } + cursor ++; + + } + + } + + } + + //如果抬笔,则进行同步 + if(isEnd) + { + annotPath->bezierEles = bezierEles; + annotPath->bezierPaths = bezierPaths; + } + + return BezierPath; +} + +/** + 绘制右侧路径 + */ +void SignPainterCacheThread_Linux::SwPenPathDrawRightWithBezier(QPainterPath* bPath ,QList& elementList, + SWRealPoint prePenPoint,CGPoint prevPoint,QList rPoints,bool end, + bool isContinue,SWRealPoint lastPoint,bool isBegin) +{ + CGPoint endPoint = CGPointZero; + if (end && penType == 1) { + + endPoint = CGPointMake((prePenPoint.pLeftTopPoint.x() + prevPoint.x())/2.f, (prePenPoint.pLeftTopPoint.y() + prevPoint.y())/2.f); + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo4 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + + } else { + + endPoint = prePenPoint.pLeftTopPoint; + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo5 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + + } + prevPoint = prePenPoint.pLeftTopPoint; + for (int k = (rPoints.count() - 1); k >= 0 ; k --) + { + + SWRealPoint penPoint = rPoints.at(k); + if (GetPointValid(penPoint)) + { + if (k == (rPoints.count() - 1)) + { + + if (end && penType == 1) + { + CGPoint endPoint = CGPointMake((prevPoint.x() + penPoint.pRightTopPoint.x())/2.f, (prevPoint.y() + penPoint.pRightTopPoint.y())/2.f); + + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo6 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + SWRealPoint lastPoint = rPoints.at(k - 1); + if (!CGPointEqualToPoint(lastPoint.PRightIntersectPoint, CGPointZero)) { + + endPoint = CGPointMake((prevPoint.x() + lastPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y() + lastPoint.PRightIntersectPoint.y())/2.f); + + } + else + { + + endPoint = CGPointMake((prevPoint.x() + lastPoint.pRightBottomPoint.x())/2.f, (prevPoint.y() + lastPoint.pRightBottomPoint.y())/2.f); + } + if(prevPoint.x() != 0 && prevPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo7 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(prevPoint.x()).arg(prevPoint.y()).arg(endPoint.x()).arg(endPoint.y())); + bPath->quadTo(prevPoint,endPoint); + } + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = CGPointEqualToPoint(lastPoint.PRightIntersectPoint, CGPointZero) ? lastPoint.pRightBottomPoint : lastPoint.PRightIntersectPoint; + + k--; + /** + * 判断是否到结尾 + */ +// if (k == startIndex) { + if (k == 0) { + + //绘制开始连接点 + if(lastPoint.pRightBottomPoint.x() != 0 && lastPoint.pRightBottomPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo8 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(lastPoint.pRightBottomPoint.x()).arg(lastPoint.pRightBottomPoint.y()).arg(lastPoint.pRightBottomPoint.x()).arg(lastPoint.pRightBottomPoint.y())); + bPath->quadTo(lastPoint.pRightBottomPoint,lastPoint.pRightBottomPoint); + } + AddQuadToElement(elementList,lastPoint.pRightBottomPoint,lastPoint.pRightBottomPoint); + prevPoint = lastPoint.pRightBottomPoint; + + SWRealPoint firstPen = rPoints.first(); + if(firstPen.pRightBottomPoint.x() != 0 && firstPen.pRightBottomPoint.y() != 0) + { +// SW_Log::Get()->info(QString("====SwPenPathDraw quadTo9 cx: %1 cy: %2 ex:%3 ey: %4" ) +// .arg(firstPen.pRightBottomPoint.x()).arg(firstPen.pRightBottomPoint.y()).arg(firstPen.pLeftBottomPoint.x()).arg(firstPen.pRightBottomPoint.y())); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + } + else + { + CGPoint endPoint = penPoint.pRightTopPoint; + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + } + + } else { + + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PRightIntersectPoint, CGPointZero)) { + + if (!CGPointEqualToPoint(penPoint.pRightTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pRightBottomPoint, CGPointZero)) { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pRightBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pRightBottomPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightBottomPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pRightTopPoint.x())/2.f, (prevPoint.y()+penPoint.pRightTopPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + } + else + { + + CGPoint endPoint = CGPointMake((penPoint.pRightBottomPoint.x() + prevPoint.x())/2.f, (penPoint.pRightBottomPoint.y() + prevPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + bPath->quadTo(penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + AddQuadToElement(elementList,penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + prevPoint = penPoint.pRightBottomPoint; + //绘制开始连接点 + SWRealPoint firstPen = rPoints.first(); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + + } + + } + else + { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.PRightIntersectPoint; + if (!CGPointEqualToPoint(lastPoint.realPoint, CGPointZero) && k == 0 && isBegin == true) + { + SWRealPoint firstPen = rPoints.first(); + endPoint = CGPointMake((lastPoint.PRightIntersectPoint.x()+firstPen.PRightIntersectPoint.x())/2.f, + (lastPoint.PRightIntersectPoint.y()+firstPen.PRightIntersectPoint.y())/2.f); + bPath->quadTo(penPoint.PRightIntersectPoint,endPoint); + AddQuadToElement(elementList,penPoint.PRightIntersectPoint,endPoint); + + endPoint = CGPointMake((penPoint.PLeftIntersectPoint.x() + lastPoint.PLeftIntersectPoint.x())/2.f, + (penPoint.PLeftIntersectPoint.y() + lastPoint.PLeftIntersectPoint.y())/2.f); + bPath->quadTo(endPoint,endPoint); + } + + } + } + + } + } + +} + diff --git a/signpaintercachethread_linux.h b/signpaintercachethread_linux.h new file mode 100644 index 0000000..6155a33 --- /dev/null +++ b/signpaintercachethread_linux.h @@ -0,0 +1,127 @@ +#ifndef SIGNPAINTERCACHETHREADLINUX_H +#define SIGNPAINTERCACHETHREADLINUX_H + +#include +#include +#include +#include +#include +#include +#include "signpenstructs.h" + +class SignPainterCacheThread_Linux : public QThread +{ + Q_OBJECT +public: + SignPainterCacheThread_Linux(); + void SetPainterRect(QRect rect); + void SetCurrentPageIndex(int page){currentPageIndex = page;} + void AddPoint(QPointF currPoint,int type,float radius,double force,double maxForce); + void Paint(QPainter* painter,QRect currentVisibleRect); + void ClearDraw(); + QList GetAnnotPathLists(){return drawPaths;} + void SetStressSwitch(bool isStressSwitch) { stressSwitch = isStressSwitch; } + bool GetStressSwitch(){return stressSwitch;} + + void SetPenType(int type){penType = type;} + + void SetPenColor(QColor penColor){m_PenColor = penColor;} + +protected: + void run(); + +private: + void PaintWithPainter(QPainter* painter,QRect currentVisibleRect); + + void SwPenSectionPathDraw(QList points,SWRealPoint endRealPoint,int endFlag); + void SwPenSectionPathDrawRightWithBezier(QPainterPath* bPath ,QList& elementList,CGPoint prevPoint,QList rPoints, + SWRealPoint endRealPoint,int endFlag,bool isEnd,bool isBegin); + + + void SwPenPathDrawPoint(SWRealPoint point); + + QPainterPath SwPenPathDraw(bool isEnd,bool flushSection); + QPainterPath SwPenPathDraw(SWAnnotPath *annotPath,bool isEnd,bool flushSection); + void SwPenPathDrawRightWithBezier(QPainterPath* bPath ,QList& elementList,SWRealPoint prePenPoint, + CGPoint prevPoint,QList rPoints,bool end,bool isContinue,SWRealPoint lastPoint,bool isBegin); + + void SwPenPathDrawLeftPoint(QList points,SWRealPoint endRealPoint); + void SwPenPathDrawRightPoint(QPainterPath *bPath, QList &elementList,SWRealPoint prePenPoint, + CGPoint prevPoint, QList rPoints,SWRealPoint endRealPoint); + + void MouseMoved(const SWRealPoint& realPoint); + void MousePressd(const SWRealPoint& realPoint); + void MouseReleased(const SWRealPoint& realPoint); + + void Init(); + + QPaintDevice *PaintingDevice(); + QPaintDevice *PaintedDevice(); + + void DrawSignPath(QPainter* painter,const QPainterPath &path,bool isEnd); + +signals: + void NeedsToRefresh(QRect rect); + void ReleasedExcuted(); + +private: + QList m_RealPoints; + //原始点的互斥锁 + QMutex m_mutex; + QSemaphore m_Sem; + + float preLineRadius; + int strokeSpl; + int stressSwitch;//是否开启压感 1开启 0关闭 + float stressSpl; + + int currentPageIndex; + + qint64 previousTimestamp; + float pointSpeed; + + SWAnnotPath *curAnnotPath; + qint64 lastPaintTimestamp; + int paintFreq; + + //currentAnnot mutex + QMutex m_AnnotMutex; + + QList drawPaths; + + QImage* m_BaseBuf; + //渲染bug,基于m_BaseBuf从上一次倒数10个点开始绘制,绘制到倒数10个点时,数据保存回m_BaseBuf + QImage* m_PaintingBuf; + + QSize m_Size; + QRect m_PaintRect; + QRect m_OriRect;//新建画布原始 + int m_ScrollH; + + int drawStartIndex; + QMutex m_drawMutex; + + int drawCount; + int drawCountOffset; + + //标记上次计算贝塞尔点 + CGPoint preBezierPoint; + + bool isPressed; + float m_fPixmapZoom; + int m_fPixmaps; + + int penType;//画笔类型1软笔2签字笔 + QColor m_PenColor; + + qint64 lasttimestamp; + + int m_BufZoomWidth; + + int m_lastSectionIndex; + SWRealPoint m_lastSectionPoint; + + SWRealPoint tempPresspoint;//缓冲的按压点 +}; + +#endif // SIGNPAINTERCACHETHREADLINUX_H diff --git a/signpenpainter.cpp b/signpenpainter.cpp new file mode 100644 index 0000000..cc42b47 --- /dev/null +++ b/signpenpainter.cpp @@ -0,0 +1,1312 @@ +#include "signpenpainter.h" +#include +#include +#include +#include "signpaintercachethread.h" +#include "signpaintercachethread_linux.h" +#include "signutils.h" +//#include "sw_log.h" + +SignPenPainter::SignPenPainter() +{ +// SW_Log::Get()->info("signPenPainter: 2022-11-23 02:46"); + isUseCache = true; + isOutDebug = false; + CGPointZero = QPointF(0,0); + m_BaseBuf = NULL; + m_PaintingBuf = NULL; + SyncCount = 10; + m_ToImageIndex = 0; + +#ifdef Q_OS_WIN + cacheThread = nullptr; + cacheThread = new SignPainterCacheThread; +#else + cacheThread = nullptr; + cacheThread = new SignPainterCacheThread_Linux; +#endif +// connect(cacheThread,SIGNAL(NeedsToRefresh()),this,SIGNAL(NeedsRefresh())); + connect(cacheThread,SIGNAL(NeedsToRefresh(QRect)),this,SIGNAL(NeedsDisplay(QRect))); + connect(cacheThread,SIGNAL(ReleasedExcuted()),this,SIGNAL(ReleasedExcuted())); + cacheThread->start(); + Init(); +} + +SignPenPainter::~SignPenPainter() +{ + if(cacheThread && cacheThread->isRunning()) + { + cacheThread->terminate(); + cacheThread->wait(); + cacheThread->deleteLater(); + cacheThread = nullptr; + } +} + +void SignPenPainter::SetPainterRect(QRect rect) +{ + qDebug() << rect; + m_Size = rect.size(); + m_PaintRect = rect; +// m_PaintRect = QRect(0,0,0,0); + if(isUseCache && cacheThread) + cacheThread->SetPainterRect(rect); +} + +void SignPenPainter::SetPenType(int type) +{ + if(isUseCache && cacheThread) + cacheThread->SetPenType(type); +} + +void SignPenPainter::SetPenColor(QColor penColor) +{ + if(isUseCache && cacheThread) + cacheThread->SetPenColor(penColor); +} + +void SignPenPainter::SetCurrentPageIndex(int page) +{ + if(isUseCache && cacheThread) + cacheThread->SetCurrentPageIndex(page); +} + + +void SignPenPainter::Init() +{ + stressSpl = 0; +// penRadius = (2*2.8345)/2.f; + penRadius = 2.f; + strokeSpl = 2; + stressSwitch = 0; + pointSpeed = 10; + isRelease = false; + curAnnotPath = nullptr; + m_FreshCount = 1; +} + +void SignPenPainter::ClearDraw() +{ + curAnnotPath = nullptr; + drawPaths.clear(); + m_ToImageIndex = 0; + if(m_BaseBuf != NULL) + { + delete m_BaseBuf; + m_BaseBuf = NULL; + } + if(m_PaintingBuf != NULL) + { + delete m_PaintingBuf; + m_PaintingBuf = NULL; + } + if(cacheThread) + cacheThread->ClearDraw(); + +// emit NeedsDisplay(m_PaintRect); +} + +typedef QPainterPath CCA_Path ; +void SignPenPainter::DrawRect(QPainter* painter,QRect currentVisibleRect) +{ + if(painter == nullptr) + return; + if(isUseCache && cacheThread) + { + cacheThread->Paint(painter,currentVisibleRect); + return; + } + + if(isRelease) + { +// painter->translate(-m_PaintRect.left(), -m_PaintRect.top()); + painter->setBrush(Qt::black); +// painter->setBrush(Qt::green); + painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing +// painter->setPen(QPen(Qt::NoPen)); + painter->setPen(QPen(Qt::red, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + + QPainter bufPainter(PaintDevice()); +// bufPainter.setBrush(penColor); +// bufPainter.setBrush(Qt::green); + bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing + bufPainter.setPen(QPen(Qt::NoPen)); + //bufPainter.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); +// bufPainter.setPen(QPen(Qt::red, radius, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); + + QList m_DrawPaths = GetAnnotPathLists(); + bool isToImage = false; + for(int i = m_ToImageIndex; i< m_DrawPaths.size(); i++) + { + isToImage = true; +// isToImage = false; +// if(i == m_DrawPaths.size()-m_FreshCount) +// isToImage = true; + QList signEleList = m_DrawPaths[i]->bezierEles; +// qDebug() << __FUNCTION__ << "signEleList size" << signEleList.count(); + QPainterPath pathData; + QList paths = GetPenPathData(pathData, -1, signEleList); + for(int j = 0 ; j < paths.count(); j++) + { +// bufPainter.drawPath(paths[j]); +// painter->fillPath(paths[j],QBrush(Qt::black)); +// painter->drawPath(paths[j]); + if(isToImage) + { +// qDebug() << __FUNCTION__ << " save to image."; + paths[j].setFillRule(Qt::WindingFill); + bufPainter.drawPath(paths[j]); + bufPainter.fillPath(paths[j],QBrush(Qt::black)); + + } + } + } + if(isToImage) + { + qDebug() << __FUNCTION__ << " save to image." << m_ToImageIndex; +// m_BaseBuf->save(QString("d:/painting_%1.png").arg(QDateTime::currentMSecsSinceEpoch())); + } +// m_ToImageIndex = m_DrawPaths.size()-m_FreshCount > 0 ? m_DrawPaths.size()-m_FreshCount : 0; + m_ToImageIndex = m_DrawPaths.size() > 0 ? m_DrawPaths.size() : 0; + + if(PaintDevice() != NULL) + { + painter->drawImage(m_BaseBuf->rect(),*m_BaseBuf); + } + } + else + { + //qDebug() << __FUNCTION__ << " ========================= 1 =========================" << QDateTime::currentMSecsSinceEpoch(); +// painter->setBrush(penColor); +// painter->translate(-m_PaintRect.left(), -m_PaintRect.top()); + painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing + painter->setPen(QPen(Qt::NoPen)); + painter->setPen(QPen(Qt::black, 0.1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); +// painter->setPen(QPen(Qt::red, radius, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + // SwPenPathDraw4(painter,false); + //qDebug() << __FUNCTION__ << " ========================= 2 =========================" << QDateTime::currentMSecsSinceEpoch(); + + if( !curAnnotPath) + return; + + if(m_BaseBuf != NULL) + painter->drawImage(m_BaseBuf->rect(),*m_BaseBuf); +// painter->setPen(QPen(Qt::black, 0.5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); +// for (int i = 0; i < drawPaths.count(); i++) +// { +// SWAnnotPath* annotPath = drawPaths[i]; + SWAnnotPath* annotPath = curAnnotPath; + QPainterPath pathBizer; + QPainterPath rpathBizer; + QList signEleList = annotPath->bezierEles; + // qDebug() << __FUNCTION__ << "signEleList size" << signEleList.count(); + QPainterPath pathData; + QList paths = GetPenPathData(pathData, -1, signEleList); + for(int j = 0 ; j < paths.count(); j++) + { + paths[j].setFillRule(Qt::WindingFill); +// painter->drawPath(paths[j]); + painter->fillPath(paths[j],QBrush(Qt::black)); + } +// for(int j = 0; j < annotPath->points.count() ; j++) +// { +// SWRealPoint point = annotPath->points[j]; + +//// if (j == 0) { + +//// pathBizer.moveTo(point.pLeftBottomPoint); +//// rpathBizer.moveTo(point.pRightBottomPoint); + +//// } else { + +//// if (!CGPointEqualToPoint(point.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(point.pLeftBottomPoint, CGPointZero)) { + +//// pathBizer.lineTo(point.pLeftTopPoint); + +//// pathBizer.lineTo(point.pLeftBottomPoint); + + +//// } + +//// if (!CGPointEqualToPoint(point.pRightTopPoint, CGPointZero) && !CGPointEqualToPoint(point.pRightBottomPoint, CGPointZero)) { + +//// rpathBizer.lineTo(point.pRightTopPoint); + +//// rpathBizer.lineTo(point.pRightBottomPoint); + + +//// } +//// } +// painter->drawPoint(point.realPoint); + +// // +// // painter->drawEllipse(point.realPoint,point.radius,point.radius); + +//// painter->drawEllipse(QRectF(point.realPoint,QSize(20,20))); +// } + //painter->drawPath(pathBizer); + //painter->drawPath(rpathBizer); +// } + } +} + +void SignPenPainter::MousePressed(CGPoint currentPoint,float radius,double force,double maxForce) +{ +// radius = 2; + qDebug() << __FUNCTION__ << radius << currentPoint; + if(isUseCache && cacheThread) + { + cacheThread->AddPoint(currentPoint,1,radius,force,maxForce); + return; + } + m_StartIndex = 0; + Init(); + isRelease = false; + previousTimestamp = QDateTime::currentMSecsSinceEpoch(); + penRadius = radius; + preLineRadius = penRadius; + float newLineRadius = CalculatePointradius(0, preLineRadius, penRadius,force,maxForce,stressSpl,stressSwitch,1); + preLineRadius = newLineRadius; + + SWRealPoint rPoint; + rPoint.realPoint = currentPoint; + rPoint.radius = newLineRadius; + + SWAnnotPath *annotPath = new SWAnnotPath; + annotPath->points.append(rPoint); + annotPath->realPoints.append(rPoint); + annotPath->isShake = false; +// drawPaths.append(annotPath); + curAnnotPath = annotPath; + SWPosRest(SWPosPointMake(currentPoint.x(), currentPoint.y(), newLineRadius)); +} + +void SignPenPainter::MouseMoved(CGPoint currentPoint,float radius,double force,double maxForce) +{ +// radius = 2; +// CGPoint currentPoint(point.x() + m_PaintRect.left(),point.y()+m_PaintRect.top()); + // qDebug() << __FUNCTION__ << radius << QDateTime::currentMSecsSinceEpoch() << currentPoint; + if(isUseCache && cacheThread) + { + cacheThread->AddPoint(currentPoint,0,radius,force,maxForce); + return; + } + penRadius = radius; + /** + 判断临近相同点,并过滤 + */ + if (!CGPointEqualToPoint(currentPoint, curAnnotPath->points.last().realPoint)) { + + /** + 计算速度半径 + */ + //todo 计算速度 +// pointSpeed = [self getPointSpeedWithTouch:touch andEvent:event]; + qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch(); + float distance = GetDistanceBetweenPoint(curAnnotPath->points.last().realPoint, currentPoint); + pointSpeed = distance / ((currentTimestamp - previousTimestamp)) * 1000; + + float newLineRadius = CalculatePointradius(pointSpeed > 0 ? pointSpeed : 0, preLineRadius, penRadius,force,maxForce,stressSpl,stressSwitch,distance); + previousTimestamp = QDateTime::currentMSecsSinceEpoch(); + preLineRadius = newLineRadius; + + + SWRealPoint curPenPoint; + curPenPoint.realPoint = currentPoint; + curPenPoint.radius = newLineRadius; + curAnnotPath->realPoints.append(curPenPoint); + + /** + * 对原始点进行预贝塞尔加工处理 + */ + int realPointCount = curAnnotPath->realPoints.count(); + if (realPointCount == 2) { + + CGPoint onePoint = curAnnotPath->realPoints.at(0).realPoint; + CGPoint twoPoint = curAnnotPath->realPoints.at(1).realPoint; + CGPoint centerPoint = CGPointMake((onePoint.x()+twoPoint.x())/2.f,(onePoint.y()+twoPoint.y())/2.f); + CalculatePointcutWihtPoint(centerPoint, newLineRadius, true, false); + preBezierPoint = centerPoint; + + } else { + + CGPoint onePoint = curAnnotPath->points.last().realPoint; + CGPoint ctrPoint = curAnnotPath->realPoints.at(realPointCount - 2).realPoint; + CGPoint twoPoint = curAnnotPath->realPoints.at(realPointCount - 1).realPoint; + double t = 0.5f; + double x = pow(1 - t, 2) * onePoint.x() + 2.0 * (1 - t) * t * ctrPoint.x() + t * t * twoPoint.x(); + double y = pow(1 - t, 2) * onePoint.y() + 2.0 * (1 - t) * t * ctrPoint.y() + t * t * twoPoint.y(); + CalculatePointcutWihtPoint(CGPointMake(x,y), newLineRadius, true, false); + } + +// [self swPenPathDraw]; + SwPenPathDraw(false); + //移动过程中,只进行部分绘制 +// SwPenPathDraw2(false); + } + +} + +void SignPenPainter::MouseReleased(CGPoint currentPoint,float radius) +{ +// radius = 2; + penRadius = radius; + if(isUseCache && cacheThread) + { + cacheThread->AddPoint(currentPoint,2,radius,10,10); + return; + } + //todo 速度 +// self.pointSpeed = [self getPointSpeedWithTouch:touch andEvent:event]; + qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch(); + float distance = GetDistanceBetweenPoint(curAnnotPath->points.last().realPoint, currentPoint); +// pointSpeed = distance / ((currentTimestamp - previousTimestamp)) * 1000; + + qDebug() << __FUNCTION__ << " speed: " << pointSpeed; + int pointCount = curAnnotPath->points.count(); + if (pointSpeed >= MinSpeed && pointCount > 1) { + + int tempStrokeSpl = pointCount > strokeSpl ? strokeSpl : (pointCount - 1); + + SWRealPoint lastPenPoint = curAnnotPath->points.at(pointCount - tempStrokeSpl - 1); + lastPenPoint.PRightIntersectPoint = CGPointZero; + lastPenPoint.PLeftIntersectPoint = CGPointZero; + SWPosPoint *posAry = (SWPosPoint *)malloc(tempStrokeSpl*sizeof(SWPosPoint)); + QList pointPack; + int j = 0; + for (int k = (pointCount - tempStrokeSpl); k < pointCount; k ++) { + + SWRealPoint tempPoint = curAnnotPath->points.at(k); + tempPoint.circleCount = 0; + posAry [j] = SWPosPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y(), tempPoint.radius); + j ++; + pointPack.append(tempPoint); + + } + SWPosPoint *newposAry = CalculateStroke(posAry, (int)tempStrokeSpl,lastPenPoint.radius); +// [curAnnotPath->points removeObjectsInArray:pointPack]; + //todo 删除相同点 + int pointPackCount = pointPack.count(); + for(int i = 0 ; i < pointPackCount; i++) + { + for(int m = curAnnotPath->points.count() - 1; m >=0 ; m--) + { + if(CGPointEqualToPoint(curAnnotPath->points.at(m).realPoint,pointPack.at(i).realPoint)) + { + curAnnotPath->points.removeAt(m); + break; + } + } + } + + + for (int k = 0; k < pointPack.count(); k ++) + { + + SWPosPoint postPoint = newposAry[k]; + SWRealPoint tempPoint = pointPack[k]; + tempPoint.radius = postPoint.radius; + CalculatePointcutWihtPoint(CGPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y()), tempPoint.radius ,false,false); + } + //todo refresh +// [self swPenPathDraw]; + //从头从新绘制 + SwPenPathDraw(true); + drawPaths.append(curAnnotPath); + free( posAry); + + } else { + + if (pointCount > 1) + { + SWRealPoint prevPoint = curAnnotPath->points.at(pointCount - 2); + if (prevPoint.circleCount == 0) { + SWRealPoint tempPoint = curAnnotPath->points.at(pointCount - 1); + tempPoint.circleCount = 0; + curAnnotPath->points.removeAt(pointCount - 1); + CalculatePointcutWihtPoint(CGPointMake(tempPoint.realPoint.x(), tempPoint.realPoint.y()), tempPoint.radius,false,true); + } + + } + //todo refresh +// [self swPenPathDraw]; + SwPenPathDraw(true); + drawPaths.append(curAnnotPath); + } + emit ReleasedExcuted(); +} + +void SignPenPainter::SetStressSwitch(bool isStressSwitch) +{ + cacheThread->SetStressSwitch(isStressSwitch); +} + +bool SignPenPainter::GetStressSwitch() +{ + return cacheThread->GetStressSwitch(); +} + +QList SignPenPainter::GetAnnotPathLists() +{ +// return drawPaths; + if(isUseCache && cacheThread) + return cacheThread->GetAnnotPathLists(); + return drawPaths; +} + +//构建绘制路径,非绘图 +void SignPenPainter::SwPenPathDraw(bool isEnd) +{ + + //todo + // QPainter bufPainter(PaintDevice()); +// QPainter bufPainter(PaintingDevice()); +// bufPainter.setBrush(Qt::black); +// bufPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing +// bufPainter.setPen(QPen(Qt::NoPen)); +// bufPainter.translate(-m_PaintRect.left(), -m_PaintRect.top()); +// SWAnnotPath* annotPath = drawPaths.last(); + SWAnnotPath* annotPath = curAnnotPath; + if (annotPath->points.count() < 2) + { + return; + } + annotPath->bezierPaths.clear(); + annotPath->bezierEles.clear(); + + CGPoint prevPoint = CGPointZero; + QList rightPoints; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + prevPoint = CGPointZero; + int cursor = 0; + for (int i = 0 ; i < annotPath->points.count(); i++) + { + SWRealPoint penPoint = annotPath->points[i]; + if (GetPointValid(penPoint)) + { + + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + SwPenPathDrawRightWithBezier(&pathBizer, annotPath->bezierEles, penPoint, prevPoint, rightPoints,isEnd); + annotPath->bezierPaths.append(pathBizer); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(annotPath->bezierEles); + AddMoveToElement(annotPath->bezierEles,ConvertToCGPoint(circleP.pointA)); + + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + annotPath->bezierPaths.append(circleBizer); + } + cursor = 0; + + } else { + + if (cursor == 0) + { + rightPoints.clear(); + prevPoint = CGPointZero; + + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); + pathBizer.moveTo(penPoint.pLeftBottomPoint); + if(i != annotPath->points.count()-1) + { + //最后一个点不进行添加 + AddStartPathElement(annotPath->bezierEles); + AddMoveToElement(annotPath->bezierEles,penPoint.pLeftBottomPoint); + } + + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + + + } + else + { + + rightPoints.append(penPoint); + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero)) + { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(annotPath->bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(annotPath->bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } + else + { + SwPenPathDrawRightWithBezier(&pathBizer,annotPath->bezierEles, penPoint, prevPoint, rightPoints,isEnd); + annotPath->bezierPaths.append(pathBizer); + SWCirclePoint circleP = SWCircleMake(SWPosPointMake(penPoint.realPoint.x(), penPoint.realPoint.y(), penPoint.radius)); + QPainterPath circleBizer; + circleBizer.setFillRule(Qt::WindingFill); + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(annotPath->bezierEles); + AddMoveToElement(annotPath->bezierEles,ConvertToCGPoint(circleP.pointA)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + annotPath->bezierPaths.append(circleBizer); + + } + + } + else + { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(annotPath->bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + + } + + } + cursor++; + + } + + } + + } + +// [self setNeedsDisplay]; +// bufPainter.drawPath(pathBizer); + //如果抬笔,则进行同步 + if(isEnd) + { + SynToBaseDevice(); + isRelease = true; + } + emit NeedsDisplay(m_PaintRect); +// emit NeedsRefresh(); +} + +/** + 绘制右侧路径 + */ +void SignPenPainter::SwPenPathDrawRightWithBezier(QPainterPath* bPath ,QList& elementList, + SWRealPoint penPoint,CGPoint prevPoint, + QList rPoints,bool end) +{ + CGPoint endPoint = CGPointZero; + if (end) { + + endPoint = CGPointMake((penPoint.pLeftTopPoint.x() + prevPoint.x())/2.f, (penPoint.pLeftTopPoint.y() + prevPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + + } else { + + endPoint = penPoint.pLeftTopPoint; + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + + } + prevPoint = penPoint.pLeftTopPoint; + for (int k = (rPoints.count() - 1); k >= 0 ; k --) + { + + SWRealPoint penPoint = rPoints.at(k); + if (GetPointValid(penPoint)) + { + if (k == (rPoints.count() - 1)) + { + + if (end) + { + CGPoint endPoint = CGPointMake((prevPoint.x() + penPoint.pRightTopPoint.x())/2.f, (prevPoint.y() + penPoint.pRightTopPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + SWRealPoint lastPoint = rPoints.at(k - 1); + if (!CGPointEqualToPoint(lastPoint.PRightIntersectPoint, CGPointZero)) { + + endPoint = CGPointMake((prevPoint.x() + lastPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y() + lastPoint.PRightIntersectPoint.y())/2.f); + + } + else + { + + endPoint = CGPointMake((prevPoint.x() + lastPoint.pRightBottomPoint.x())/2.f, (prevPoint.y() + lastPoint.pRightBottomPoint.y())/2.f); + } + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = CGPointEqualToPoint(lastPoint.PRightIntersectPoint, CGPointZero) ? lastPoint.pRightBottomPoint : lastPoint.PRightIntersectPoint; + + k--; + /** + * 判断是否到结尾 + */ + if (k == 0) { + + //绘制开始连接点 + bPath->quadTo(lastPoint.pRightBottomPoint,lastPoint.pRightBottomPoint); + AddQuadToElement(elementList,lastPoint.pRightBottomPoint,lastPoint.pRightBottomPoint); + prevPoint = lastPoint.pRightBottomPoint; + + SWRealPoint firstPen = rPoints.first(); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + } + } + else + { + CGPoint endPoint = penPoint.pRightTopPoint; + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + } + + } else { + + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PRightIntersectPoint, CGPointZero)) { + + if (!CGPointEqualToPoint(penPoint.pRightTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pRightBottomPoint, CGPointZero)) { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pRightBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pRightBottomPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightBottomPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pRightTopPoint.x())/2.f, (prevPoint.y()+penPoint.pRightTopPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.pRightTopPoint; + + } + else + { + CGPoint endPoint = CGPointMake((penPoint.pRightBottomPoint.x() + prevPoint.x())/2.f, (penPoint.pRightBottomPoint.y() + prevPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + bPath->quadTo(penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + AddQuadToElement(elementList,penPoint.pRightBottomPoint,penPoint.pRightBottomPoint); + prevPoint = penPoint.pRightBottomPoint; + //绘制开始连接点 + SWRealPoint firstPen = rPoints.first(); + bPath->quadTo(firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + AddQuadToElement(elementList,firstPen.pRightBottomPoint,firstPen.pLeftBottomPoint); + + } + + } + else + { + + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PRightIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PRightIntersectPoint.y())/2.f); + bPath->quadTo(prevPoint,endPoint); + AddQuadToElement(elementList,prevPoint,endPoint); + prevPoint = penPoint.PRightIntersectPoint; + + } + } + + } + } + +} + +void SignPenPainter::CalculatePointcutWihtPoint(CGPoint point, float radius, bool stroke, bool circle) +{ + /** + 进行切点计算 + */ + SWRealPoint curPenPoint; + curPenPoint.realPoint = point; + curPenPoint.radius = radius; + curAnnotPath->points.append(curPenPoint); + int realPointCount = curAnnotPath->points.count(); + + /** + * 判断点数大于2进行 防抖处理 + */ + if (realPointCount > 3) + { + + SWRealPoint penPoint0 = curAnnotPath->points.at(realPointCount - 3); + SWRealPoint penPoint1 = curAnnotPath->points.at(realPointCount - 2); + SWRealPoint penPoint2 = curAnnotPath->points.at(realPointCount - 1); + SWPosStatus ret = CalculateShake(SWPosPointMake(penPoint0.realPoint.x(), penPoint0.realPoint.y(),penPoint0.radius), + SWPosPointMake(penPoint1.realPoint.x(), penPoint1.realPoint.y(),penPoint1.radius), + SWPosPointMake(penPoint2.realPoint.x(), penPoint2.realPoint.y(),penPoint2.radius)); + if (ret == SWPosRetSuccess) + { + if (penPoint0.circleCount != 0) + { + + penPoint0.circleCount = 0; + penPoint0.circlePoints.clear(); + } + penPoint0.pLeftBottomPoint = CGPointZero; + penPoint0.pRightBottomPoint = CGPointZero; + penPoint0.PLeftIntersectPoint = CGPointZero; + penPoint0.PRightIntersectPoint = CGPointZero; + if (curAnnotPath->isShake) + { + /** + * 判断边际值停止纠偏 + **/ + double distance = GetDistanceBetweenPoint(penPoint0.realPoint,penPoint2.realPoint); + if (distance >= 3) { + + curAnnotPath->isShake = false; + + } else { + + curAnnotPath->points.removeAt(realPointCount - 2); + } + + + } + else + { + curAnnotPath->points.removeAt(realPointCount - 2); + curAnnotPath->isShake = true; + } + + } + else + { + curAnnotPath->isShake = false; + } + } + + realPointCount = curAnnotPath->points.count(); + + if (realPointCount == 2) + { + SWRealPoint penPoint0 = curAnnotPath->points.at(0); + SWRealPoint penPoint1 = curAnnotPath->points.at(1); + SWPosRet ret = SWGetTangentcurPoint(SWPosPointMake(penPoint0.realPoint.x(), penPoint0.realPoint.y(), penPoint0.radius), + SWPosPointMake(penPoint1.realPoint.x(), penPoint1.realPoint.y(), penPoint1.radius), + SWLineMakeZero(), SWLineMakeZero(),circle ? 1 : 0); + + if (ret.status == SWPosRetSuccess) + { + + if (ret.circleCount > 0) + { + + curAnnotPath->points[0].circleCount = ret.circleCount; + curAnnotPath->points[0].circlePoints = ret.circlePoints; + + } + else + { + + curAnnotPath->points[0].pLeftBottomPoint = CGPointMake(ret.prevLeftPoint.x, ret.prevLeftPoint.y); + curAnnotPath->points[0].pRightBottomPoint = CGPointMake(ret.prevRightPoint.x, ret.prevRightPoint.y); + curAnnotPath->points[1].pLeftTopPoint = CGPointMake(ret.curLeftPoint.x, ret.curLeftPoint.y); + curAnnotPath->points[1].pRightTopPoint = CGPointMake(ret.curRightPoint.x, ret.curRightPoint.y); + } + + } + else + { + curAnnotPath->points.removeLast(); + } + + } + else if (realPointCount > 2) + { + + SWRealPoint penPoint0 = curAnnotPath->points.at(realPointCount - 3); + SWRealPoint penPoint1 = curAnnotPath->points.at(realPointCount - 2); + SWRealPoint penPoint2 = curAnnotPath->points.at(realPointCount - 1); + if (penPoint0.circleCount == 0) + { + + CGPoint penPoint0Left = CGPointEqualToPoint(penPoint0.PLeftIntersectPoint, CGPointZero) ? penPoint0.pLeftBottomPoint : penPoint0.PLeftIntersectPoint; + + CGPoint penPoint1Left = CGPointEqualToPoint(penPoint1.PLeftIntersectPoint, CGPointZero) ? penPoint1.pLeftTopPoint : penPoint1.PLeftIntersectPoint; + + CGPoint penPoint0Right = CGPointEqualToPoint(penPoint0.PRightIntersectPoint, CGPointZero) ? penPoint0.pRightBottomPoint : penPoint0.PRightIntersectPoint; + + CGPoint penPoint1Right = CGPointEqualToPoint(penPoint1.PRightIntersectPoint, CGPointZero) ? penPoint1.pRightTopPoint : penPoint1.PRightIntersectPoint; + + SWPosRet ret = SWGetTangentcurPoint(SWPosPointMake(penPoint1.realPoint.x(), penPoint1.realPoint.y(), penPoint1.radius), SWPosPointMake(penPoint2.realPoint.x(), penPoint2.realPoint.y(), penPoint2.radius), SWLineMake(penPoint0Left.x(), penPoint0Left.y(), penPoint1Left.x(), penPoint1Left.y()), SWLineMake(penPoint0Right.x(), penPoint0Right.y(), penPoint1Right.x(), penPoint1Right.y()),circle ? 1 : 0); + if (ret.status == SWPosRetSuccess ) + { + + if (ret.circleCount > 0) + { + + curAnnotPath->points[realPointCount - 2].circleCount = ret.circleCount; + curAnnotPath->points[realPointCount - 2].circlePoints = ret.circlePoints; + + } + else + { + curAnnotPath->points[realPointCount - 2].PLeftIntersectPoint = CGPointMake(ret.prevLeftIntersectPoint.x, ret.prevLeftIntersectPoint.y); + curAnnotPath->points[realPointCount - 2].PRightIntersectPoint = CGPointMake(ret.prevRightIntersectPoint.x, ret.prevRightIntersectPoint.y); + curAnnotPath->points[realPointCount - 2].pLeftBottomPoint = CGPointMake(ret.prevLeftPoint.x, ret.prevLeftPoint.y); + curAnnotPath->points[realPointCount - 2].pRightBottomPoint = CGPointMake(ret.prevRightPoint.x, ret.prevRightPoint.y); + curAnnotPath->points[realPointCount - 1].pLeftTopPoint = CGPointMake(ret.curLeftPoint.x, ret.curLeftPoint.y); + curAnnotPath->points[realPointCount - 1].pRightTopPoint = CGPointMake(ret.curRightPoint.x, ret.curRightPoint.y); + } + } + else if (ret.status == SWPosRetFail) + { + curAnnotPath->points.removeLast(); + } + + } + else + { + + SWPosRet ret = SWGetTangentcurPoint(SWPosPointMake(penPoint1.realPoint.x(), penPoint1.realPoint.y(), penPoint1.radius), SWPosPointMake(penPoint2.realPoint.x(), penPoint2.realPoint.y(), penPoint2.radius), SWLineMakeZero(), SWLineMakeZero(),circle ? 1 : 0); + if (ret.status == SWPosRetSuccess) + { + + if (ret.circleCount > 0) + { + + curAnnotPath->points[realPointCount - 2].circleCount = ret.circleCount; + curAnnotPath->points[realPointCount - 2].circlePoints = ret.circlePoints; + + } + else + { + + curAnnotPath->points[realPointCount - 2].pLeftBottomPoint = CGPointMake(ret.prevLeftPoint.x, ret.prevLeftPoint.y); + curAnnotPath->points[realPointCount - 2].pRightBottomPoint = CGPointMake(ret.prevRightPoint.x, ret.prevRightPoint.y); + curAnnotPath->points[realPointCount - 1].pLeftTopPoint = CGPointMake(ret.curLeftPoint.x, ret.curLeftPoint.y); + curAnnotPath->points[realPointCount - 1].pRightTopPoint = CGPointMake(ret.curRightPoint.x, ret.curRightPoint.y); + } + + } + else + { + + curAnnotPath->points.removeLast(); + + } + + } + + } + +} + +bool SignPenPainter::CGPointEqualToPoint(const CGPoint &point1, const CGPoint &point2) +{ + return point1.x() == point2.x() && point1.y() == point2.y(); +} + +bool SignPenPainter::GetPointValid(SWRealPoint penPoint) +{ + return true; +} + +CGPoint SignPenPainter::ConvertToCGPoint(SWPointcut cPoint) +{ + return CGPointMake(cPoint.x, cPoint.y); +} + +float SignPenPainter::GetDistanceBetweenPoint(QPointF start, QPointF end) +{ + return sqrt(pow(start.y()-end.y(), 2.0) + pow(start.x()-end.x(), 2.0)); +} + +QPaintDevice *SignPenPainter::PaintDevice() +{ + //绘制buffer + if (m_BaseBuf == NULL) + { + m_BaseBuf = new QImage(m_Size, QImage::Format_ARGB32_Premultiplied);// + m_BaseBuf->fill(Qt::transparent); + + } + else if(m_BaseBuf->size() != m_Size) + { + delete m_BaseBuf; + m_BaseBuf = NULL; + // m_Buf = new QPixmap(m_Size);//new QImage(ur.size(),QImage::Format_ARGB32);// + m_BaseBuf = new QImage(m_Size, QImage::Format_ARGB32_Premultiplied);// + m_BaseBuf->fill(Qt::transparent); + } + + return m_BaseBuf; +} + +void SignPenPainter::SynToBaseDevice() +{ + if(m_PaintingBuf != NULL && m_BaseBuf != NULL) + { + *m_BaseBuf = m_PaintingBuf->copy(); +// m_BaseBuf->save(QString("d:/painting_%1.png").arg(previousTimestamp)); + } +} + +typedef QPointF CCA_Point; +typedef QPointF CCA_GPoint; +QList SignPenPainter::GetPenPathData(QPainterPath &data, int pageIndex, QList penDataList, float factorW, float factorH, int offsetX, int offsetY) +{ + QList paths; + QPainterPath path; + QRect m_VisibleRect = m_PaintRect; +// qDebug() << __FUNCTION__ << "========================penDataList.size()=============================" << penDataList.size(); + for (int j = 0; j < penDataList.size(); j++) + { + Element element = penDataList[j]; + float x;//控制点x + float y;//控制点y + float x2; //控制点x2 + float y2; //控制点y2 + float endX;//结束点X + float endY;//结束点Y + QPointF point = element.GetEndPoint(); + + CCA_Point viewPt(point.rx()*factorW + offsetX, point.ry()*factorH + offsetY); +// IRF_PageView* pPageView = m_pDocView->GetPageViewAt(pageIndex); +// if( pPageView == NULL ) return path; + +// CCA_GPoint docPt = pPageView->DocPointFromViewPoint(viewPt); + CCA_GPoint docPt = viewPt; + float ofdX = docPt.x(); + float ofdY = docPt.y(); + + endX = ofdX; + endY = ofdY; + + QPointF controlPoint = element.GetControlPoint(); + CCA_Point controlPt(controlPoint.rx()*factorW + offsetX, controlPoint.ry()*factorH + offsetY); +// CCA_GPoint docControlPt = pPageView->DocPointFromViewPoint(controlPt); + CCA_GPoint docControlPt = controlPt; + x = docControlPt.x(); + y = docControlPt.y(); + + QPointF controlPoint2 = element.GetControlPoint2(); + CCA_Point controlPt2(controlPoint2.rx()*factorW + offsetX, controlPoint2.ry()*factorH + offsetY); +// CCA_GPoint docControlPt2 = pPageView->DocPointFromViewPoint(controlPt2); + CCA_GPoint docControlPt2 = controlPt2; + x2 = docControlPt2.x(); + y2 = docControlPt2.y(); + + QPointF tempPoint(point.x() + m_VisibleRect.left(), point.y() + m_VisibleRect.top()); + QPointF tempConPoint(controlPoint.x() + m_VisibleRect.left(), controlPoint.y() + m_VisibleRect.top()); + QPointF tempConPoint2(controlPoint2.x() + m_VisibleRect.left(), controlPoint2.y() + m_VisibleRect.top()); + + if (j == 0) + { +// data.StartFigure(docPt.x(), docPt.y()); +// qDebug() << __FUNCTION__ << " ==========StartFigure========="; + if(element.GetElementType() == MoveToElement) + { +// qDebug() << __FUNCTION__ << " MoveToElement " << tempPoint; + path.moveTo(tempPoint); + } + else if(element.GetElementType() == QuadToElement) + { +// qDebug() << __FUNCTION__ << " QuadToElement c: " << tempConPoint << " e: " << tempPoint; + path.quadTo(tempConPoint, tempPoint); + } + else if(element.GetElementType() == CurveToElement) + { +// qDebug() << __FUNCTION__ << " CurveToElement c1: " << tempConPoint << " c2: " << tempConPoint2 << " e: " << tempPoint; + path.cubicTo(tempConPoint, tempConPoint2, tempPoint); + } + } + else if(j == penDataList.size() -1) + { +// qDebug() << __FUNCTION__ << " ==========CloseFigure========="; + if(element.GetElementType() == MoveToElement) + { + data.moveTo(endX,endX); + path.moveTo(tempPoint); + } + else if(element.GetElementType() == QuadToElement) + { + data.quadTo(x, y, endX, endY); + path.quadTo(tempConPoint, tempPoint); + } + else if(element.GetElementType() == CurveToElement) + { + data.cubicTo(x, y, x2, y2, endX, endY); + path.cubicTo(tempConPoint, tempConPoint2, tempPoint); + } + // data.CloseFigure(); + paths.append(path); + } + else + { + if(element.GetElementType() == StartFigure) + { +// qDebug() << __FUNCTION__ << " ==========StartFigure========="; + paths.append(path); + path = QPainterPath(); + } + else if(element.GetElementType() == MoveToElement) + { +// qDebug() << __FUNCTION__ << " MoveToElement " << tempPoint; + data.moveTo(endX,endX); + path.moveTo(tempPoint); + } + else if(element.GetElementType() == QuadToElement) + { +// qDebug() << __FUNCTION__ << " QuadToElement c: " << tempConPoint << " e: " << tempPoint; + data.quadTo(x, y, endX, endY); + path.quadTo(tempConPoint, tempPoint); + } + else if(element.GetElementType() == CurveToElement) + { +// qDebug() << __FUNCTION__ << " CurveToElement c1: " << tempConPoint << " c2: " << tempConPoint2 << " e: " << tempPoint; + data.cubicTo(x, y, x2, y2, endX, endY); + path.cubicTo(tempConPoint, tempConPoint2, tempPoint); + } + } + + } + // data.CloseFigure(); + return paths; +} + +void SignPenPainter::SwPenPathDrawWithPainter(QPainter* bufPainter,bool isEnd) +{ + qDebug() << __FUNCTION__; + if( !curAnnotPath) + return; + //todo +// QPainter bufPainter(PaintDevice()); +// QPainter bufPainter(PaintingDevice()); + bufPainter->setBrush(Qt::black); + bufPainter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); //QPainter::Antialiasing + bufPainter->setPen(QPen(Qt::NoPen)); + bufPainter->translate(-m_PaintRect.left(), -m_PaintRect.top()); +// SWAnnotPath* annotPath = drawPaths.last(); + SWAnnotPath* annotPath = curAnnotPath; + int n = 0; + do + { +// SWAnnotPath* annotPath = curAnnotPath; + if (annotPath->points.count() < 2) + { + return; + } + // for (QPainterPath bBizer:annotPath.bezierPaths) + // { + // [bBizer removeAllPoints]; + // } + // [annotPath.bezierPaths removeAllObjects]; + annotPath->bezierPaths.clear(); + annotPath->bezierEles.clear(); + + CGPoint prevPoint = CGPointZero; + QList rightPoints; + + int cursor = 0; + QPainterPath pathBizer; + pathBizer.setFillRule(Qt::WindingFill); + int cIndex = 0; + for (int i = 0 ; i < annotPath->points.count(); i++) + { + SWRealPoint penPoint = annotPath->points[i]; + cIndex++; + // qDebug() << __FUNCTION__ << cursor; + if(i == 0 && isEnd) + int jjj = 0; + if (GetPointValid(penPoint)) + { + /** + 判断是否为圆形贝塞尔 + */ + if (penPoint.circleCount > 0) { + + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero)) { + + rightPoints.append(penPoint); + SwPenPathDrawRightWithBezier(&pathBizer, annotPath->bezierEles, penPoint, prevPoint, rightPoints,isEnd); + annotPath->bezierPaths.append(pathBizer); + + } + for (int i = 0; i < penPoint.circleCount; i ++) + { + SWCirclePoint circleP = penPoint.circlePoints[i]; + QPainterPath circleBizer; + // circleBizer.lineWidth = 0.3f; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(annotPath->bezierEles); + AddMoveToElement(annotPath->bezierEles,ConvertToCGPoint(circleP.pointA)); + + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + annotPath->bezierPaths.append(circleBizer); +// bufPainter->drawPath(circleBizer); + bufPainter->fillPath(circleBizer,QBrush(Qt::black)); + } + cursor = 0; + + } + else + { + + if (cursor == 0) + { + // pathBizer.lineWidth = 0.3f; + + rightPoints.clear(); + prevPoint = CGPointZero; + if(i != annotPath->points.count()-1) + { + //最后一个点不进行添加 +// bufPainter->drawPath(pathBizer); + bufPainter->fillPath(pathBizer,QBrush(Qt::black)); + } + pathBizer = QPainterPath(); + pathBizer.setFillRule(Qt::WindingFill); + pathBizer.moveTo(penPoint.pLeftBottomPoint); + if(i != annotPath->points.count()-1) + { + //最后一个点不进行添加 + AddStartPathElement(annotPath->bezierEles); + AddMoveToElement(annotPath->bezierEles,penPoint.pLeftBottomPoint); + } + prevPoint = penPoint.pLeftBottomPoint; + rightPoints.append(penPoint); + + // annotPath->bezierPaths.append(pathBizer); + } + else + { + // qDebug() << __FUNCTION__ << " cursor != 0 "; + rightPoints.append(penPoint); + //判断交点是否有效 + if (CGPointEqualToPoint(penPoint.PLeftIntersectPoint, CGPointZero)) + { + // qDebug() << __FUNCTION__ << " cursor != 0 and PLeftIntersectPoint is null"; + if (!CGPointEqualToPoint(penPoint.pLeftTopPoint, CGPointZero) && !CGPointEqualToPoint(penPoint.pLeftBottomPoint, CGPointZero)) { + + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint and pLeftBottomPoint is not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftTopPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftTopPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(annotPath->bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftTopPoint; + + endPoint = CGPointMake((prevPoint.x()+penPoint.pLeftBottomPoint.x())/2.f, (prevPoint.y()+penPoint.pLeftBottomPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(annotPath->bezierEles,prevPoint,endPoint); + prevPoint = penPoint.pLeftBottomPoint; + + } + else + { + + SwPenPathDrawRightWithBezier(&pathBizer,annotPath->bezierEles, penPoint, prevPoint, rightPoints,isEnd); + annotPath->bezierPaths.append(pathBizer); +// bufPainter->drawPath(pathBizer); + bufPainter->fillPath(pathBizer,QBrush(Qt::black)); + + SWCirclePoint circleP = SWCircleMake(SWPosPointMake(penPoint.realPoint.x(), penPoint.realPoint.y(), penPoint.radius)); + QPainterPath circleBizer; + circleBizer.moveTo(ConvertToCGPoint(circleP.pointA)); + AddStartPathElement(annotPath->bezierEles); + AddMoveToElement(annotPath->bezierEles,ConvertToCGPoint(circleP.pointA)); + circleBizer.cubicTo(circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointB.x,circleP.pointB.y, circleP.pointC.x,circleP.pointC.y,circleP.pointD.x,circleP.pointD.y); + + circleBizer.cubicTo(circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointE.x,circleP.pointE.y, circleP.pointF.x,circleP.pointF.y,circleP.pointG.x,circleP.pointG.y); + + circleBizer.cubicTo(circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointH.x,circleP.pointH.y, circleP.pointI.x,circleP.pointI.y,circleP.pointJ.x,circleP.pointJ.y); + + circleBizer.cubicTo(circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + AddCurveToElement(annotPath->bezierEles,circleP.pointK.x,circleP.pointK.y, circleP.pointL.x,circleP.pointL.y,circleP.pointM.x,circleP.pointM.y); + +// bufPainter->drawPath(circleBizer); + bufPainter->fillPath(circleBizer,QBrush(Qt::black)); + annotPath->bezierPaths.append(circleBizer); + // qDebug() << __FUNCTION__ << " cursor != 0 and pLeftTopPoint or pLeftBottomPoint is null ,to write right."; + // SwPenPathDrawRightWithBezier(&pathBizer,annotPath->bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // annotPath->bezierPaths.append(pathBizer); + + // SwPenPathDrawRightWithBezier(&pathBizer,annotPath->bezierEles, penPoint, prevPoint, rightPoints,isEnd); + // annotPath->bezierPaths.append(pathBizer); + } + + } + else + { + // qDebug() << __FUNCTION__ << " cursor != 0 PLeftIntersectPoint not null"; + CGPoint endPoint = CGPointMake((prevPoint.x()+penPoint.PLeftIntersectPoint.x())/2.f, (prevPoint.y()+penPoint.PLeftIntersectPoint.y())/2.f); + pathBizer.quadTo(prevPoint,endPoint); + AddQuadToElement(annotPath->bezierEles,prevPoint,endPoint); + prevPoint = penPoint.PLeftIntersectPoint; + // qDebug() << __FUNCTION__ << " PLeftIntersectPoint: " << penPoint.PLeftIntersectPoint.x() << penPoint.PLeftIntersectPoint.y(); + } + + } + cursor ++; + + } + + } + + } +// bufPainter->drawPath(pathBizer); + bufPainter->fillPath(pathBizer,QBrush(Qt::black)); + + if(drawPaths.count() > n) + { + annotPath = drawPaths[n]; + } + n++; +// }while(n <= drawPaths.count()); + }while(false); + //如果抬笔,则进行同步 +// if(isEnd) +// { +// SynToBaseDevice(); +// isRelease = true; +// } +// emit NeedsDisplay(); +} diff --git a/signpenpainter.h b/signpenpainter.h new file mode 100644 index 0000000..e5882de --- /dev/null +++ b/signpenpainter.h @@ -0,0 +1,108 @@ +#ifndef SIGNPENPAINTER_H +#define SIGNPENPAINTER_H + +#include +#include +#include +#include "SWPosPointcut.h" +#include "signpenstructs.h" + +#define MaxBrushCount 2 +#define MinSpeed 300 +#define MaxSpeed 400 +#define MaxBrush 0.2f + +class SignPainterCacheThread; +class SignPainterCacheThread_Linux; +class QPainter; + +class SignPenPainter : public QObject +{ + Q_OBJECT +public: + SignPenPainter(); + ~SignPenPainter(); + void SetPainterRect(QRect rect); + void SetPenType(int type); + void SetPenColor(QColor penColor); + void SetCurrentPageIndex(int page); + void SetOffSetRect(QRect rect); + void Init(); + void ClearDraw(); + void DrawRect(QPainter* painter,QRect currentVisibleRect); + void MousePressed(CGPoint currentPoint,float radius,double force,double maxForce);//force 压感力度 + void MouseMoved(CGPoint currentPoint,float radius,double force,double maxForce); + void MouseReleased(CGPoint currentPoint,float radius); + void SetUseCache(bool use){ isUseCache = use;} + bool GetUseCache(){return isUseCache;} + void SetUseDebug(bool use){ isOutDebug = use;} + bool GetUseDebug(){return isOutDebug;} + void SetStressSwitch(bool isStressSwitch); + bool GetStressSwitch();//是否使用压感设备 + + QList GetAnnotPathLists(); + +QList GetPenPathData(QPainterPath &data, int pageIndex, QList penDataList, float factorW = 1.0, float factorH = 1.0, int offsetX = 0, int offsetY = 0); +private: + void SwPenPathDrawWithPainter(QPainter* bufPainter,bool isEnd); + void SwPenPathDraw(bool isEnd); + void SwPenPathDrawRightWithBezier(QPainterPath* bPath ,QList& elementList,SWRealPoint penPoint,CGPoint prevPoint,QList rPoints,bool end); + bool CGPointEqualToPoint(const CGPoint &point1, const CGPoint &point2); + void CalculatePointcutWihtPoint(CGPoint point, float radius, bool stroke, bool circle); + bool GetPointValid(SWRealPoint penPoint); + CGPoint ConvertToCGPoint(SWPointcut cPoint); + float GetDistanceBetweenPoint(QPointF start, QPointF end); + + QPaintDevice *PaintDevice(); + + void SynToBaseDevice(); + + +signals: + void NeedsDisplay(QRect rect); + void NeedsRefresh(); + void ReleasedExcuted(); + + //记录日志 + void log(QString); +private: + QPointF CGPointZero; + + int strokeSpl; + float stressSpl; + float penRadius; + SWAnnotPath *curAnnotPath; + + QList drawPaths; + CGPoint selectPoint; + //标记上次计算贝塞尔点 + CGPoint preBezierPoint; + qint64 previousTimestamp; + float pointSpeed; + float preLineRadius; + + int stressSwitch;//是否开启压感 1开启 0关闭 + + QImage* m_BaseBuf; + //渲染bug,基于m_BaseBuf从上一次倒数10个点开始绘制,绘制到倒数10个点时,数据保存回m_BaseBuf + QImage* m_PaintingBuf; + QSize m_Size; + QRect m_PaintRect; + + int m_StartIndex;//渲染开始的节点 + int SyncCount;// 重新绘制的数据 + + bool isRelease; + int m_ToImageIndex;//图片后的开始渲染点 + int m_FreshCount;//实时渲染的笔画数 + +#ifdef Q_OS_WIN + SignPainterCacheThread* cacheThread; +#else + SignPainterCacheThread_Linux* cacheThread; +#endif + bool isUseCache; + bool isOutDebug; +}; + +#endif // SIGNPENPAINTER_H diff --git a/signpenstructs.h b/signpenstructs.h new file mode 100644 index 0000000..32d2793 --- /dev/null +++ b/signpenstructs.h @@ -0,0 +1,122 @@ +#ifndef SIGNPENSTRUCTS_H +#define SIGNPENSTRUCTS_H +#include +#include +#include +#include "SWPosPointcut.h" + +typedef QPointF CGPointMake ; +typedef QPointF CGPoint; + +struct SWRealPoint +{ + CGPoint realPoint; // 原始点 + int pointType;//0 moved 1 press 2 releas + double force; + double maxForce; + + qint64 timestamp;//当前点的时间戳 + + float radius; + float finalRadius; + + CGPoint pLeftTopPoint; + CGPoint pLeftBottomPoint; + CGPoint PLeftIntersectPoint; + CGPoint pRightTopPoint; + CGPoint pRightBottomPoint; + CGPoint PRightIntersectPoint; + +// SWCirclePoint *circlePoints; + QList circlePoints; + int circleCount; + SWRealPoint() + { + timestamp = -1; + circleCount = 0; + pointType = 2; + force = 10; + maxForce = 10; + radius = 3; + } +}; + +enum ElementType { + StartFigure, + MoveToElement, + LineToElement, + CurveToElement, + QuadToElement +}; + +class Element { +public: + Element(ElementType type){ + this->type = type; + point = QPointF(0,0); + control = QPointF(0,0);//CurveToElement时的控制点 point为结束点 + control2 = QPointF(0,0);} + ~Element(){} + ElementType GetElementType(){return type;} + + void AddEndPoint(QPointF point){ + this->point = point; + x = point.x(); + y = point.y(); + } + //二阶贝塞尔控制点,三阶贝塞尔控制点1, 非CurveToElement和QuadToElement时,此点为空 + void AddControlPoint(QPointF point){control = point;} + //三阶贝塞尔控制点2,非QuadToElement时,此点为空 + void AddControlPoint2(QPointF point){control2 = point;} + + QPointF GetEndPoint(){return point;} + QPointF GetControlPoint(){return (type == CurveToElement || type == QuadToElement) ? control : QPointF(0,0);} + QPointF GetControlPoint2(){return (type == CurveToElement) ? control2 : QPointF(0,0);} + + + bool IsMoveTo() const { return type == MoveToElement; } + bool IsLineTo() const { return type == LineToElement; } + bool IsCurveTo() const { return type == CurveToElement; } + bool IsQuadTo() const { return type == QuadToElement; } + + operator QPointF () const { return point; } + + bool operator==(const Element &e) const { return qFuzzyCompare(x, e.x) + && qFuzzyCompare(y, e.y) && type == e.type; } + inline bool operator!=(const Element &e) const { return !operator==(e); } + + ElementType type; + QPointF point; + QPointF control;//CurveToElement时的控制点 point为结束点 + QPointF control2; +private: + qreal x; + qreal y; +// ElementType type; +// QPointF point; +// QPointF control;//CurveToElement时的控制点 point为结束点 +// QPointF control2; +}; + +// 一笔的Path数据(抬笔前) +struct SWAnnotPath +{ + QList points; + QList realPoints; + QList bezierPaths; //绘制的Path + QList > currentPathsList; + QList bezierEles; //绘制 + bool isShake; //是否防抖 + int pageIndex; + bool isEnd; + bool isPainted;//是否已经缓冲绘制 + QRect paintRect;//手写时的区域 + SWAnnotPath() + { + isShake = false; + isEnd = false; + isPainted = false; + } +}; + +#endif // SIGNPENSTRUCTS_H diff --git a/signutils.cpp b/signutils.cpp new file mode 100644 index 0000000..777b93a --- /dev/null +++ b/signutils.cpp @@ -0,0 +1,253 @@ +#include "signutils.h" +#include +#include "sw_log.h" + +QPointF CGPointZero = QPointF(0,0); + +void CalculatePointcutWihtPoint(SWAnnotPath *curAnnotPath,CGPoint point, float radius, bool stroke, bool circle,qint64 ts) +{ + /** + 进行切点计算 + */ + SWRealPoint curPenPoint; + curPenPoint.realPoint = point; + curPenPoint.radius = radius; + curPenPoint.timestamp = ts; + curAnnotPath->points.append(curPenPoint); + int realPointCount = curAnnotPath->points.count(); + + /** + * 判断点数大于2进行 防抖处理 + */ + if (realPointCount > 3) + { + + SWRealPoint penPoint0 = curAnnotPath->points.at(realPointCount - 3); + SWRealPoint penPoint1 = curAnnotPath->points.at(realPointCount - 2); + SWRealPoint penPoint2 = curAnnotPath->points.at(realPointCount - 1); + SWPosStatus ret = CalculateShake(SWPosPointMake(penPoint0.realPoint.x(), penPoint0.realPoint.y(),penPoint0.radius), + SWPosPointMake(penPoint1.realPoint.x(), penPoint1.realPoint.y(),penPoint1.radius), + SWPosPointMake(penPoint2.realPoint.x(), penPoint2.realPoint.y(),penPoint2.radius)); + if (ret == SWPosRetSuccess) + { + if (penPoint0.circleCount != 0) + { + + penPoint0.circleCount = 0; + penPoint0.circlePoints.clear(); + } + penPoint0.pLeftBottomPoint = CGPointZero; + penPoint0.pRightBottomPoint = CGPointZero; + penPoint0.PLeftIntersectPoint = CGPointZero; + penPoint0.PRightIntersectPoint = CGPointZero; + if (curAnnotPath->isShake) + { + /** + * 判断边际值停止纠偏 + **/ + double distance = GetDistanceBetweenPoint(penPoint0.realPoint,penPoint2.realPoint); + if (distance >= 3) { + + curAnnotPath->isShake = false; + + } else { + + curAnnotPath->points.removeAt(realPointCount - 2); + } + + + } + else + { + curAnnotPath->points.removeAt(realPointCount - 2); + curAnnotPath->isShake = true; + } + + } + else + { + curAnnotPath->isShake = false; + } + } + + realPointCount = curAnnotPath->points.count(); + + if (realPointCount == 2) + { + SWRealPoint penPoint0 = curAnnotPath->points.at(0); + SWRealPoint penPoint1 = curAnnotPath->points.at(1); + SWPosRet ret = SWGetTangentcurPoint(SWPosPointMake(penPoint0.realPoint.x(), penPoint0.realPoint.y(), penPoint0.radius), + SWPosPointMake(penPoint1.realPoint.x(), penPoint1.realPoint.y(), penPoint1.radius), + SWLineMakeZero(), SWLineMakeZero(),circle ? 1 : 0); + + if (ret.status == SWPosRetSuccess) + { + + if (ret.circleCount > 0) + { + + curAnnotPath->points[0].circleCount = ret.circleCount; + curAnnotPath->points[0].circlePoints = ret.circlePoints; + + } + else + { + + curAnnotPath->points[0].pLeftBottomPoint = CGPointMake(ret.prevLeftPoint.x, ret.prevLeftPoint.y); + curAnnotPath->points[0].pRightBottomPoint = CGPointMake(ret.prevRightPoint.x, ret.prevRightPoint.y); + curAnnotPath->points[1].pLeftTopPoint = CGPointMake(ret.curLeftPoint.x, ret.curLeftPoint.y); + curAnnotPath->points[1].pRightTopPoint = CGPointMake(ret.curRightPoint.x, ret.curRightPoint.y); + } + + } + else + { + curAnnotPath->points.removeLast(); + } + + } + else if (realPointCount > 2) + { + + SWRealPoint penPoint0 = curAnnotPath->points.at(realPointCount - 3); + SWRealPoint penPoint1 = curAnnotPath->points.at(realPointCount - 2); + SWRealPoint penPoint2 = curAnnotPath->points.at(realPointCount - 1); + if (penPoint0.circleCount == 0) + { + + CGPoint penPoint0Left = CGPointEqualToPoint(penPoint0.PLeftIntersectPoint, CGPointZero) ? penPoint0.pLeftBottomPoint : penPoint0.PLeftIntersectPoint; + + CGPoint penPoint1Left = CGPointEqualToPoint(penPoint1.PLeftIntersectPoint, CGPointZero) ? penPoint1.pLeftTopPoint : penPoint1.PLeftIntersectPoint; + + CGPoint penPoint0Right = CGPointEqualToPoint(penPoint0.PRightIntersectPoint, CGPointZero) ? penPoint0.pRightBottomPoint : penPoint0.PRightIntersectPoint; + + CGPoint penPoint1Right = CGPointEqualToPoint(penPoint1.PRightIntersectPoint, CGPointZero) ? penPoint1.pRightTopPoint : penPoint1.PRightIntersectPoint; + + SWPosRet ret = SWGetTangentcurPoint(SWPosPointMake(penPoint1.realPoint.x(), penPoint1.realPoint.y(), penPoint1.radius), SWPosPointMake(penPoint2.realPoint.x(), penPoint2.realPoint.y(), penPoint2.radius), SWLineMake(penPoint0Left.x(), penPoint0Left.y(), penPoint1Left.x(), penPoint1Left.y()), SWLineMake(penPoint0Right.x(), penPoint0Right.y(), penPoint1Right.x(), penPoint1Right.y()),circle ? 1 : 0); + if (ret.status == SWPosRetSuccess ) + { + + if (ret.circleCount > 0) + { + + curAnnotPath->points[realPointCount - 2].circleCount = ret.circleCount; + curAnnotPath->points[realPointCount - 2].circlePoints = ret.circlePoints; + + } + else + { + curAnnotPath->points[realPointCount - 2].PLeftIntersectPoint = CGPointMake(ret.prevLeftIntersectPoint.x, ret.prevLeftIntersectPoint.y); + curAnnotPath->points[realPointCount - 2].PRightIntersectPoint = CGPointMake(ret.prevRightIntersectPoint.x, ret.prevRightIntersectPoint.y); + curAnnotPath->points[realPointCount - 2].pLeftBottomPoint = CGPointMake(ret.prevLeftPoint.x, ret.prevLeftPoint.y); + curAnnotPath->points[realPointCount - 2].pRightBottomPoint = CGPointMake(ret.prevRightPoint.x, ret.prevRightPoint.y); + curAnnotPath->points[realPointCount - 1].pLeftTopPoint = CGPointMake(ret.curLeftPoint.x, ret.curLeftPoint.y); + curAnnotPath->points[realPointCount - 1].pRightTopPoint = CGPointMake(ret.curRightPoint.x, ret.curRightPoint.y); + } + } + else if (ret.status == SWPosRetFail) + { + curAnnotPath->points.removeLast(); + } + + } + else + { + + SWPosRet ret = SWGetTangentcurPoint(SWPosPointMake(penPoint1.realPoint.x(), penPoint1.realPoint.y(), penPoint1.radius), SWPosPointMake(penPoint2.realPoint.x(), penPoint2.realPoint.y(), penPoint2.radius), SWLineMakeZero(), SWLineMakeZero(),circle ? 1 : 0); + if (ret.status == SWPosRetSuccess) + { + + if (ret.circleCount > 0) + { + + curAnnotPath->points[realPointCount - 2].circleCount = ret.circleCount; + curAnnotPath->points[realPointCount - 2].circlePoints = ret.circlePoints; + + } + else + { + + curAnnotPath->points[realPointCount - 2].pLeftBottomPoint = CGPointMake(ret.prevLeftPoint.x, ret.prevLeftPoint.y); + curAnnotPath->points[realPointCount - 2].pRightBottomPoint = CGPointMake(ret.prevRightPoint.x, ret.prevRightPoint.y); + curAnnotPath->points[realPointCount - 1].pLeftTopPoint = CGPointMake(ret.curLeftPoint.x, ret.curLeftPoint.y); + curAnnotPath->points[realPointCount - 1].pRightTopPoint = CGPointMake(ret.curRightPoint.x, ret.curRightPoint.y); + } + + } + else + { + + curAnnotPath->points.removeLast(); + + } + + } + + } + +} + +float GetDistanceBetweenPoint(QPointF start, QPointF end) +{ + return sqrt(pow(start.y()-end.y(), 2.0) + pow(start.x()-end.x(), 2.0)); +} + + +bool CGPointEqualToPoint(const CGPoint &point1, const CGPoint &point2) +{ + return point1.x() == point2.x() && point1.y() == point2.y(); +} + +bool GetPointValid(SWRealPoint penPoint) +{ + return true; +} + +CGPoint ConvertToCGPoint(SWPointcut cPoint) +{ + return CGPointMake(cPoint.x, cPoint.y); +} + +void AddStartPathElement(QList &elementList) +{ + Element ele(StartFigure); + elementList.append(ele); +} + +void AddMoveToElement(QList &elementList, QPointF point) +{ +// qDebug() << __FUNCTION__ << point; +// SW_Log::Get()->info(QString("====AddMoveToElement x: %1 y: %2====").arg(point.x()).arg(point.y())); + + Element ele(MoveToElement); + ele.AddEndPoint(point); + elementList.append(ele); +} + +void AddCurveToElement(QList &elementList, QPointF control, QPointF control2, QPointF end) +{ +// SW_Log::Get()->info(QString("====AddCurveToElement cx: %1 cy: %2 c2x: %3 c2y: %4 ex: %5 ey: %6====") +// .arg(control.x()).arg(control.y()).arg(control2.x()).arg(control2.y()).arg(end.x()).arg(end.y())); + Element ele(CurveToElement); + ele.AddEndPoint(end); + ele.AddControlPoint(control); + ele.AddControlPoint2(control2); + elementList.append(ele); +} + +void AddCurveToElement(QList &elementList, qreal ctrlPt1x, qreal ctrlPt1y, qreal ctrlPt2x, qreal ctrlPt2y, qreal endPtx, qreal endPty) +{ +// SW_Log::Get()->info(QString("====AddCurveToElement cx: %1 cy: %2 c2x: %3 c2y: %4 ex: %5 ey: %6====") +// .arg(ctrlPt1x).arg(ctrlPt1y).arg(ctrlPt2x).arg(ctrlPt2y).arg(endPtx).arg(endPty)); + AddCurveToElement(elementList,QPointF(ctrlPt1x,ctrlPt1y),QPointF(ctrlPt2x,ctrlPt2y),QPointF(endPtx,endPty)); +} + +void AddQuadToElement(QList &elementList, QPointF control, QPointF end) +{ +// SW_Log::Get()->info(QString("====AddQuadToElement cx: %1 cy: %2 ex: %5 ey: %6====") +// .arg(control.x()).arg(control.y()).arg(end.x()).arg(end.y())); + Element ele(QuadToElement); + ele.AddEndPoint(end); + ele.AddControlPoint(control); + elementList.append(ele); +} diff --git a/signutils.h b/signutils.h new file mode 100644 index 0000000..e26e23e --- /dev/null +++ b/signutils.h @@ -0,0 +1,18 @@ +#ifndef SIGNUTILS_H +#define SIGNUTILS_H +#include "signpenstructs.h" + +extern QPointF CGPointZero; +extern bool CGPointEqualToPoint(const CGPoint &point1, const CGPoint &point2); +extern void CalculatePointcutWihtPoint(SWAnnotPath *curAnnotPath,CGPoint point, float radius, bool stroke, bool circle,qint64 ts); +extern bool GetPointValid(SWRealPoint penPoint); +extern CGPoint ConvertToCGPoint(SWPointcut cPoint); +extern float GetDistanceBetweenPoint(QPointF start, QPointF end); + +extern void AddStartPathElement(QList& elementList); +extern void AddMoveToElement(QList& elementList,QPointF point); +extern void AddCurveToElement(QList& elementList,QPointF control,QPointF control2,QPointF end); +extern void AddCurveToElement(QList& elementList,qreal ctrlPt1x, qreal ctrlPt1y, qreal ctrlPt2x, qreal ctrlPt2y, + qreal endPtx, qreal endPty); +extern void AddQuadToElement(QList& elementList,QPointF control,QPointF end); +#endif // SIGNUTILS_H diff --git a/sw_log.cpp b/sw_log.cpp new file mode 100644 index 0000000..b488f44 --- /dev/null +++ b/sw_log.cpp @@ -0,0 +1,114 @@ +#include "sw_log.h" +#include + +static SW_Log *m_pLogInstance = NULL; +QString SW_Log::m_appInfo = ""; + +void SW_Log::Create(const QString& appPath,const QString appInfo) +{ + m_appInfo = appInfo; + if(m_pLogInstance == NULL) + { + m_pLogInstance = new SW_Log; + } +} + +SW_Log* SW_Log::Get() +{ + if(m_pLogInstance == NULL) + { + m_pLogInstance = new SW_Log; + } + return m_pLogInstance; +} + +void SW_Log::Destroy() +{ + SW_Log::Get()->warning("SW_Log::Destroy"); + if (m_pLogInstance) + { + delete m_pLogInstance; + m_pLogInstance = NULL; + } +} + +void SW_Log::error(const char *message) +{ +// log4cpp::Category& root = log4cpp::Category::getRoot(); +// root.error(message); + qDebug() << message; +} + +void SW_Log::error(const QString &message) +{ +// log4cpp::Category& root = log4cpp::Category::getRoot(); +// root.error(message.toStdString()); + qDebug() << message; +} + +void SW_Log::warning(const char *message) +{ +// log4cpp::Category& root = log4cpp::Category::getRoot(); +// root.warn(message); + qDebug() << message; +} + +void SW_Log::warning(const QString &message) +{ +// log4cpp::Category& root = log4cpp::Category::getRoot(); +// root.warn(message.toStdString()); + qDebug() << message; +} + +void SW_Log::debug(const char *message) +{ +// log4cpp::Category& root = log4cpp::Category::getRoot(); +// root.debug(message); + qDebug() << message; +} + +void SW_Log::debug(const QString &message) +{ +// log4cpp::Category& root = log4cpp::Category::getRoot(); +// root.debug(message.toStdString()); + qDebug() << message; +} + +void SW_Log::info(const char *message) +{ +// log4cpp::Category& root = log4cpp::Category::getRoot(); +// root.info(message); + qDebug() << message; +} + +void SW_Log::info(const QString &message) +{ +// log4cpp::Category& root = log4cpp::Category::getRoot(); +// root.info(message.toStdString()); + qDebug() << message; +} + +QString SW_Log::GetUserDir() +{ + return m_userDir; +} + +QString SW_Log::GetConfFile() +{ + return m_confFile; +} + +QString SW_Log::GetEnvUserDir() +{ + return m_envUserDir; +} + +SW_Log::SW_Log() +{ + +} + +SW_Log::~SW_Log() +{ +// log4cpp::Category::shutdown(); +} diff --git a/sw_log.h b/sw_log.h new file mode 100644 index 0000000..157447b --- /dev/null +++ b/sw_log.h @@ -0,0 +1,36 @@ +#ifndef SW_LOG_H +#define SW_LOG_H + +#include +#include + +class SW_Log +{ +public: + static void Create(const QString& appPath,const QString appInfo=""); + static SW_Log* Get(); + static void Destroy(); + + void error(const char *message); + void error(const QString &message); + void warning(const char *message); + void warning(const QString &message); + void debug(const char *message); + void debug(const QString &message); + void info(const char *message); + void info(const QString &message); + + QString GetUserDir(); + QString GetConfFile(); + QString GetEnvUserDir(); + +protected: + SW_Log(); + ~SW_Log(); +private: + static QString m_appInfo; + QString m_userDir; + QString m_envUserDir; + QString m_confFile; +}; +#endif // SW_LOG_H diff --git a/wintab/Utils.cpp b/wintab/Utils.cpp new file mode 100644 index 0000000..2672f63 --- /dev/null +++ b/wintab/Utils.cpp @@ -0,0 +1,171 @@ +/*---------------------------------------------------------------------------- + + NAME + Utils.c + + PURPOSE + Some general-purpose functions for the WinTab demos. + + COPYRIGHT + Copyright (c) Wacom Company, Ltd. 2014 All Rights Reserved + All rights reserved. + + The text and information contained in this file may be freely used, + copied, or distributed without compensation or licensing restrictions. + +---------------------------------------------------------------------------- */ +#include "Utils.h" + +#ifdef WACOM_DEBUG + +void WacomTrace( char *lpszFormat, ...); + +#define WACOM_ASSERT( x ) assert( x ) +#define WACOM_TRACE(...) WacomTrace(__VA_ARGS__) +#else +#define WACOM_TRACE(...) +#define WACOM_ASSERT( x ) + +#endif // WACOM_DEBUG + +////////////////////////////////////////////////////////////////////////////// +HINSTANCE ghWintab = NULL; +WTINFOA gpWTInfoA = NULL; +WTINFOW gpWTInfoW = NULL; +WTOPENW gpWTOpenW = NULL; +WTGETW gpWTGetW = NULL; +WTSETW gpWTSetW = NULL; +WTCLOSE gpWTClose = NULL; +WTPACKET gpWTPacket = NULL; +WTENABLE gpWTEnable = NULL; +WTOVERLAP gpWTOverlap = NULL; +WTSAVE gpWTSave = NULL; +WTCONFIG gpWTConfig = NULL; +WTRESTORE gpWTRestore = NULL; +WTEXTSET gpWTExtSet = NULL; +WTEXTGET gpWTExtGet = NULL; +WTQUEUESIZESET gpWTQueueSizeSet = NULL; +WTQUEUESIZEGET gpWTQueueSizeGet = NULL; +WTDATAPEEK gpWTDataPeek = NULL; +WTPACKETSGET gpWTPacketsGet = NULL; + +// TODO - add more wintab32 function pointers as needed + +char* pszProgramName = NULL; + +#define GETPROCADDRESS(type, func) \ + gp##func = (type)GetProcAddress(ghWintab, #func); \ + if (!gp##func){ WACOM_ASSERT(FALSE); UnloadWintab(); return FALSE; } + +////////////////////////////////////////////////////////////////////////////// +// Purpose +// Find wintab32.dll and load it. +// Find the exported functions we need from it. +// +// Returns +// TRUE on success. +// FALSE on failure. +// +BOOL LoadWintab( void ) +{ + ghWintab = LoadLibraryW( L"Wintab32.dll" ); + if ( !ghWintab ) + { + DWORD err = GetLastError(); + //WACOM_TRACE("LoadLibrary error: %i\n", err); + OutputDebugStringA("Could not load Wintab32.dll"); + return FALSE; + } + + // Explicitly find the exported Wintab functions in which we are interested. + // We are using the ASCII, not unicode versions (where applicable). + GETPROCADDRESS( WTOPENW, WTOpenW ); + GETPROCADDRESS( WTINFOW, WTInfoW ); + GETPROCADDRESS(WTINFOA, WTInfoA); + GETPROCADDRESS( WTGETW, WTGetW ); + GETPROCADDRESS( WTSETW, WTSetW ); + GETPROCADDRESS( WTPACKET, WTPacket ); + GETPROCADDRESS( WTCLOSE, WTClose ); + GETPROCADDRESS( WTENABLE, WTEnable ); + GETPROCADDRESS( WTOVERLAP, WTOverlap ); + GETPROCADDRESS( WTSAVE, WTSave ); + GETPROCADDRESS( WTCONFIG, WTConfig ); + GETPROCADDRESS( WTRESTORE, WTRestore ); + GETPROCADDRESS( WTEXTSET, WTExtSet ); + GETPROCADDRESS( WTEXTGET, WTExtGet ); + GETPROCADDRESS( WTQUEUESIZESET, WTQueueSizeSet ); + GETPROCADDRESS(WTQUEUESIZEGET, WTQueueSizeGet); + GETPROCADDRESS( WTDATAPEEK, WTDataPeek ); + GETPROCADDRESS( WTPACKETSGET, WTPacketsGet ); + + + // TODO - don't forget to NULL out pointers in UnloadWintab(). + return TRUE; +} + + + +////////////////////////////////////////////////////////////////////////////// +// Purpose +// Uninitializes use of wintab32.dll +// +// Returns +// Nothing. +// +void UnloadWintab( void ) +{ + //WACOM_TRACE( "UnloadWintab()\n" ); + + if ( ghWintab ) + { + FreeLibrary( ghWintab ); + ghWintab = NULL; + } + + gpWTOpenW = NULL; + gpWTClose = NULL; + gpWTInfoW = NULL; + gpWTPacket = NULL; + gpWTEnable = NULL; + gpWTOverlap = NULL; + gpWTSave = NULL; + gpWTConfig = NULL; + gpWTGetW = NULL; + gpWTSetW = NULL; + gpWTRestore = NULL; + gpWTExtSet = NULL; + gpWTExtGet = NULL; + gpWTQueueSizeSet = NULL; + gpWTQueueSizeGet = NULL; + gpWTDataPeek = NULL; + gpWTPacketsGet = NULL; +} + +#ifdef WACOM_DEBUG + +////////////////////////////////////////////////////////////////////////////// + +void WacomTrace(char *lpszFormat, ...) +{ + char szTraceMessage[ 128 ]; + + int nBytesWritten; + + va_list args; + + WACOM_ASSERT( lpszFormat ); + + va_start( args, lpszFormat ); + + nBytesWritten = _vsnprintf( szTraceMessage, sizeof( szTraceMessage ) - 1, + lpszFormat, args ); + + if ( nBytesWritten > 0 ) + { + OutputDebugStringA( szTraceMessage ); + } + + va_end( args ); +} + +#endif // WACOM_DEBUG diff --git a/wintab/Utils.h b/wintab/Utils.h new file mode 100644 index 0000000..a057a31 --- /dev/null +++ b/wintab/Utils.h @@ -0,0 +1,97 @@ +/*---------------------------------------------------------------------------- + + NAME + Utils.h + + PURPOSE + Defines for the general-purpose functions for the WinTab demos. + + COPYRIGHT + Copyright (c) Wacom Company, Ltd. 2014 All Rights Reserved + All rights reserved. + + The text and information contained in this file may be freely used, + copied, or distributed without compensation or licensing restrictions. + +---------------------------------------------------------------------------- */ +#pragma once + +#include +#include +#include +#include + +#include "wintab.h" // NOTE: get from wactab header package + + +////////////////////////////////////////////////////////////////////////////// +#define WACOM_DEBUG + +// Ignore warnings about using unsafe string functions. +#pragma warning( disable : 4996 ) + +////////////////////////////////////////////////////////////////////////////// +// Function pointers to Wintab functions exported from wintab32.dll. +typedef UINT ( API * WTINFOW ) ( UINT, UINT, LPVOID ); +typedef UINT(API * WTINFOA) (UINT, UINT, LPVOID); +typedef HCTX ( API * WTOPENW )( HWND, LPLOGCONTEXTW, BOOL ); +typedef BOOL ( API * WTGETW ) ( HCTX, LPLOGCONTEXT ); +typedef BOOL ( API * WTSETW ) ( HCTX, LPLOGCONTEXT ); +typedef BOOL ( API * WTCLOSE ) ( HCTX ); +typedef BOOL ( API * WTENABLE ) ( HCTX, BOOL ); +typedef BOOL ( API * WTPACKET ) ( HCTX, UINT, LPVOID ); +typedef BOOL ( API * WTOVERLAP ) ( HCTX, BOOL ); +typedef BOOL ( API * WTSAVE ) ( HCTX, LPVOID ); +typedef BOOL ( API * WTCONFIG ) ( HCTX, HWND ); +typedef HCTX ( API * WTRESTORE ) ( HWND, LPVOID, BOOL ); +typedef BOOL ( API * WTEXTSET ) ( HCTX, UINT, LPVOID ); +typedef BOOL ( API * WTEXTGET ) ( HCTX, UINT, LPVOID ); +typedef BOOL ( API * WTQUEUESIZESET ) ( HCTX, int ); +typedef BOOL(API * WTQUEUESIZEGET) (HCTX); +typedef int ( API * WTDATAPEEK ) ( HCTX, UINT, UINT, int, LPVOID, LPINT); +typedef int ( API * WTPACKETSGET ) (HCTX, int, LPVOID); + +// TODO - add more wintab32 function defs as needed + +////////////////////////////////////////////////////////////////////////////// +// Loaded Wintab32 API functions. +extern HINSTANCE ghWintab; + +extern WTINFOW gpWTInfoW; +extern WTINFOA gpWTInfoA; +extern WTOPENW gpWTOpenW; +extern WTGETW gpWTGetW; +extern WTSETW gpWTSetW; +extern WTCLOSE gpWTClose; +extern WTPACKET gpWTPacket; +extern WTENABLE gpWTEnable; +extern WTOVERLAP gpWTOverlap; +extern WTSAVE gpWTSave; +extern WTCONFIG gpWTConfig; +extern WTRESTORE gpWTRestore; +extern WTEXTSET gpWTExtSet; +extern WTEXTGET gpWTExtGet; +extern WTQUEUESIZESET gpWTQueueSizeSet; +extern WTQUEUESIZEGET gpWTQueueSizeGet; +extern WTDATAPEEK gpWTDataPeek; +extern WTPACKETSGET gpWTPacketsGet; + +// TODO - add more wintab32 function pointers as needed + +////////////////////////////////////////////////////////////////////////////// +BOOL LoadWintab( void ); +void UnloadWintab( void ); + +////////////////////////////////////////////////////////////////////////////// +#ifdef WACOM_DEBUG + +void WacomTrace( char *lpszFormat, ...); + +#define WACOM_ASSERT( x ) assert( x ) +#define WACOM_TRACE(...) WacomTrace(__VA_ARGS__) +#else +#define WACOM_TRACE(...) +#define WACOM_ASSERT( x ) + +#endif // WACOM_DEBUG + diff --git a/wintab/WINTAB.H b/wintab/WINTAB.H new file mode 100644 index 0000000..fe78e77 --- /dev/null +++ b/wintab/WINTAB.H @@ -0,0 +1,930 @@ +/* -------------------------------- wintab.h -------------------------------- */ +/* Combined 16 & 32-bit version. */ + +/*------------------------------------------------------------------------------ +The text and information contained in this file may be freely used, +copied, or distributed without compensation or licensing restrictions. + +This file is Copyright (c) Wacom Company, Ltd. 2010 All Rights Reserved +with portions copyright 1991-1998 by LCS/Telegraphics. +------------------------------------------------------------------------------*/ + +#ifndef _INC_WINTAB /* prevent multiple includes */ +#define _INC_WINTAB +#include +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* -------------------------------------------------------------------------- */ +/* Messages */ +#ifndef NOWTMESSAGES + + #define WT_DEFBASE 0x7FF0 + #define WT_MAXOFFSET 0xF + + #define _WT_PACKET(b) ((b)+0) + #define _WT_CTXOPEN(b) ((b)+1) + #define _WT_CTXCLOSE(b) ((b)+2) + #define _WT_CTXUPDATE(b) ((b)+3) + #define _WT_CTXOVERLAP(b) ((b)+4) + #define _WT_PROXIMITY(b) ((b)+5) + #define _WT_INFOCHANGE(b) ((b)+6) + #define _WT_CSRCHANGE(b) ((b)+7) /* 1.1 */ + #define _WT_PACKETEXT(b) ((b)+8) /* 1.4 */ + #define _WT_MAX(b) ((b)+WT_MAXOFFSET) + + #define WT_PACKET _WT_PACKET(WT_DEFBASE) + #define WT_CTXOPEN _WT_CTXOPEN(WT_DEFBASE) + #define WT_CTXCLOSE _WT_CTXCLOSE(WT_DEFBASE) + #define WT_CTXUPDATE _WT_CTXUPDATE(WT_DEFBASE) + #define WT_CTXOVERLAP _WT_CTXOVERLAP(WT_DEFBASE) + #define WT_PROXIMITY _WT_PROXIMITY(WT_DEFBASE) + #define WT_INFOCHANGE _WT_INFOCHANGE(WT_DEFBASE) + #define WT_CSRCHANGE _WT_CSRCHANGE(WT_DEFBASE) /* 1.1 */ + #define WT_PACKETEXT _WT_PACKETEXT(WT_DEFBASE) /* 1.4 */ + #define WT_MAX _WT_MAX(WT_DEFBASE) + +#endif + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* Data Types */ + +/* -------------------------------------------------------------------------- */ +/* COMMON DATA DEFS */ + +DECLARE_HANDLE(HMGR); /* manager handle */ +DECLARE_HANDLE(HCTX); /* context handle */ +DECLARE_HANDLE(HWTHOOK); /* hook handle */ + +typedef DWORD WTPKT; /* packet mask */ + + +#ifndef NOWTPKT + + /* WTPKT bits */ + #define PK_CONTEXT 0x0001 /* reporting context */ + #define PK_STATUS 0x0002 /* status bits */ + #define PK_TIME 0x0004 /* time stamp */ + #define PK_CHANGED 0x0008 /* change bit vector */ + + #define PK_SERIAL_NUMBER 0x0010 /* packet serial number */ + #define PK_CURSOR 0x0020 /* reporting cursor */ + #define PK_BUTTONS 0x0040 /* button information */ + #define PK_X 0x0080 /* x axis */ + + #define PK_Y 0x0100 /* y axis */ + #define PK_Z 0x0200 /* z axis */ + #define PK_NORMAL_PRESSURE 0x0400 /* normal or tip pressure */ + #define PK_TANGENT_PRESSURE 0x0800 /* tangential or barrel pressure */ + #define PK_ORIENTATION 0x1000 /* orientation info: tilts */ + #define PK_ROTATION 0x2000 /* rotation info; 1.1 */ + +#endif + +typedef DWORD FIX32; /* fixed-point arithmetic type */ + +#ifndef NOFIX32 + #define INT(x) HIWORD(x) + #define FRAC(x) LOWORD(x) + + #define CASTFIX32(x) ((FIX32)((x)*65536L)) + + #define ROUND(x) (INT(x) + (FRAC(x) > (WORD)0x8000)) + + #define FIX_MUL(c, a, b) \ + (c = (((DWORD)FRAC(a) * FRAC(b)) >> 16) + \ + (DWORD)INT(a) * FRAC(b) + \ + (DWORD)INT(b) * FRAC(a) + \ + ((DWORD)INT(a) * INT(b) << 16)) + + #ifdef _WINDLL + #define FIX_DIV_SC static + #else + #define FIX_DIV_SC + #endif + + #define FIX_DIV(c, a, b) \ + { \ + FIX_DIV_SC DWORD temp, rem, btemp; \ + \ + /* fraction done bytewise */ \ + temp = ((a / b) << 16); \ + rem = a % b; \ + btemp = b; \ + if (INT(btemp) < 256) { \ + rem <<= 8; \ + } \ + else { \ + btemp >>= 8; \ + } \ + temp += ((rem / btemp) << 8); \ + rem %= btemp; \ + rem <<= 8; \ + temp += rem / btemp; \ + c = temp; \ + } +#endif + +/* -------------------------------------------------------------------------- */ +/* INFO DATA DEFS */ + +#ifndef NOWTINFO + +#ifndef NOWTAXIS + +typedef struct tagAXIS { + LONG axMin; + LONG axMax; + UINT axUnits; + FIX32 axResolution; + + tagAXIS() + { + axMin = 0; + axMax = 0; + axUnits = 0; + axResolution = 0; + } +} AXIS, *PAXIS, NEAR *NPAXIS, FAR *LPAXIS; + + /* unit specifiers */ + #define TU_NONE 0 + #define TU_INCHES 1 + #define TU_CENTIMETERS 2 + #define TU_CIRCLE 3 + +#endif + +#ifndef NOWTSYSBUTTONS + +/* system button assignment values */ +#define SBN_NONE 0x00 +#define SBN_LCLICK 0x01 +#define SBN_LDBLCLICK 0x02 +#define SBN_LDRAG 0x03 +#define SBN_RCLICK 0x04 +#define SBN_RDBLCLICK 0x05 +#define SBN_RDRAG 0x06 +#define SBN_MCLICK 0x07 +#define SBN_MDBLCLICK 0x08 +#define SBN_MDRAG 0x09 +/* for Pen Windows */ +#define SBN_PTCLICK 0x10 +#define SBN_PTDBLCLICK 0x20 +#define SBN_PTDRAG 0x30 +#define SBN_PNCLICK 0x40 +#define SBN_PNDBLCLICK 0x50 +#define SBN_PNDRAG 0x60 +#define SBN_P1CLICK 0x70 +#define SBN_P1DBLCLICK 0x80 +#define SBN_P1DRAG 0x90 +#define SBN_P2CLICK 0xA0 +#define SBN_P2DBLCLICK 0xB0 +#define SBN_P2DRAG 0xC0 +#define SBN_P3CLICK 0xD0 +#define SBN_P3DBLCLICK 0xE0 +#define SBN_P3DRAG 0xF0 + +#endif + +#ifndef NOWTCAPABILITIES + +/* hardware capabilities */ +#define HWC_INTEGRATED 0x0001 +#define HWC_TOUCH 0x0002 +#define HWC_HARDPROX 0x0004 +#define HWC_PHYSID_CURSORS 0x0008 /* 1.1 */ +#endif + +#ifndef NOWTIFC + +#ifndef NOWTCURSORS + +/* cursor capabilities */ +#define CRC_MULTIMODE 0x0001 /* 1.1 */ +#define CRC_AGGREGATE 0x0002 /* 1.1 */ +#define CRC_INVERT 0x0004 /* 1.1 */ + +#endif + +/* info categories */ +#define WTI_INTERFACE 1 + #define IFC_WINTABID 1 + #define IFC_SPECVERSION 2 + #define IFC_IMPLVERSION 3 + #define IFC_NDEVICES 4 + #define IFC_NCURSORS 5 + #define IFC_NCONTEXTS 6 + #define IFC_CTXOPTIONS 7 + #define IFC_CTXSAVESIZE 8 + #define IFC_NEXTENSIONS 9 + #define IFC_NMANAGERS 10 + #define IFC_MAX 10 + + +#endif + +#ifndef NOWTSTATUS + +#define WTI_STATUS 2 + #define STA_CONTEXTS 1 + #define STA_SYSCTXS 2 + #define STA_PKTRATE 3 + #define STA_PKTDATA 4 + #define STA_MANAGERS 5 + #define STA_SYSTEM 6 + #define STA_BUTTONUSE 7 + #define STA_SYSBTNUSE 8 + #define STA_MAX 8 + +#endif + +#ifndef NOWTDEFCONTEXT + +#define WTI_DEFCONTEXT 3 +#define WTI_DEFSYSCTX 4 +#define WTI_DDCTXS 400 /* 1.1 */ +#define WTI_DSCTXS 500 /* 1.1 */ + #define CTX_NAME 1 + #define CTX_OPTIONS 2 + #define CTX_STATUS 3 + #define CTX_LOCKS 4 + #define CTX_MSGBASE 5 + #define CTX_DEVICE 6 + #define CTX_PKTRATE 7 + #define CTX_PKTDATA 8 + #define CTX_PKTMODE 9 + #define CTX_MOVEMASK 10 + #define CTX_BTNDNMASK 11 + #define CTX_BTNUPMASK 12 + #define CTX_INORGX 13 + #define CTX_INORGY 14 + #define CTX_INORGZ 15 + #define CTX_INEXTX 16 + #define CTX_INEXTY 17 + #define CTX_INEXTZ 18 + #define CTX_OUTORGX 19 + #define CTX_OUTORGY 20 + #define CTX_OUTORGZ 21 + #define CTX_OUTEXTX 22 + #define CTX_OUTEXTY 23 + #define CTX_OUTEXTZ 24 + #define CTX_SENSX 25 + #define CTX_SENSY 26 + #define CTX_SENSZ 27 + #define CTX_SYSMODE 28 + #define CTX_SYSORGX 29 + #define CTX_SYSORGY 30 + #define CTX_SYSEXTX 31 + #define CTX_SYSEXTY 32 + #define CTX_SYSSENSX 33 + #define CTX_SYSSENSY 34 + #define CTX_MAX 34 + +#endif + +#ifndef NOWTDEVICES + +#define WTI_DEVICES 100 + #define DVC_NAME 1 + #define DVC_HARDWARE 2 + #define DVC_NCSRTYPES 3 + #define DVC_FIRSTCSR 4 + #define DVC_PKTRATE 5 + #define DVC_PKTDATA 6 + #define DVC_PKTMODE 7 + #define DVC_CSRDATA 8 + #define DVC_XMARGIN 9 + #define DVC_YMARGIN 10 + #define DVC_ZMARGIN 11 + #define DVC_X 12 + #define DVC_Y 13 + #define DVC_Z 14 + #define DVC_NPRESSURE 15 + #define DVC_TPRESSURE 16 + #define DVC_ORIENTATION 17 + #define DVC_ROTATION 18 /* 1.1 */ + #define DVC_PNPID 19 /* 1.1 */ + #define DVC_MAX 19 + +#endif + +#ifndef NOWTCURSORS + +#define WTI_CURSORS 200 + #define CSR_NAME 1 + #define CSR_ACTIVE 2 + #define CSR_PKTDATA 3 + #define CSR_BUTTONS 4 + #define CSR_BUTTONBITS 5 + #define CSR_BTNNAMES 6 + #define CSR_BUTTONMAP 7 + #define CSR_SYSBTNMAP 8 + #define CSR_NPBUTTON 9 + #define CSR_NPBTNMARKS 10 + #define CSR_NPRESPONSE 11 + #define CSR_TPBUTTON 12 + #define CSR_TPBTNMARKS 13 + #define CSR_TPRESPONSE 14 + #define CSR_PHYSID 15 /* 1.1 */ + #define CSR_MODE 16 /* 1.1 */ + #define CSR_MINPKTDATA 17 /* 1.1 */ + #define CSR_MINBUTTONS 18 /* 1.1 */ + #define CSR_CAPABILITIES 19 /* 1.1 */ + #define CSR_TYPE 20 /* 1.2 */ + #define CSR_MAX 20 + +#endif + +#ifndef NOWTEXTENSIONS + +#define WTI_EXTENSIONS 300 + #define EXT_NAME 1 + #define EXT_TAG 2 + #define EXT_MASK 3 + #define EXT_SIZE 4 + #define EXT_AXES 5 + #define EXT_DEFAULT 6 + #define EXT_DEFCONTEXT 7 + #define EXT_DEFSYSCTX 8 + #define EXT_CURSORS 9 + #define EXT_DEVICES 110 /* Allow 100 cursors */ + #define EXT_MAX 210 /* Allow 100 devices */ + +#endif + +#endif + +/* -------------------------------------------------------------------------- */ +/* CONTEXT DATA DEFS */ + +#define LCNAMELEN 40 +#define LC_NAMELEN 40 +#ifdef WIN32 +typedef struct tagLOGCONTEXTA { + char lcName[LCNAMELEN]; + UINT lcOptions; + UINT lcStatus; + UINT lcLocks; + UINT lcMsgBase; + UINT lcDevice; + UINT lcPktRate; + WTPKT lcPktData; + WTPKT lcPktMode; + WTPKT lcMoveMask; + DWORD lcBtnDnMask; + DWORD lcBtnUpMask; + LONG lcInOrgX; + LONG lcInOrgY; + LONG lcInOrgZ; + LONG lcInExtX; + LONG lcInExtY; + LONG lcInExtZ; + LONG lcOutOrgX; + LONG lcOutOrgY; + LONG lcOutOrgZ; + LONG lcOutExtX; + LONG lcOutExtY; + LONG lcOutExtZ; + FIX32 lcSensX; + FIX32 lcSensY; + FIX32 lcSensZ; + BOOL lcSysMode; + int lcSysOrgX; + int lcSysOrgY; + int lcSysExtX; + int lcSysExtY; + FIX32 lcSysSensX; + FIX32 lcSysSensY; +} LOGCONTEXTA, *PLOGCONTEXTA, NEAR *NPLOGCONTEXTA, FAR *LPLOGCONTEXTA; +typedef struct tagLOGCONTEXTW { + WCHAR lcName[LCNAMELEN]; + UINT lcOptions; + UINT lcStatus; + UINT lcLocks; + UINT lcMsgBase; + UINT lcDevice; + UINT lcPktRate; + WTPKT lcPktData; + WTPKT lcPktMode; + WTPKT lcMoveMask; + DWORD lcBtnDnMask; + DWORD lcBtnUpMask; + LONG lcInOrgX; + LONG lcInOrgY; + LONG lcInOrgZ; + LONG lcInExtX; + LONG lcInExtY; + LONG lcInExtZ; + LONG lcOutOrgX; + LONG lcOutOrgY; + LONG lcOutOrgZ; + LONG lcOutExtX; + LONG lcOutExtY; + LONG lcOutExtZ; + FIX32 lcSensX; + FIX32 lcSensY; + FIX32 lcSensZ; + BOOL lcSysMode; + int lcSysOrgX; + int lcSysOrgY; + int lcSysExtX; + int lcSysExtY; + FIX32 lcSysSensX; + FIX32 lcSysSensY; +} LOGCONTEXTW, *PLOGCONTEXTW, NEAR *NPLOGCONTEXTW, FAR *LPLOGCONTEXTW; +#ifdef UNICODE +typedef LOGCONTEXTW LOGCONTEXT; +typedef PLOGCONTEXTW PLOGCONTEXT; +typedef NPLOGCONTEXTW NPLOGCONTEXT; +typedef LPLOGCONTEXTW LPLOGCONTEXT; +#else +typedef LOGCONTEXTA LOGCONTEXT; +typedef PLOGCONTEXTA PLOGCONTEXT; +typedef NPLOGCONTEXTA NPLOGCONTEXT; +typedef LPLOGCONTEXTA LPLOGCONTEXT; +#endif /* UNICODE */ +#else /* WIN32 */ +typedef struct tagLOGCONTEXT { + char lcName[LCNAMELEN]; + UINT lcOptions; + UINT lcStatus; + UINT lcLocks; + UINT lcMsgBase; + UINT lcDevice; + UINT lcPktRate; + WTPKT lcPktData; + WTPKT lcPktMode; + WTPKT lcMoveMask; + DWORD lcBtnDnMask; + DWORD lcBtnUpMask; + LONG lcInOrgX; + LONG lcInOrgY; + LONG lcInOrgZ; + LONG lcInExtX; + LONG lcInExtY; + LONG lcInExtZ; + LONG lcOutOrgX; + LONG lcOutOrgY; + LONG lcOutOrgZ; + LONG lcOutExtX; + LONG lcOutExtY; + LONG lcOutExtZ; + FIX32 lcSensX; + FIX32 lcSensY; + FIX32 lcSensZ; + BOOL lcSysMode; + int lcSysOrgX; + int lcSysOrgY; + int lcSysExtX; + int lcSysExtY; + FIX32 lcSysSensX; + FIX32 lcSysSensY; +} LOGCONTEXT, *PLOGCONTEXT, NEAR *NPLOGCONTEXT, FAR *LPLOGCONTEXT; +#endif /* WIN32 */ + + /* context option values */ + #define CXO_SYSTEM 0x0001 + #define CXO_PEN 0x0002 + #define CXO_MESSAGES 0x0004 + #define CXO_MARGIN 0x8000 + #define CXO_MGNINSIDE 0x4000 + #define CXO_CSRMESSAGES 0x0008 /* 1.1 */ + + /* context status values */ + #define CXS_DISABLED 0x0001 + #define CXS_OBSCURED 0x0002 + #define CXS_ONTOP 0x0004 + + /* context lock values */ + #define CXL_INSIZE 0x0001 + #define CXL_INASPECT 0x0002 + #define CXL_SENSITIVITY 0x0004 + #define CXL_MARGIN 0x0008 + #define CXL_SYSOUT 0x0010 + +/* -------------------------------------------------------------------------- */ +/* EVENT DATA DEFS */ + +/* For packet structure definition, see pktdef.h */ + +/* packet status values */ +#define TPS_PROXIMITY 0x0001 +#define TPS_QUEUE_ERR 0x0002 +#define TPS_MARGIN 0x0004 +#define TPS_GRAB 0x0008 +#define TPS_INVERT 0x0010 /* 1.1 */ + +typedef struct tagORIENTATION { + int orAzimuth; + int orAltitude; + int orTwist; +} ORIENTATION, *PORIENTATION, NEAR *NPORIENTATION, FAR *LPORIENTATION; + +typedef struct tagROTATION { /* 1.1 */ + int roPitch; + int roRoll; + int roYaw; +} ROTATION, *PROTATION, NEAR *NPROTATION, FAR *LPROTATION; +// grandfather in obsolete member names. +#define rotPitch roPitch +#define rotRoll roRoll +#define rotYaw roYaw + + +/* relative buttons */ +#define TBN_NONE 0 +#define TBN_UP 1 +#define TBN_DOWN 2 + +/* -------------------------------------------------------------------------- */ +/* DEVICE CONFIG CONSTANTS */ + +#ifndef NOWTDEVCFG + +#define WTDC_NONE 0 +#define WTDC_CANCEL 1 +#define WTDC_OK 2 +#define WTDC_RESTART 3 + +#endif + +/* -------------------------------------------------------------------------- */ +/* HOOK CONSTANTS */ + +#ifndef NOWTHOOKS + +#define WTH_PLAYBACK 1 +#define WTH_RECORD 2 + +#define WTHC_GETLPLPFN (-3) +#define WTHC_LPLPFNNEXT (-2) +#define WTHC_LPFNNEXT (-1) +#define WTHC_ACTION 0 +#define WTHC_GETNEXT 1 +#define WTHC_SKIP 2 + +#endif + +/* -------------------------------------------------------------------------- */ +/* PREFERENCE FUNCTION CONSTANTS */ + +#ifndef NOWTPREF + +#define WTP_LPDEFAULT ((LPVOID)-1L) +#define WTP_DWDEFAULT ((DWORD)-1L) + +#endif + +/* -------------------------------------------------------------------------- */ +/* EXTENSION TAGS AND CONSTANTS */ + +#ifndef NOWTEXTENSIONS + +/* constants for use with pktdef.h */ +#define PKEXT_ABSOLUTE 1 +#define PKEXT_RELATIVE 2 + +/* Extension tags. */ +#define WTX_OBT 0 /* Out of bounds tracking */ +#define WTX_FKEYS 1 /* Function keys */ +#define WTX_TILT 2 /* Raw Cartesian tilt; 1.1 */ +#define WTX_CSRMASK 3 /* select input by cursor type; 1.1 */ +#define WTX_XBTNMASK 4 /* Extended button mask; 1.1 */ +#define WTX_EXPKEYS 5 /* ExpressKeys; 1.3 - DEPRECATED: see WTX_EXPKEYS2 */ +#define WTX_TOUCHSTRIP 6 /* TouchStrips; 1.4 */ +#define WTX_TOUCHRING 7 /* TouchRings; 1.4 */ +#define WTX_EXPKEYS2 8 /* ExpressKeys; 1.4 */ + +typedef struct tagXBTNMASK { + BYTE xBtnDnMask[32]; + BYTE xBtnUpMask[32]; +} XBTNMASK; + +typedef struct tagTILT { /* 1.1 */ + int tiltX; + int tiltY; +} TILT; + +typedef struct tagEXTENSIONBASE { /* 1.4 */ + HCTX nContext; + UINT nStatus; + DWORD nTime; + UINT nSerialNumber; +} EXTENSIONBASE; + +typedef struct tagEXPKEYSDATA { /* 1.4 */ + BYTE nTablet; + BYTE nControl; + BYTE nLocation; + BYTE nReserved; + DWORD nState; +} EXPKEYSDATA; + +typedef struct tagSLIDERDATA { /* 1.4 */ + BYTE nTablet; + BYTE nControl; + BYTE nMode; + BYTE nReserved; + DWORD nPosition; +} SLIDERDATA; + +typedef struct tagEXTPROPERTY { /* 1.4 */ + BYTE version; // Structure version, 0 for now + BYTE tabletIndex; // 0-based index for tablet + BYTE controlIndex; // 0-based index for control + BYTE functionIndex; // 0-based index for control's sub-function + WORD propertyID; // property ID + WORD reserved; // DWORD-alignment filler + DWORD dataSize; // number of bytes in data[] buffer + BYTE data[1]; // raw data +} EXTPROPERTY; + +#define TABLET_PROPERTY_CONTROLCOUNT 0 // UINT32: number of physical controls on tablet +#define TABLET_PROPERTY_FUNCCOUNT 1 // UINT32: number of functions of control +#define TABLET_PROPERTY_AVAILABLE 2 // BOOL: control/mode is available for override +#define TABLET_PROPERTY_MIN 3 // UINT32: minimum value +#define TABLET_PROPERTY_MAX 4 // UINT32: maximum value +#define TABLET_PROPERTY_OVERRIDE 5 // BOOL: control is overridden +#define TABLET_PROPERTY_OVERRIDE_NAME 6 // UTF-8: Displayable name when control is overridden +#define TABLET_PROPERTY_LOCATION 11 // UINT32: Physical location of control (see TABLET_LOC_*) + +#define TABLET_LOC_LEFT 0 +#define TABLET_LOC_RIGHT 1 +#define TABLET_LOC_TOP 2 +#define TABLET_LOC_BOTTOM 3 +#define TABLET_LOC_TRANSDUCER 4 + +#endif + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* Functions */ + + #ifndef API + #ifndef WINAPI + #define API FAR PASCAL + #else + #define API WINAPI + #endif + #endif + +#ifndef NOWTCALLBACKS + + #ifndef CALLBACK + #define CALLBACK FAR PASCAL + #endif + + #ifndef NOWTMANAGERFXNS + /* callback function types */ + typedef BOOL (WINAPI * WTENUMPROC)(HCTX, LPARAM); /* changed CALLBACK->WINAPI, 1.1 */ + typedef BOOL (WINAPI * WTCONFIGPROC)(HCTX, HWND); + typedef LRESULT (WINAPI * WTHOOKPROC)(int, WPARAM, LPARAM); + typedef WTHOOKPROC FAR *LPWTHOOKPROC; + #endif + +#endif + + +#ifndef NOWTFUNCTIONS + + #ifndef NOWTBASICFXNS + /* BASIC FUNCTIONS */ +#ifdef WIN32 + UINT API WTInfoA(UINT, UINT, LPVOID); + #define ORD_WTInfoA 20 + UINT API WTInfoW(UINT, UINT, LPVOID); + #define ORD_WTInfoW 1020 + #ifdef UNICODE + #define WTInfo WTInfoW + #define ORD_WTInfo ORD_WTInfoW + #else + #define WTInfo WTInfoA + #define ORD_WTInfo ORD_WTInfoA + #endif /* !UNICODE */ +#else + UINT API WTInfo(UINT, UINT, LPVOID); + #define ORD_WTInfo 20 +#endif +#ifdef WIN32 + HCTX API WTOpenA(HWND, LPLOGCONTEXTA, BOOL); + #define ORD_WTOpenA 21 + HCTX API WTOpenW(HWND, LPLOGCONTEXTW, BOOL); + #define ORD_WTOpenW 1021 + #ifdef UNICODE + #define WTOpen WTOpenW + #define ORD_WTOpen ORD_WTOpenW + #else + #define WTOpen WTOpenA + #define ORD_WTOpen ORD_WTOpenA + #endif /* !UNICODE */ +#else + HCTX API WTOpen(HWND, LPLOGCONTEXT, BOOL); + #define ORD_WTOpen 21 +#endif + BOOL API WTClose(HCTX); + #define ORD_WTClose 22 + int API WTPacketsGet(HCTX, int, LPVOID); + #define ORD_WTPacketsGet 23 + BOOL API WTPacket(HCTX, UINT, LPVOID); + #define ORD_WTPacket 24 + #endif + + #ifndef NOWTVISIBILITYFXNS + /* VISIBILITY FUNCTIONS */ + BOOL API WTEnable(HCTX, BOOL); + #define ORD_WTEnable 40 + BOOL API WTOverlap(HCTX, BOOL); + #define ORD_WTOverlap 41 + #endif + + #ifndef NOWTCTXEDITFXNS + /* CONTEXT EDITING FUNCTIONS */ + BOOL API WTConfig(HCTX, HWND); + #define ORD_WTConfig 60 +#ifdef WIN32 + BOOL API WTGetA(HCTX, LPLOGCONTEXTA); + #define ORD_WTGetA 61 + BOOL API WTGetW(HCTX, LPLOGCONTEXTW); + #define ORD_WTGetW 1061 + #ifdef UNICODE + #define WTGet WTGetW + #define ORD_WTGet ORD_WTGetW + #else + #define WTGet WTGetA + #define ORD_WTGet ORD_WTGetA + #endif /* !UNICODE */ +#else + BOOL API WTGet(HCTX, LPLOGCONTEXT); + #define ORD_WTGet 61 +#endif +#ifdef WIN32 + BOOL API WTSetA(HCTX, LPLOGCONTEXTA); + #define ORD_WTSetA 62 + BOOL API WTSetW(HCTX, LPLOGCONTEXTW); + #define ORD_WTSetW 1062 + #ifdef UNICODE + #define WTSet WTSetW + #define ORD_WTSet ORD_WTSetW + #else + #define WTSet WTSetA + #define ORD_WTSet ORD_WTSetA + #endif /* !UNICODE */ +#else + BOOL API WTSet(HCTX, LPLOGCONTEXT); + #define ORD_WTSet 62 +#endif + BOOL API WTExtGet(HCTX, UINT, LPVOID); + #define ORD_WTExtGet 63 + BOOL API WTExtSet(HCTX, UINT, LPVOID); + #define ORD_WTExtSet 64 + BOOL API WTSave(HCTX, LPVOID); + #define ORD_WTSave 65 + HCTX API WTRestore(HWND, LPVOID, BOOL); + #define ORD_WTRestore 66 + #endif + + #ifndef NOWTQUEUEFXNS + /* ADVANCED PACKET AND QUEUE FUNCTIONS */ + int API WTPacketsPeek(HCTX, int, LPVOID); + #define ORD_WTPacketsPeek 80 + int API WTDataGet(HCTX, UINT, UINT, int, LPVOID, LPINT); + #define ORD_WTDataGet 81 + int API WTDataPeek(HCTX, UINT, UINT, int, LPVOID, LPINT); + #define ORD_WTDataPeek 82 +#ifndef WIN32 +/* OBSOLETE IN WIN32! */ + DWORD API WTQueuePackets(HCTX); + #define ORD_WTQueuePackets 83 +#endif + int API WTQueueSizeGet(HCTX); + #define ORD_WTQueueSizeGet 84 + BOOL API WTQueueSizeSet(HCTX, int); + #define ORD_WTQueueSizeSet 85 + #endif + + #ifndef NOWTHMGRFXNS + /* MANAGER HANDLE FUNCTIONS */ + HMGR API WTMgrOpen(HWND, UINT); + #define ORD_WTMgrOpen 100 + BOOL API WTMgrClose(HMGR); + #define ORD_WTMgrClose 101 + #endif + + #ifndef NOWTMGRCTXFXNS + /* MANAGER CONTEXT FUNCTIONS */ + BOOL API WTMgrContextEnum(HMGR, WTENUMPROC, LPARAM); + #define ORD_WTMgrContextEnum 120 + HWND API WTMgrContextOwner(HMGR, HCTX); + #define ORD_WTMgrContextOwner 121 + HCTX API WTMgrDefContext(HMGR, BOOL); + #define ORD_WTMgrDefContext 122 + HCTX API WTMgrDefContextEx(HMGR, UINT, BOOL); /* 1.1 */ + #define ORD_WTMgrDefContextEx 206 + #endif + + #ifndef NOWTMGRCONFIGFXNS + /* MANAGER CONFIG BOX FUNCTIONS */ + UINT API WTMgrDeviceConfig(HMGR, UINT, HWND); + #define ORD_WTMgrDeviceConfig 140 +#ifndef WIN32 +/* OBSOLETE IN WIN32! */ + BOOL API WTMgrConfigReplace(HMGR, BOOL, WTCONFIGPROC); + #define ORD_WTMgrConfigReplace 141 +#endif + #endif + + #ifndef NOWTMGRHOOKFXNS + /* MANAGER PACKET HOOK FUNCTIONS */ +#ifndef WIN32 +/* OBSOLETE IN WIN32! */ + WTHOOKPROC API WTMgrPacketHook(HMGR, BOOL, int, WTHOOKPROC); + #define ORD_WTMgrPacketHook 160 + LRESULT API WTMgrPacketHookDefProc(int, WPARAM, LPARAM, LPWTHOOKPROC); + #define ORD_WTMgrPacketHookDefProc 161 +#endif + #endif + + #ifndef NOWTMGRPREFFXNS + /* MANAGER PREFERENCE DATA FUNCTIONS */ + BOOL API WTMgrExt(HMGR, UINT, LPVOID); + #define ORD_WTMgrExt 180 + BOOL API WTMgrCsrEnable(HMGR, UINT, BOOL); + #define ORD_WTMgrCsrEnable 181 + BOOL API WTMgrCsrButtonMap(HMGR, UINT, LPBYTE, LPBYTE); + #define ORD_WTMgrCsrButtonMap 182 + BOOL API WTMgrCsrPressureBtnMarks(HMGR, UINT, DWORD, DWORD); + #define ORD_WTMgrCsrPressureBtnMarks 183 + BOOL API WTMgrCsrPressureResponse(HMGR, UINT, UINT FAR *, UINT FAR *); + #define ORD_WTMgrCsrPressureResponse 184 + BOOL API WTMgrCsrExt(HMGR, UINT, UINT, LPVOID); + #define ORD_WTMgrCsrExt 185 + #endif + +/* Win32 replacements for non-portable functions. */ + #ifndef NOWTQUEUEFXNS + /* ADVANCED PACKET AND QUEUE FUNCTIONS */ + BOOL API WTQueuePacketsEx(HCTX, UINT FAR *, UINT FAR *); + #define ORD_WTQueuePacketsEx 200 + #endif + + #ifndef NOWTMGRCONFIGFXNS + /* MANAGER CONFIG BOX FUNCTIONS */ +#ifdef WIN32 + BOOL API WTMgrConfigReplaceExA(HMGR, BOOL, LPSTR, LPSTR); + #define ORD_WTMgrConfigReplaceExA 202 + BOOL API WTMgrConfigReplaceExW(HMGR, BOOL, LPWSTR, LPSTR); + #define ORD_WTMgrConfigReplaceExW 1202 + #ifdef UNICODE + #define WTMgrConfigReplaceEx WTMgrConfigReplaceExW + #define ORD_WTMgrConfigReplaceEx ORD_WTMgrConfigReplaceExW + #else + #define WTMgrConfigReplaceEx WTMgrConfigReplaceExA + #define ORD_WTMgrConfigReplaceEx ORD_WTMgrConfigReplaceExA + #endif /* !UNICODE */ +#else + BOOL API WTMgrConfigReplaceEx(HMGR, BOOL, LPSTR, LPSTR); + #define ORD_WTMgrConfigReplaceEx 202 +#endif + #endif + + #ifndef NOWTMGRHOOKFXNS + /* MANAGER PACKET HOOK FUNCTIONS */ +#ifdef WIN32 + HWTHOOK API WTMgrPacketHookExA(HMGR, int, LPSTR, LPSTR); + #define ORD_WTMgrPacketHookExA 203 + HWTHOOK API WTMgrPacketHookExW(HMGR, int, LPWSTR, LPSTR); + #define ORD_WTMgrPacketHookExW 1203 + #ifdef UNICODE + #define WTMgrPacketHookEx WTMgrPacketHookExW + #define ORD_WTMgrPacketHookEx ORD_WTMgrPacketHookExW + #else + #define WTMgrPacketHookEx WTMgrPacketHookExA + #define ORD_WTMgrPacketHookEx ORD_WTMgrPacketHookExA + #endif /* !UNICODE */ +#else + HWTHOOK API WTMgrPacketHookEx(HMGR, int, LPSTR, LPSTR); + #define ORD_WTMgrPacketHookEx 203 +#endif + BOOL API WTMgrPacketUnhook(HWTHOOK); + #define ORD_WTMgrPacketUnhook 204 + LRESULT API WTMgrPacketHookNext(HWTHOOK, int, WPARAM, LPARAM); + #define ORD_WTMgrPacketHookNext 205 + #endif + + #ifndef NOWTMGRPREFFXNS + /* MANAGER PREFERENCE DATA FUNCTIONS */ + BOOL API WTMgrCsrPressureBtnMarksEx(HMGR, UINT, UINT FAR *, UINT FAR *); + #define ORD_WTMgrCsrPressureBtnMarksEx 201 + #endif + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* #define _INC_WINTAB */ +