void CBCStroke::DrawBezierCurve(FCObjImage& img,BezierPressCurve& bezpCurve,BYTE alpha,float zoompaper,float zoompress) { double t,delt; //delt=(double)1/bezpCurve.numpoint; TPosition position; t=0.0; int x1,y1,x2,y2; x1=y1=x2=y2=0; BezierCurve bezCurve=new Point2[bezpCurve.degree+1]; for(int i=0;i<=bezpCurve.degree;++i){ bezCurve[i].x=zoompaper*(bezpCurve.bezCurve[i].x); bezCurve[i].y=zoompaper*(bezpCurve.bezCurve[i].y); } /* for(int i=0;i<=bezpCurve.degree;++i){ bezpCurve.bezCurve[i].x=zoompaper*(bezpCurve.bezCurve[i].x); bezpCurve.bezCurve[i].y=zoompaper*(bezpCurve.bezCurve[i].y); }*/ float numpoint=0; if(bezpCurve.degree>=2){ numpoint=V2DistanceBetween2Points(&(bezCurve[0]),&(bezCurve[1])); for (int i =1; i <bezpCurve.degree; i++) { numpoint+=V2DistanceBetween2Points(&(bezCurve[i]),&(bezCurve[i+1])); } } numpoint=numpoint*2; if(numpoint<=0) return; delt=(double)1/numpoint; bezpCurve.numpoint=0; for(int i=0;i<=numpoint;++i){ Point2 p=CBCStroke::BezierII(bezpCurve.degree,bezCurve,t); //if(i==numpoint) // continue; x1=p.x; y1=p.y; if(x1!=x2||y1!=y2){ PARAMER param; //CStrokeTransform::GenParamer(bezpCurve.uList,t,param); position.press=param.press*zoompress; position.press=(position.press<1)?1:position.press; position.m_angle_z=param.m_angle_z; position.m_angle_xy=param.m_angle_xy; position.m_x=x1; position.m_y=y1; m_lpPaper->DrawSection(img,position,alpha); x2=x1; y2=y1; bezpCurve.numpoint++; } t+=delt; } }
double Measurement::NearestPointOnCurve(QPointF P, vector<QPointF> V) { QPointF *w; /* Ctl pts for 5th-degree eqn */ double t_candidate[W_DEGREE]; /* Possible roots */ int n_solutions; /* Number of roots found */ double t; /* Parameter value of closest pt*/ QPointF v_arr[4]; for(int i=0; i<4; i++) v_arr[i]=V[i]; /* Convert problem to 5th-degree Bezier form */ w = ConvertToBezierForm(P, v_arr); /* Find all possible roots of 5th-degree equation */ n_solutions = FindRoots(w, W_DEGREE, t_candidate, 0); free((char *)w); /* Compare distances of P to all candidates, and to t=0, and t=1 */ { double dist, new_dist; QPointF p; QPointF v; int i; /* Check distance to beginning of curve, where t = 0 */ dist = V2SquaredLength(V2Sub(&P, &v_arr[0], &v)); t = 0.0; /* Find distances for candidate points */ for (i = 0; i < n_solutions; i++) { p = Bezier(v_arr, DEGREE, t_candidate[i], (QPointF *)NULL, (QPointF *)NULL); new_dist = V2SquaredLength(V2Sub(&P, &p, &v)); if (new_dist < dist) { dist = new_dist; t = t_candidate[i]; } } /* Finally, look at distance to end point, where t = 1.0 */ new_dist = V2SquaredLength(V2Sub(&P, &V[DEGREE], &v)); if (new_dist < dist) { dist = new_dist; t = 1.0; } } /* Return the point on the curve at parameter value t */ // printf("t : %4.12f\n", t); QPointF b=Bezier(v_arr, DEGREE, t, (QPointF *)NULL, (QPointF *)NULL); return V2DistanceBetween2Points(&P,&b); }
//------------------------------------------------------ //----计算u为t时的bezier曲线的近似长度。 double BezierPressCurve::GetLengthFromParam(double t,double t_begin,double error) { Point2 p1=CBCStroke::BezierII(degree,bezCurve,t_begin); Point2 p2=CBCStroke::BezierII(degree,bezCurve,t); double length=V2DistanceBetween2Points(&p1,&p2); if((length>error)||(fabs(t-t_begin)>=0.25)){ length=GetLengthFromParam((t+t_begin)/2,t_begin,error)+GetLengthFromParam(t,(t+t_begin)/2,error); } return length; }
void CBCStroke::AddBezierCurve(int degree,BezierCurve bezCurve,PARAMERLIST& paramList) { BezierPressCurve bezpCurve; bezpCurve.degree=degree; bezpCurve.bezCurve = (Point2 *)malloc((unsigned)((degree+1) * sizeof (Point2))); //for(int i=0;i<=degree;++i){ // bezpCurve.bezCurve[i].x=bezCurve[i].x; // bezpCurve.bezCurve[i].y=bezCurve[i].y; //} memcpy(bezpCurve.bezCurve,bezCurve,(degree+1) * sizeof (Point2)); double numpoint=0; if(degree>=2){ numpoint=V2DistanceBetween2Points(&(bezCurve[0]),&(bezCurve[1])); for (int i =1; i <degree; i++) { numpoint+=V2DistanceBetween2Points(&(bezCurve[i]),&(bezCurve[i+1])); } } bezpCurve.numpoint=numpoint*2; //copy(paramList.begin(),paramList.end(),bezpCurve.uList.begin()); bezpCurve.uList.swap(paramList); // paramList.clear(); m_bezStroke.push_back(bezpCurve); }
/* * ChordLengthParameterize : * Assign parameter values to digitized points * using relative distances between points. */ static double *ChordLengthParameterize(Point2 *d, int first, int last) { int i; double *u; /* Parameterization */ u = (double *)malloc((unsigned)(last-first+1) * sizeof(double)); u[0] = 0.0; for (i = first+1; i <= last; i++) { u[i-first] = u[i-first-1] + V2DistanceBetween2Points(&d[i], &d[i-1]); } for (i = first + 1; i <= last; i++) { u[i-first] = u[i-first] / u[last-first]; } return(u); }
/* * ChordLengthParameterize : * Assign parameter values to digitized points * using relative distances between points. */ double *CBCStroke::ChordLengthParameterize( DISCURVE& d, /* Array of digitized points */ int first,int last) /* Indices defining region */ { int i; double *u; /* Parameterization */ u = (double *)malloc((unsigned)(last-first+1) * sizeof(double)); u[0] = 0.0; for (i = first+1; i <= last; i++) { u[i-first] = u[i-first-1] + V2DistanceBetween2Points(&d[i], &d[i-1]); } for (i = first + 1; i <= last; i++) { u[i-first] = u[i-first] / u[last-first]; } return(u); }
/* * GenerateBezier : * Use least-squares method to find Bezier control points for region. * */ static BezierCurve GenerateBezier(Point2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2) { int i; Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */ int nPts; /* Number of pts in sub-curve */ double C[2][2]; /* Matrix C */ double X[2]; /* Matrix X */ double det_C0_C1, /* Determinants of matrices */ det_C0_X, det_X_C1; double alpha_l, /* Alpha values, left and right */ alpha_r; Vector2 tmp; /* Utility variable */ BezierCurve bezCurve; /* RETURN bezier curve ctl pts */ bezCurve = (Point2 *)malloc(4 * sizeof(Point2)); nPts = last - first + 1; /* Compute the A's */ for (i = 0; i < nPts; i++) { Vector2 v1, v2; v1 = tHat1; v2 = tHat2; V2Scale(&v1, B1(uPrime[i])); V2Scale(&v2, B2(uPrime[i])); A[i][0] = v1; A[i][1] = v2; } /* Create the C and X matrices */ C[0][0] = 0.0; C[0][1] = 0.0; C[1][0] = 0.0; C[1][1] = 0.0; X[0] = 0.0; X[1] = 0.0; for (i = 0; i < nPts; i++) { C[0][0] += V2Dot(&A[i][0], &A[i][0]); C[0][1] += V2Dot(&A[i][0], &A[i][1]); /* C[1][0] += V2Dot(&A[i][0], &A[i][1]);*/ C[1][0] = C[0][1]; C[1][1] += V2Dot(&A[i][1], &A[i][1]); tmp = V2SubII(d[first + i], V2AddII( V2ScaleIII(d[first], B0(uPrime[i])), V2AddII( V2ScaleIII(d[first], B1(uPrime[i])), V2AddII( V2ScaleIII(d[last], B2(uPrime[i])), V2ScaleIII(d[last], B3(uPrime[i])))))); X[0] += V2Dot(&A[i][0], &tmp); X[1] += V2Dot(&A[i][1], &tmp); } /* Compute the determinants of C and X */ det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; det_C0_X = C[0][0] * X[1] - C[1][0] * X[0]; det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]; /* Finally, derive alpha values */ alpha_l = (det_C0_C1 < ZERO_TOLERANCE) ? 0.0 : det_X_C1 / det_C0_C1; alpha_r = (det_C0_C1 < ZERO_TOLERANCE) ? 0.0 : det_C0_X / det_C0_C1; /* If alpha negative, use the Wu/Barsky heuristic (see text) */ /* (if alpha is 0, you get coincident control points that lead to * divide by zero in any subsequent NewtonRaphsonRootFind() call. */ double segLength = V2DistanceBetween2Points(&d[last], &d[first]); double epsilon = 1.0e-6 * segLength; if (alpha_l < epsilon || alpha_r < epsilon) { /* fall back on standard (probably inaccurate) formula, and subdivide further if needed. */ double dist = segLength / 3.0; bezCurve[0] = d[first]; bezCurve[3] = d[last]; V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]); V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]); return (bezCurve); } /* First and last control points of the Bezier curve are */ /* positioned exactly at the first and last data points */ /* Control points 1 and 2 are positioned an alpha distance out */ /* on the tangent vectors, left and right, respectively */ bezCurve[0] = d[first]; bezCurve[3] = d[last]; V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]); V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]); return (bezCurve); }
/* * FitCubic : * Fit a Bezier curve to a (sub)set of digitized points */ static void FitCubic(Point2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error, BezierContour &bezContour) { BezierCurve bezCurve; /*Control points of fitted Bezier curve*/ double *u; /* Parameter values for point */ double *uPrime; /* Improved parameter values */ double maxError; /* Maximum fitting error */ int splitPoint; /* Point to split point set at */ int nPts; /* Number of points in subset */ double iterationError; /*Error below which you try iterating */ int maxIterations = 4; /* Max times to try iterating */ Vector2 tHatCenter; /* Unit tangent vector at splitPoint */ int i; iterationError = error * error; nPts = last - first + 1; /* Use heuristic if region only has two points in it */ if (nPts == 2) { double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0; bezCurve = (Point2 *)malloc(4 * sizeof(Point2)); bezCurve[0] = d[first]; bezCurve[3] = d[last]; V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]); V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]); DrawBezierCurve(3, bezCurve, bezContour); free((void *)bezCurve); return; } /* Parameterize points, and attempt to fit curve */ u = ChordLengthParameterize(d, first, last); bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2); /* Find max deviation of points to fitted curve */ maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint); if (maxError < error) { DrawBezierCurve(3, bezCurve, bezContour); free((void *)u); free((void *)bezCurve); return; } /* If error not too large, try some reparameterization */ /* and iteration */ if (maxError < iterationError) { for (i = 0; i < maxIterations; i++) { uPrime = Reparameterize(d, first, last, u, bezCurve); free((void *)bezCurve); bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2); maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, &splitPoint); if (maxError < error) { DrawBezierCurve(3, bezCurve, bezContour); free((void *)u); free((void *)bezCurve); free((void *)uPrime); return; } free((void *)u); u = uPrime; } } /* Fitting failed -- split at max error point and fit recursively */ free((void *)u); free((void *)bezCurve); tHatCenter = ComputeCenterTangent(d, splitPoint); FitCubic(d, first, splitPoint, tHat1, tHatCenter, error, bezContour); V2Negate(&tHatCenter); FitCubic(d, splitPoint, last, tHatCenter, tHat2, error, bezContour); }
/* * GenerateBezier : * Use least-squares method to find Bezier control points for region. * */ static BezierCurve GenerateBezier( Point2 *d, /* Array of digitized points */ int first, int last, /* Indices defining region */ double *uPrime, /* Parameter values for region */ Vector2 tHat1, Vector2 tHat2) /* Unit tangents at endpoints */ { int i; // Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */ int nPts; /* Number of pts in sub-curve */ double C[2][2]; /* Matrix C */ double X[2]; /* Matrix X */ double det_C0_C1, /* Determinants of matrices */ det_C0_X, det_X_C1; double alpha_l, /* Alpha values, left and right */ alpha_r; Vector2 tmp; /* Utility variable */ BezierCurve bezCurve; /* RETURN bezier curve ctl pts */ bezCurve = (Point2 *)malloc(4 * sizeof(Point2)); nPts = last - first + 1; Vector2 (*A)[2]; A = new Vector2[nPts][2]; /* Precomputed rhs for eqn */ /* Compute the A's */ for (i = 0; i < nPts; i++) { Vector2 v1, v2; v1 = tHat1; v2 = tHat2; V2Scale(&v1, B1(uPrime[i])); V2Scale(&v2, B2(uPrime[i])); A[i][0] = v1; A[i][1] = v2; } /* Create the C and X matrices */ C[0][0] = 0.0; C[0][1] = 0.0; C[1][0] = 0.0; C[1][1] = 0.0; X[0] = 0.0; X[1] = 0.0; for (i = 0; i < nPts; i++) { C[0][0] += V2Dot(&A[i][0], &A[i][0]); C[0][1] += V2Dot(&A[i][0], &A[i][1]); /* C[1][0] += V2Dot(&A[i][0], &A[i][1]);*/ C[1][0] = C[0][1]; C[1][1] += V2Dot(&A[i][1], &A[i][1]); tmp = V2SubII(d[first + i], V2AddII( V2ScaleIII(d[first], B0(uPrime[i])), V2AddII( V2ScaleIII(d[first], B1(uPrime[i])), V2AddII( V2ScaleIII(d[last], B2(uPrime[i])), V2ScaleIII(d[last], B3(uPrime[i])))))); X[0] += V2Dot(&A[i][0], &tmp); X[1] += V2Dot(&A[i][1], &tmp); } /* Compute the determinants of C and X */ det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; det_C0_X = C[0][0] * X[1] - C[0][1] * X[0]; det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]; /* Finally, derive alpha values */ if (det_C0_C1 == 0.0) { det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12; } alpha_l = det_X_C1 / det_C0_C1; alpha_r = det_C0_X / det_C0_C1; /* If alpha negative, use the Wu/Barsky heuristic (see text) */ if (alpha_l < 0.0 || alpha_r < 0.0) { double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0; bezCurve[0] = d[first]; bezCurve[3] = d[last]; V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]); V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]); delete[] A; return (bezCurve); } /* First and last control points of the Bezier curve are */ /* positioned exactly at the first and last data points */ /* Control points 1 and 2 are positioned an alpha distance out */ /* on the tangent vectors, left and right, respectively */ bezCurve[0] = d[first]; bezCurve[3] = d[last]; V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]); V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]); delete[] A; return (bezCurve); }
void CBCStroke::DrawHarryBrush(FCObjImage& img,BezierPressCurve& bezpCurve,BYTE alpha,float zoom) { double t,delt; t=0.0; int x1,y1,x2,y2; x1=y1=x2=y2=0; for(int i=0;i<=bezpCurve.degree;++i){ bezpCurve.bezCurve[i].x=zoom*(bezpCurve.bezCurve[i].x); bezpCurve.bezCurve[i].y=zoom*(bezpCurve.bezCurve[i].y); } float numpoint=0; if(bezpCurve.degree>=2){ numpoint=V2DistanceBetween2Points(&(bezpCurve.bezCurve[0]),&(bezpCurve.bezCurve[1])); for (int i =1; i <bezpCurve.degree; i++) { numpoint+=V2DistanceBetween2Points(&(bezpCurve.bezCurve[i]),&(bezpCurve.bezCurve[i+1])); } } numpoint=numpoint*2; if(numpoint<=0) return; delt=(double)1/numpoint; bezpCurve.numpoint=0; int count=0; TPosition tp[3]; std::vector<TPosition> pList; for(int i=0;i<=numpoint;++i){ Point2 p=CBCStroke::BezierII(bezpCurve.degree,bezpCurve.bezCurve,t); x1=p.x; y1=p.y; if(x1!=x2||y1!=y2){ PARAMER param; //CStrokeTransform::GenParamer(bezpCurve.uList,t,param); TPosition position; position.press=(param.press<1)?1:param.press; position.m_angle_z=param.m_angle_z; position.m_angle_xy=param.m_angle_xy; position.m_x=x1; position.m_y=y1; //m_disCurve. pList.push_back(position); //m_lpPaper->DrawSection(img,position,alpha); x2=x1; y2=y1; bezpCurve.numpoint++; } t+=delt; } int size=pList.size(); if(size<=3) return; std::vector<TPosition> pList2; int i=0; for(;i<size/2-1;++i) { pList2.push_back(pList[2*i]); } pList2.push_back(pList[size-1]); Vector2 v,v_cur,v_pre; v.x=pList2[1].m_x-pList2[0].m_x; v.y=pList2[1].m_y-pList2[0].m_y; V2MakePerpendicular(&v,&v_pre); int j=0; for(j=2;j<pList2.size();++j) { Point2 A,B,C; A.x=pList[j-2].m_x; A.y=pList[j-2].m_y; B.x=pList[j-1].m_x; B.y=pList[j-1].m_y; C.x=pList[j].m_x; C.y=pList[j].m_y; v_cur=AngleBisectors(A,B,C); m_lpPaper->DrawSection(img,pList2[j-2],v_pre,pList2[j-1],v_cur,alpha); v_pre=v_cur; } if(i<=2) return; v.x=pList2[j-1].m_x-pList2[j-2].m_x; v.y=pList2[j-1].m_y-pList2[j-2].m_y; V2MakePerpendicular(&v,&v_cur); m_lpPaper->DrawSection(img,pList2[j-2],v_pre,pList2[j-1],v_cur,alpha); }