20#include <karbon_part.h>
21#include <karbon_view.h>
22#include <core/vcolor.h>
23#include <core/vcomposite.h>
24#include <core/vfill.h>
25#include <core/vstroke.h>
26#include <core/vglobal.h>
27#include <render/vpainter.h>
28#include <render/vpainterfactory.h>
29#include <commands/vshapecmd.h>
48 FitVector(KoPoint &p){
58 FitVector(KoPoint &a,KoPoint &b){
76 double len = length();
83 double dot(FitVector &v){
84 return ((m_X*v.m_X)+(m_Y*v.m_Y));
88 return (
double) sqrt(m_X*m_X+m_Y*m_Y);
91 KoPoint operator+(KoPoint &p){
92 KoPoint b(p.x()+m_X,p.y()+m_Y);
100double distance(KoPoint *p1,KoPoint *p2){
101 double dx = (p1->x()-p2->x());
102 double dy = (p1->y()-p2->y());
103 return sqrt( dx*dx + dy*dy );
107FitVector ComputeLeftTangent(TQPtrList<KoPoint> &points,
int end){
108 FitVector tHat1(*points.at(end+1),*points.at(end));
115FitVector ComputeRightTangent(TQPtrList<KoPoint> &points,
int end){
116 FitVector tHat1(*points.at(end-1),*points.at(end));
128static double *ChordLengthParameterize(TQPtrList<KoPoint> points,
int first,
int last)
133 u =
new double[(last-first+1)];
136 for (i = first+1; i <= last; i++) {
137 u[i-first] = u[i-first-1] +
138 distance(points.at(i), points.at(i-1));
141 for (i = first + 1; i <= last; i++) {
142 u[i-first] = u[i-first] / u[last-first];
148static FitVector VectorAdd(FitVector a,FitVector b)
151 c.m_X = a.m_X + b.m_X; c.m_Y = a.m_Y + b.m_Y;
154static FitVector VectorScale(FitVector v,
double s)
157 result.m_X = v.m_X * s; result.m_Y = v.m_Y * s;
161static FitVector VectorSub(FitVector a,FitVector b)
164 c.m_X = a.m_X - b.m_X; c.m_Y = a.m_Y - b.m_Y;
168static FitVector ComputeCenterTangent(TQPtrList<KoPoint> points,
int center)
170 FitVector V1, V2, tHatCenter;
172 FitVector cpointb = *points.at(center-1);
173 FitVector cpoint = *points.at(center);
174 FitVector cpointa = *points.at(center+1);
176 V1 = VectorSub(cpointb,cpoint);
177 V2 = VectorSub(cpoint,cpointa);
178 tHatCenter.m_X= ((V1.m_X + V2.m_X)/2.0);
179 tHatCenter.m_Y= ((V1.m_Y + V2.m_Y)/2.0);
180 tHatCenter.normalize();
188static double B0(
double u)
190 double tmp = 1.0 - u;
191 return (tmp * tmp * tmp);
195static double B1(
double u)
197 double tmp = 1.0 - u;
198 return (3 * u * (tmp * tmp));
201static double B2(
double u)
203 double tmp = 1.0 - u;
204 return (3 * u * u * tmp);
207static double B3(
double u)
217KoPoint* GenerateBezier(TQPtrList<KoPoint> &points,
int first,
int last,
double *uPrime,FitVector tHat1,FitVector tHat2)
220 FitVector A[MAXPOINTS][2];
232 curve =
new KoPoint[4];
233 nPts = last - first + 1;
237 for (i = 0; i < nPts; i++) {
241 v1.scale(B1(uPrime[i]));
242 v2.scale(B2(uPrime[i]));
255 for (i = 0; i < nPts; i++) {
256 C[0][0] += (A[i][0]).dot(A[i][0]);
257 C[0][1] += A[i][0].dot(A[i][1]);
260 C[1][1] += A[i][1].dot(A[i][1]);
262 FitVector vfirstp1(*points.at(first+i));
263 FitVector vfirst(*points.at(first));
264 FitVector vlast(*points.at(last));
266 tmp = VectorSub(vfirstp1,
268 VectorScale(vfirst, B0(uPrime[i])),
270 VectorScale(vfirst, B1(uPrime[i])),
272 VectorScale(vlast, B2(uPrime[i])),
273 VectorScale(vlast, B3(uPrime[i])) ))));
276 X[0] += A[i][0].dot(tmp);
277 X[1] += A[i][1].dot(tmp);
281 det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
282 det_C0_X = C[0][0] * X[1] - C[0][1] * X[0];
283 det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
286 if (det_C0_C1 == 0.0) {
287 det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12;
289 alpha_l = det_X_C1 / det_C0_C1;
290 alpha_r = det_C0_X / det_C0_C1;
296 if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) {
297 double dist = distance(points.at(last),points.at(first)) /
300 curve[0] = *points.at(first);
301 curve[3] = *points.at(last);
306 curve[1] = tHat1 + curve[0];
307 curve[2] = tHat2 + curve[3];
315 curve[0] = *points.at(first);
316 curve[3] = *points.at(last);
318 tHat1.scale(alpha_l);
319 tHat2.scale(alpha_r);
321 curve[1] = tHat1 + curve[0];
322 curve[2] = tHat2 + curve[3];
332static KoPoint BezierII(
int degree,KoPoint *V,
double t)
338 Vtemp =
new KoPoint[degree+1];
340 for (i = 0; i <= degree; i++) {
345 for (i = 1; i <= degree; i++) {
346 for (j = 0; j <= degree-i; j++) {
347 Vtemp[j].setX((1.0 - t) * Vtemp[j].x() + t * Vtemp[j+1].x());
348 Vtemp[j].setY((1.0 - t) * Vtemp[j].y() + t * Vtemp[j+1].y());
362static double ComputeMaxError(TQPtrList<KoPoint> points,
int first,
int last,KoPoint *curve,
double *u,
int *splitPoint)
370 *splitPoint = (last - first + 1)/2;
372 for (i = first + 1; i < last; i++) {
373 P = BezierII(3, curve, u[i-first]);
374 v = VectorSub(P, *points.at(i));
376 if (dist >= maxDist) {
389static double NewtonRaphsonRootFind(KoPoint *Q,KoPoint P,
double u)
391 double numerator, denominator;
392 KoPoint Q1[3], Q2[2];
393 KoPoint TQ_u, Q1_u, Q2_u;
398 TQ_u = BezierII(3,Q, u);
401 for (i = 0; i <= 2; i++) {
402 Q1[i].setX((Q[i+1].x() - Q[i].x()) * 3.0);
403 Q1[i].setY((Q[i+1].y() - Q[i].y()) * 3.0);
407 for (i = 0; i <= 1; i++) {
408 Q2[i].setX((Q1[i+1].x() - Q1[i].x()) * 2.0);
409 Q2[i].setY((Q1[i+1].y() - Q1[i].y()) * 2.0);
413 Q1_u = BezierII(2, Q1, u);
414 Q2_u = BezierII(1, Q2, u);
417 numerator = (TQ_u.x() - P.x()) * (Q1_u.x()) + (TQ_u.y() - P.y()) * (Q1_u.y());
418 denominator = (Q1_u.x()) * (Q1_u.x()) + (Q1_u.y()) * (Q1_u.y()) +
419 (TQ_u.x() - P.x()) * (Q2_u.x()) + (TQ_u.y() - P.y()) * (Q2_u.y());
422 uPrime = u - (numerator/denominator);
432static double *Reparameterize(TQPtrList<KoPoint> points,
int first,
int last,
double *u,KoPoint *curve)
434 int nPts = last-first+1;
438 uPrime =
new double[nPts];
439 for (i = first; i <= last; i++) {
440 uPrime[i-first] = NewtonRaphsonRootFind(curve, *points.at(i), u[i-
446KoPoint *FitCubic(TQPtrList<KoPoint> &points,
int first,
int last,FitVector tHat1,FitVector tHat2,
float error,
int &width){
452 double iterationError;
454 FitVector tHatCenter;
461 iterationError=error*error;
465 double dist = distance(points.at(last), points.at(first)) / 3.0;
467 curve =
new KoPoint[4];
469 curve[0] = *points.at(first);
470 curve[3] = *points.at(last);
475 curve[1] = tHat1 + curve[0];
476 curve[2] = tHat2 + curve[3];
483 u = ChordLengthParameterize(points, first, last);
484 curve = GenerateBezier(points, first, last, u, tHat1, tHat2);
488 maxError = ComputeMaxError(points, first, last, curve, u, &splitPoint);
489 if (maxError < error) {
498 if (maxError < iterationError) {
499 for (i = 0; i < maxIterations; i++) {
500 uPrime = Reparameterize(points, first, last, u, curve);
501 curve = GenerateBezier(points, first, last, uPrime, tHat1, tHat2);
502 maxError = ComputeMaxError(points, first, last,
503 curve, uPrime, &splitPoint);
504 if (maxError < error) {
517 tHatCenter = ComputeCenterTangent(points, splitPoint);
520 KoPoint *cu1=NULL, *cu2=NULL;
521 cu1 = FitCubic(points, first, splitPoint, tHat1, tHatCenter, error,w1);
524 cu2 = FitCubic(points, splitPoint, last, tHatCenter, tHat2, error,w2);
526 KoPoint *newcurve =
new KoPoint[w1+w2];
527 for(
int i=0;i<w1;i++){
530 for(
int i=0;i<w2;i++){
531 newcurve[i+w1]=cu2[i];
541VPath *bezierFit(TQPtrList<KoPoint> &points,
float error){
542 FitVector tHat1, tHat2;
544 tHat1 = ComputeLeftTangent(points,0);
545 tHat2 = ComputeRightTangent(points,points.count()-1);
549 curve = FitCubic(points,0,points.count()-1,tHat1,tHat2,error,width);
554 path->moveTo(curve[0]);
555 path->curveTo(curve[1],curve[2],curve[3]);
556 for(
int i=4;i<width;i+=4){
557 path->curveTo(curve[i+1],curve[i+2],curve[i+3]);
A composite path consists of one or many subpaths.