CurveFitObject Class Reference

Fits bezier curves to a serious of coordinates. Call the constructor, Initialise and finally FitCurve to fit a bezier curve to the coords. More...

#include <fitcurve.h>

List of all members.

Public Member Functions

 CurveFitObject (Path *LongPath, double Error)
 Constructs a Curve Fitting Object and gives it some data that it will need during the fit.
 ~CurveFitObject ()
 Destroys the curve fitter when it is done, freeing any memory that was allocated in the Initialise() function.
BOOL Initialise (Path *CopyPath, INT32 NumPoints)
 Gets memory to store all the coords in and starts going through the path extracting the relavent points. It also calculates the distance along the path of each of the points it stores, which are needed extensivly when checking the accuracy of the fit. This function also empties the path object ready for the fitted version to be added.
void FitCurve ()
 Actually fits the curve and places the results back in the path object declared in the constructor. This function walks through all the data points trying to find cusps in the path and fits curves between them by calling the FitCubic member of the CurveFitObject.

Private Member Functions

 CC_DECLARE_MEMDUMP (CurveFitObject)
void FitCubic (INT32 FirstPoint, INT32 LastPoint, FitPoint Tangent1, FitPoint Tangent2, BOOL IsStartCusp=TRUE, BOOL IsEndCusp=TRUE)
 This function is recursive. It tries to fit a cubic function to the coordinates in the path between FirstPoint and LastPoint. It then compares this function with the actual coordinates to determine how good a fit it has found. If the fit is good it is added to the path object. If the fit is bad then it is split at the point where the fit is at its worst and FitCubic is called again for the left and right halves. Scope: private.
void GenerateBezier (INT32 FirstPoint, INT32 LastPoint, FitPoint Tangent1, FitPoint Tangent2, FitPoint *Bezier)
 This function supplies the maths to try and fit a cubic function to a set of points. It spends its time trying to come up with good lengths for the two tangents passed in to maximise the closeness of the fit. If it fails to come up with realistic results it simply sets the tangent lengths to be 1/3 of the distance between the start point and the end point. Scope: private.
FitPoint BezierPoint (FitPoint *Bez, double u)
 This function simply evaluates the bezier function for a given position and is used to help when determining how good a fit we have obtained Scope: private.
double CalcMaxError (INT32 FirstPoint, INT32 LastPoint, FitPoint *Bezier, INT32 *SplitPoint)
 Finds out how good a fit the bezier curve we have created is when compared with the data points Scope: private.
FitPoint LeftTangent (INT32 Start)
 Finds the Left tangent at the given point in the path Scope: private.
FitPoint RightTangent (INT32 End)
 Finds the Right tangent at the given point in the path Scope: private.
FitPoint CentreTangent (INT32 Centre)
 Finds the tangent at the centre of the path Scope: private.
double Bezier0 (double u)
double Bezier1 (double u)
double Bezier2 (double u)
double Bezier3 (double u)
void InsertBezier (FitPoint *Bezier, BOOL, BOOL)
 Adds the bezier curve to the path. If it is that last curve in the fitting (ie Depth is 0) then the rotate flag will not be set Scope: private.
void InsertLine (const DocCoord &Start, const DocCoord &End, FitPoint Tangent1, FitPoint Tangent2, BOOL, BOOL)
 Inserts a straight curve into the path. It keeps it as a curve so that the path will continue to look smooth after it is edited. If this is the last Path element in the fit, (ie Depth is zero) then the rotate flag will not be set. Scope: private.
void InsertStraightLine (const DocCoord &End)
 Inserts a straight Line into the path. This is used in cases where the Line segment must be kept as a straight line (ie by using Straight Line Mode of the FreeHand tool) Scope: private.

Private Attributes

PathLongPath
DocCoordPathArray
INT32 * LineArray
INT32 * Distances
double Error
INT32 TotalCoords
INT32 TotalStraightLines


Detailed Description

Fits bezier curves to a serious of coordinates. Call the constructor, Initialise and finally FitCurve to fit a bezier curve to the coords.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
22/9/94
See also:
FitPoint

Definition at line 182 of file fitcurve.h.


Constructor & Destructor Documentation

CurveFitObject::CurveFitObject Path ThePath,
double  MaxError
 

Constructs a Curve Fitting Object and gives it some data that it will need during the fit.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
ThePath - A Pointer to a path object that we are to simplify [INPUTS] MaxError - The Square of the distance that we are prepared to let the fitted path stray from the original data
See also:
CurveFitObject::Initialise

Definition at line 305 of file fitcurve.cpp.

00306 {
00307     // Make a note of info we have got
00308     LongPath = ThePath;
00309     Error = MaxError;
00310 
00311     // And set defaults to the rest
00312     Distances = NULL;
00313     PathArray = NULL;
00314     LineArray = NULL;
00315 
00316     TotalStraightLines = 0;
00317     TotalCoords = 0;
00318 }

CurveFitObject::~CurveFitObject  ) 
 

Destroys the curve fitter when it is done, freeing any memory that was allocated in the Initialise() function.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
See also:
CurveFitObject::Initialise

Definition at line 333 of file fitcurve.cpp.

00334 {
00335     if (Distances!=NULL)
00336         delete Distances;
00337 
00338     if (PathArray!=NULL)
00339         delete PathArray;
00340 
00341     if (LineArray!=NULL)
00342         delete LineArray;
00343 }


Member Function Documentation

double CurveFitObject::Bezier0 double  u  )  [inline, private]
 

Definition at line 217 of file fitcurve.h.

00217 { double t=1.0-u; return (t*t*t); }

double CurveFitObject::Bezier1 double  u  )  [inline, private]
 

Definition at line 218 of file fitcurve.h.

00218 { double t=1.0-u; return (3*u*t*t); }

double CurveFitObject::Bezier2 double  u  )  [inline, private]
 

Definition at line 219 of file fitcurve.h.

00219 { double t=1.0-u; return (3*u*u*t); }

double CurveFitObject::Bezier3 double  u  )  [inline, private]
 

Definition at line 220 of file fitcurve.h.

00220 { return (u*u*u); }

FitPoint CurveFitObject::BezierPoint FitPoint Bez,
double  u
[private]
 

This function simply evaluates the bezier function for a given position and is used to help when determining how good a fit we have obtained Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
Bez - The control points of a bezier curve [INPUTS] u - the normalised distance along the bezier that we are interested in
Returns:
The coord of the point that is a distance u into the bezier. for example, if u = 0.5 then the coord of the point half way along the bezier will be returned
See also:
CurveFitObject::CalcMaxError

Definition at line 808 of file fitcurve.cpp.

00809 {
00810     double OneMinus = 1.0-u;
00811     double uSquared = u*u;
00812     double OneMinusSquared = OneMinus*OneMinus;
00813 
00814     FitPoint Coord;
00815     Coord = Bez[0]*(OneMinusSquared*OneMinus);
00816     Coord = Coord + Bez[1]*(3.0*u*OneMinusSquared);
00817     Coord = Coord + Bez[2]*(3.0*uSquared*OneMinus);
00818     Coord = Coord + Bez[3]*(uSquared*u);
00819 
00820     return Coord;
00821 }

double CurveFitObject::CalcMaxError INT32  FirstPoint,
INT32  LastPoint,
FitPoint Bezier,
INT32 *  SplitPoint
[private]
 

Finds out how good a fit the bezier curve we have created is when compared with the data points Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
FirstPoint,LastPoint - The index at the start and end of the curve section [INPUTS] we have just fit Bezier - the control points of the bezier we have fitted to the points
SplitPoint - the point to split the curve at if the error is too great [OUTPUTS]
Returns:
The maximum distance between the bezier curve and the original data points

Definition at line 843 of file fitcurve.cpp.

00844 {
00845     double      Distance;
00846     double      MaxDist = 0.0;
00847     double      RTotalLength = 1.0/(Distances[LastPoint] - Distances[FirstPoint]);
00848     FitPoint    Point;
00849 
00850     // Start out by putting the split point in the middle of the curve segment
00851     INT32 NumPoints = LastPoint - FirstPoint + 1;
00852     *SplitPoint = NumPoints / 2;
00853     INT32 step = (NumPoints+ERROR_STEP) / ERROR_STEP;
00854     
00855     // Loop though the points, visiting a fixed number of them
00856     for (INT32 i=FirstPoint+1; i<LastPoint; i+=step)
00857     {
00858         // Calculate the offset at this point
00859         double Offset = Distances[i] - Distances[FirstPoint];
00860         Offset *= RTotalLength;
00861 
00862         // Calculate where the curve actually is and find the distance from where we want it
00863         FitPoint Coord = PathArray[i];
00864         Point = BezierPoint(Bezier, Offset);
00865         Distance = (Point - Coord).SquaredLength();
00866         if ( Distance >= MaxDist)
00867         {
00868             MaxDist = Distance;
00869             *SplitPoint = i;
00870         }
00871     }
00872     
00873     return MaxDist;
00874 }

CurveFitObject::CC_DECLARE_MEMDUMP CurveFitObject   )  [private]
 

FitPoint CurveFitObject::CentreTangent INT32  Centre  )  [private]
 

Finds the tangent at the centre of the path Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
Centre - the index of the split point in the path [INPUTS]
Returns:
The tangent at the point Centre

Definition at line 977 of file fitcurve.cpp.

00978 {
00979     DocCoord Left, Right;
00980     FitPoint CentreTang;
00981 
00982     // check for empty point array
00983     if (TotalCoords == 0)
00984     {
00985         CentreTang.x = 1;
00986         CentreTang.y = 0;
00987 
00988         return CentreTang;
00989     }
00990 
00991     // check for centre outside the array
00992     if ((Centre >= TotalCoords) || (Centre < 0))
00993         Centre = TotalCoords / 2;
00994 
00995     // Find out which point to look to
00996     INT32 Forward = Centre+2;
00997     if (Forward > TotalCoords-1)
00998         Forward = TotalCoords-1;
00999 
01000     // Find out which point to look to
01001     INT32 Backward = Centre-2;
01002     if (Backward < 0)
01003         Backward = 0;
01004 
01005     // Calc right tangent
01006     Left.x = PathArray[Backward].x - PathArray[Centre].x;
01007     Left.y = PathArray[Backward].y - PathArray[Centre].y;
01008 
01009     // Calc left tangent
01010     Right.x = PathArray[Centre].x - PathArray[Forward].x;
01011     Right.y = PathArray[Centre].y - PathArray[Forward].y;
01012 
01013     // Average to get the centre tangent
01014     CentreTang.x = (Left.x + Right.x) / 2.0;
01015     CentreTang.y = (Left.y + Right.y) / 2.0;
01016 
01017     // Make sure that is not of zero length
01018     if ((CentreTang.x==0) && (CentreTang.y==0))
01019     {
01020         TRACEALL( _T("Tangent was a zero length vector in the curve fitter (Cent)\n"));
01021         CentreTang.x = 1;
01022     }
01023 
01024     // return it
01025     return CentreTang;
01026 }

void CurveFitObject::FitCubic INT32  FirstPoint,
INT32  LastPoint,
FitPoint  Tangent1,
FitPoint  Tangent2,
BOOL  IsStartCusp = TRUE,
BOOL  IsEndCusp = TRUE
[private]
 

This function is recursive. It tries to fit a cubic function to the coordinates in the path between FirstPoint and LastPoint. It then compares this function with the actual coordinates to determine how good a fit it has found. If the fit is good it is added to the path object. If the fit is bad then it is split at the point where the fit is at its worst and FitCubic is called again for the left and right halves. Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
FirstPoint - the index of the coordinate in the path to start fitting from [INPUTS] LastPoint - the index of the coordinate in the path to stop fitting at Tangent1 - The tangent of the curve at the first point Tangent2 - the tangent of the curve at the last point IsStartCusp - TRUE if FirstPoint is next to a cusp IsEndCusp - TRUE of EndPoint is next to a cusp
See also:
CurveFitObject::GenerateBezier; CurveFitObject::CalcMaxError

Definition at line 612 of file fitcurve.cpp.

00614 {
00615     // Will need space for a Bezier curve
00616     FitPoint Bezier[4];
00617     INT32 NumPoints = LastPoint - FirstPoint + 1;
00618 
00619     // if this segment only has 2 points in it then do the special case
00620     if ( NumPoints == 2 )
00621     {
00622         InsertLine(PathArray[FirstPoint], PathArray[LastPoint], Tangent1, Tangent2, IsStartCusp, IsEndCusp);
00623         return;
00624     }
00625     
00626     // Due to a bug in the algorithm we also have to consider 3 points as a special case
00627     if ( NumPoints == 3 )
00628     {
00629         INT32 Distance = (Distances[LastPoint] - Distances[FirstPoint]) / 3;
00630         
00631         // store the end points
00632         Bezier[0] = PathArray[FirstPoint];
00633         Bezier[3] = PathArray[LastPoint];
00634         
00635         // calc the control points
00636         Bezier[1] = Bezier[0] + Tangent1.SetLength(Distance);
00637         Bezier[2] = Bezier[3] + Tangent2.SetLength(Distance);
00638 
00639         // add it to the path
00640         InsertBezier(Bezier, IsStartCusp, IsEndCusp);
00641         return;
00642     }
00643 
00644     // Create a Bezier curve from the segemnt and see if it is a good fit
00645     INT32 SplitPoint;
00646     GenerateBezier(FirstPoint, LastPoint, Tangent1, Tangent2, Bezier);
00647     double MaxError = CalcMaxError(FirstPoint, LastPoint, Bezier, &SplitPoint);
00648     
00649     if (MaxError < Error)
00650     {
00651         // The mapping was good, so output the curve segment
00652         InsertBezier(Bezier, IsStartCusp, IsEndCusp);
00653         return;
00654     }
00655     
00656     // fitting failed -- split at max error point and fit recursively
00657     FitPoint CentTangent = CentreTangent(SplitPoint);
00658     FitCubic(FirstPoint, SplitPoint, Tangent1, CentTangent, IsStartCusp, FALSE);
00659 
00660     CentTangent = -CentTangent;
00661     FitCubic(SplitPoint, LastPoint, CentTangent, Tangent2, FALSE, IsEndCusp);
00662 }

void CurveFitObject::FitCurve  ) 
 

Actually fits the curve and places the results back in the path object declared in the constructor. This function walks through all the data points trying to find cusps in the path and fits curves between them by calling the FitCubic member of the CurveFitObject.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
See also:
CurveFitObject::FitCubic

Definition at line 503 of file fitcurve.cpp.

00504 {
00505     FitPoint Tangent1, Tangent2;
00506     double Angle1, Angle2;
00507     INT32 Start = 0;
00508     INT32 StraightLinePos = 0;
00509 
00510     for (INT32 i=1; i<TotalCoords-1; i++)
00511     {
00512         if ((TotalStraightLines>0) && (i==LineArray[StraightLinePos]))
00513         {
00514             // if we have a section to the path that needs fitting before we do this then do it
00515             if (Start != (i-1))
00516             {
00517                 // calculate the tangents off the end of the path
00518                 Tangent1 = LeftTangent(Start);
00519                 Tangent2 = RightTangent(i-1);
00520 
00521                 // Fit a curve up to the straight line section
00522                 FitCubic(Start, i-1, Tangent1, Tangent2);
00523             }
00524             
00525             // And draw in the straight line section
00526             InsertStraightLine(PathArray[i]);
00527             StraightLinePos++;
00528             Start = i;
00529         }
00530         else
00531         {
00532             // Go find the angle between a group of points
00533             Angle1 = atan2((double)PathArray[i].y-PathArray[i-1].y, (double)PathArray[i].x-PathArray[i-1].x);
00534             Angle2 = atan2((double)PathArray[i+1].y-PathArray[i].y, (double)PathArray[i+1].x-PathArray[i].x);
00535         
00536             // Get them in a sensible range
00537             if (Angle1 < -PI)   Angle1 += 2*PI;
00538             if (Angle1 > PI)    Angle1 -= 2*PI;
00539             if (Angle2 < -PI)   Angle2 += 2*PI;
00540             if (Angle2 > PI)    Angle2 -= 2*PI;
00541         
00542             // See if this point is a cusp in the curve
00543             if ((fabs(Angle2-Angle1) > (PI/2)) && (fabs(Angle2-Angle1) <= PI))
00544             {
00545                 // calculate the tangents off the end of the path
00546                 Tangent1 = LeftTangent(Start);
00547                 Tangent2 = RightTangent(i);
00548 
00549                 // and do a load of maths that will hopefully fit a nice curve on it
00550                 FitCubic(Start, i, Tangent1, Tangent2);
00551                 Start = i;
00552             }
00553         }
00554     }
00555 
00556 
00557     INT32 End = TotalCoords-1;
00558     if ((TotalStraightLines>0) && (End==LineArray[StraightLinePos]))
00559     {
00560         // if we have a section to the path that needs fitting before we do this then do it
00561         if (Start != (End-1))
00562         {
00563             // calculate the tangents off the end of the path
00564             Tangent1 = LeftTangent(Start);
00565             Tangent2 = RightTangent(End-1);
00566 
00567             // Fit a curve up to the straight line section
00568             FitCubic(Start, End-1, Tangent1, Tangent2);
00569         }
00570         
00571         // And draw in the straight line section
00572         InsertStraightLine(PathArray[End]);
00573     }
00574     else
00575     {
00576         // Just have to fit a curve from the last cusp to the end of the path
00577         Tangent1 = LeftTangent(Start);
00578         Tangent2 = RightTangent(End);
00579     
00580         // and do a load of maths that will hopefully fit a nice curve on it
00581         FitCubic(Start, End, Tangent1, Tangent2);
00582     }
00583 }

void CurveFitObject::GenerateBezier INT32  FirstPoint,
INT32  LastPoint,
FitPoint  Tangent1,
FitPoint  Tangent2,
FitPoint Bezier
[private]
 

This function supplies the maths to try and fit a cubic function to a set of points. It spends its time trying to come up with good lengths for the two tangents passed in to maximise the closeness of the fit. If it fails to come up with realistic results it simply sets the tangent lengths to be 1/3 of the distance between the start point and the end point. Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
FirstPoint - the index of the coordinate in the path to start fitting from [INPUTS] LastPoint - the index of the coordinate in the path to stop fitting at Tangent1 - The tangent of the curve at the first point Tangent2 - the tangent of the curve at the last point
Bezier - A pointer to a Bezier Curve [OUTPUTS]

Definition at line 688 of file fitcurve.cpp.

00690 {
00691     INT32 NumPoints = LastPoint - FirstPoint + 1;
00692     
00693     // Build a matrix type of thing that contains the tangents scaled by the offsets
00694     FitPoint A[STEP_SIZE+1][2];         //  Vector2 (*A)[2] = new Vector2[NumPoints+1][2];
00695     double   Offsets[STEP_SIZE+1];
00696 
00697     INT32 step = (NumPoints+STEP_SIZE) / STEP_SIZE;
00698     INT32 i, pos = 0;
00699 
00700     // Chord length parameterisation
00701     const INT32 DistToEnd = Distances[LastPoint] - Distances[FirstPoint];
00702     for (i=FirstPoint; i<LastPoint+1; i+=step)
00703     {
00704         Offsets[pos] = Distances[i] - Distances[FirstPoint];
00705         Offsets[pos] /= DistToEnd;
00706 
00707         // Fill the matrix A
00708         A[pos][0] = Tangent1.SetLength( Bezier1(Offsets[pos]) );
00709         A[pos][1] = Tangent2.SetLength( Bezier2(Offsets[pos]) );
00710 
00711         // Move to the next element in the path
00712         pos++;
00713     }
00714 
00715     // For a detailed description of the maths used here, please see Graphics Gems I
00716     // I have made some changes to the basic algorithm used there - the main one is
00717     // that this block of maths is only performed on a small selection of the points
00718     // in the data set, where-as the one in the book uses all the points
00719     double  C[2][2];
00720     double  X[2];
00721     
00722     C[0][0] = 0.0;
00723     C[0][1] = 0.0;
00724     C[1][0] = 0.0;
00725     C[1][1] = 0.0;
00726     X[0]    = 0.0;
00727     X[1]    = 0.0;
00728     
00729     FitPoint FirstCoord = PathArray[FirstPoint];
00730     FitPoint LastCoord  = PathArray[LastPoint];
00731     FitPoint ThisCoord, Combo;
00732 
00733     pos = 0;
00734     for (i=0; i<NumPoints; i+=step)
00735     {
00736         C[0][0] += A[pos][0].SquaredLength();
00737         C[0][1] += A[pos][0].Dot(A[pos][1]);
00738         // Point C[1][0] is the same as C[0][1] and is set outside the loop below
00739         C[1][1] += A[pos][1].SquaredLength();
00740         
00741         // Go ahead and build a vector based on the bezier functions
00742         ThisCoord = PathArray[FirstPoint+i];
00743         Combo = ThisCoord - ((FirstCoord * Bezier0(Offsets[pos]))
00744                             + (FirstCoord * Bezier1(Offsets[pos]))
00745                             + (LastCoord  * Bezier2(Offsets[pos]))
00746                             + (LastCoord  * Bezier3(Offsets[pos])));
00747 
00748         // Combine it with the other points
00749         X[0] += A[pos][0].Dot( Combo );
00750         X[1] += A[pos][1].Dot( Combo );
00751 
00752         pos++;
00753     }
00754 
00755     // This point in the matrix is the same, so we do not need to do it in the loop
00756     C[1][0] = C[0][1];
00757     
00758     // calc the determinants of C and X
00759     double det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
00760     double det_C0_X  = C[0][0] * X[1]    - C[0][1] * X[0];
00761     double det_X_C1  = X[0]    * C[1][1] - X[1]    * C[0][1];
00762     
00763     // finally, derive the length of the ideal tangents
00764     if (det_C0_C1 == 0.0)
00765         det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12;   // oh err, whats it up to here then!
00766     
00767     double AlphaLeft  = det_X_C1 / det_C0_C1;
00768     double AlphaRight = det_C0_X / det_C0_C1;
00769     
00770     Bezier[0] = PathArray[FirstPoint];
00771     Bezier[3] = PathArray[LastPoint];
00772 
00773     // if alpha negative, the set the tangent length to a third of the distance between
00774     // the start and the end points of the curve segment    
00775     if ( AlphaLeft < 0.0 || AlphaRight < 0.0)
00776     {
00777         INT32 Distance = (Distances[LastPoint] - Distances[FirstPoint]) / 3;
00778         
00779         Bezier[1] = Bezier[0] + Tangent1.SetLength(Distance);
00780         Bezier[2] = Bezier[3] + Tangent2.SetLength(Distance);
00781     }
00782     else
00783     {   
00784         Bezier[1] = Bezier[0] + Tangent1.SetLength(AlphaLeft);
00785         Bezier[2] = Bezier[3] + Tangent2.SetLength(AlphaRight);
00786     }
00787 }

BOOL CurveFitObject::Initialise Path CopyPath,
INT32  NumPoints
 

Gets memory to store all the coords in and starts going through the path extracting the relavent points. It also calculates the distance along the path of each of the points it stores, which are needed extensivly when checking the accuracy of the fit. This function also empties the path object ready for the fitted version to be added.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
CopyPath - The path to copy the MoveTo Data from [INPUTS] NumPoints - the number of points in the path object
Returns:
TRUE if the CurveFitter was properly initialised or FALSE if it failed to get the memory that it needs

Definition at line 365 of file fitcurve.cpp.

00366 {
00367     // Here we must try and get some memory for the path array
00368     PathArray = new DocCoord[NumPoints];
00369     if (PathArray==NULL)
00370         return FALSE;
00371 
00372     // copy the data out of the path and into the array. Only copy points of interest
00373     CopyPath->FindStartOfPath();
00374     DocCoord* Coords = CopyPath->GetCoordArray();
00375 
00376     // Deal with the flags - We have to look for Spare1 being true, meaning that the previous
00377     // Lineto was meant to stay as a straight line
00378     PathFlags* Flags = CopyPath->GetFlagArray();
00379     TotalStraightLines = 0;
00380     for (INT32 i=0; i<NumPoints; i++)
00381     {
00382         if (Flags[i].Spare1==TRUE)
00383             TotalStraightLines++;
00384     }
00385 
00386     // Get some memory to store the positions of the line breaks in
00387     if (TotalStraightLines>0)
00388     {
00389         LineArray = new INT32[TotalStraightLines];
00390         if (LineArray==NULL)
00391         {
00392             delete PathArray;
00393             PathArray = NULL;
00394             return FALSE;
00395         }
00396     }
00397 
00398     // copy the MoveTo out of the path and into our array
00399     PathArray[0].x = Coords[0].x;
00400     PathArray[0].y = Coords[0].y;
00401 
00402     INT32 IncludePoint = 1;
00403     INT32 StraightLinePos = 0;
00404     for (INT32 i=1; i<NumPoints; i++)
00405     {
00406         // If this is one of the straight line bits, then make a note of its position
00407         if (Flags[i].Spare1==TRUE)
00408         {
00409             LineArray[StraightLinePos] = IncludePoint;
00410             StraightLinePos++;
00411         }
00412 
00413         // Check to see if this coordinate is really needed (last point is always needed)
00414         if ((Coords[i].x != PathArray[IncludePoint-1].x) || (Coords[i].y != PathArray[IncludePoint-1].y) &&
00415             (i!=NumPoints-1))
00416         {
00417             // This point is not the same as the one before, so add it into the array
00418             PathArray[IncludePoint].x = Coords[i].x;
00419             PathArray[IncludePoint].y = Coords[i].y;
00420 
00421             IncludePoint++;
00422         }
00423     }
00424 
00425     // Add the last point in the track data to the path array if it is not already there
00426     if ((PathArray[IncludePoint-1].x != Coords[NumPoints-1].x) ||
00427         (PathArray[IncludePoint-1].y != Coords[NumPoints-1].y))
00428     {
00429         PathArray[IncludePoint].x = Coords[NumPoints-1].x;
00430         PathArray[IncludePoint].y = Coords[NumPoints-1].y;
00431         IncludePoint++;
00432     }
00433 
00434     // increment the Include count (as we have just added a point to the array) and then
00435     // set the true number of points properly.
00436     NumPoints = IncludePoint;
00437     if (NumPoints<2)
00438     {
00439         delete PathArray;
00440         delete LineArray;
00441         PathArray = NULL;
00442         LineArray = NULL;
00443         return FALSE;
00444     }
00445 
00446     // Build an array of the distances along the path
00447     Distances = new INT32[NumPoints];
00448     if (Distances==NULL)
00449     {
00450         delete PathArray;
00451         delete LineArray;
00452         PathArray = NULL;
00453         LineArray = NULL;
00454         return FALSE;
00455     }
00456 
00457     Distances[0] = 0;
00458     INT32 dx, dy, min;
00459     for (INT32 i=1; i<NumPoints; i++)
00460     {
00461         // This is doing an approximation to a Square Root
00462         // It is about 250 times faster on a machine without FPU
00463 
00464         // find the difference between the last 2 points
00465         dx = abs(PathArray[i].x - PathArray[i-1].x);
00466         dy = abs(PathArray[i].y - PathArray[i-1].y);
00467 
00468         // Find out half the smallest of dx and dy
00469         if (dx>dy)
00470             min = dy>>1;
00471         else
00472             min = dx>>1;
00473 
00474         Distances[i] = Distances[i-1] + dx + dy - min;
00475     }
00476 
00477     // Now we can delete the Path Data in the path we are to put the smoothed path in
00478     LongPath->ClearPath();
00479     LongPath->FindStartOfPath();
00480     LongPath->InsertMoveTo(PathArray[0]);
00481 
00482     // Store the total number of coords in the array for future reference
00483     TotalCoords = NumPoints;
00484 
00485     return TRUE;
00486 }

void CurveFitObject::InsertBezier FitPoint Bezier,
BOOL  IsStartCusp,
BOOL  IsEndCusp
[private]
 

Adds the bezier curve to the path. If it is that last curve in the fitting (ie Depth is 0) then the rotate flag will not be set Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
Bezier - the control points of the bezier curve to add to the path [INPUTS] IsStartCusp - TRUE if the start of this bezier is at a cusp IsEndCusp - TRUE if the End of this bezier is at a cusp

Definition at line 1045 of file fitcurve.cpp.

01046 {
01047     // Prepare some flags
01048     PathFlags Flags;
01049     Flags.IsSelected = FALSE;
01050     Flags.IsSmooth = FALSE;
01051     Flags.IsRotate = TRUE;
01052 
01053     // Add this Bezier curve into the path
01054     LongPath->InsertCurveTo( DocCoord( (INT32)Bezier[1].x, (INT32)Bezier[1].y),
01055                              DocCoord( (INT32)Bezier[2].x, (INT32)Bezier[2].y),
01056                              DocCoord( (INT32)Bezier[3].x, (INT32)Bezier[3].y), &Flags);
01057 
01058     // Deal with cusps
01059     if (IsStartCusp || IsEndCusp)
01060     {
01061         // Go find out about the path
01062         PathFlags* AllFlags = LongPath->GetFlagArray();
01063         INT32 NumCoords = LongPath->GetNumCoords();
01064 
01065         if (IsStartCusp)
01066         {
01067             // Patch up the flags of the bits near that start
01068             AllFlags[NumCoords-3].IsRotate = FALSE;
01069         }
01070     
01071         if (IsEndCusp)
01072         {
01073             // Patch up the flags of the bits near that end
01074             AllFlags[NumCoords-2].IsRotate = FALSE;
01075             AllFlags[NumCoords-1].IsRotate = FALSE;
01076         }
01077     }
01078 }

void CurveFitObject::InsertLine const DocCoord Start,
const DocCoord End,
FitPoint  Tangent1,
FitPoint  Tangent2,
BOOL  IsStartCusp,
BOOL  IsEndCusp
[private]
 

Inserts a straight curve into the path. It keeps it as a curve so that the path will continue to look smooth after it is edited. If this is the last Path element in the fit, (ie Depth is zero) then the rotate flag will not be set. Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
Start - the coord of the start point of the line [INPUTS] End - the coord of the end point of the line Tangent1, Tangent2 - The tangents to the curve at the start and end points IsStartCusp - TRUE if the start of this bezier is at a cusp IsEndCusp - TRUE if the End of this bezier is at a cusp

Definition at line 1102 of file fitcurve.cpp.

01104 {
01105     // Prepare some flags
01106     PathFlags Flags;
01107     Flags.IsSelected = FALSE;
01108     Flags.IsSmooth = FALSE;
01109     Flags.IsRotate = TRUE;
01110 
01111     // Find out a third of the distance between the two points
01112     FitPoint StartPos(Start);
01113     FitPoint EndPos(End);
01114     FitPoint DistanceVect = EndPos - StartPos;
01115     INT32 Length = (INT32)DistanceVect.Length() / 3;
01116 
01117     // Make the tangents the right length
01118     Tangent1 = Tangent1.SetLength(Length);
01119     Tangent2 = Tangent2.SetLength(Length);
01120 
01121     // Work out the position of the control points
01122     StartPos = StartPos + Tangent1;
01123     EndPos = EndPos + Tangent2;
01124 
01125     // Add the line to the curve
01126     LongPath->InsertCurveTo( DocCoord( (INT32)StartPos.x, (INT32)StartPos.y ), 
01127                              DocCoord( (INT32)EndPos.x, (INT32)EndPos.y ),
01128                              End, &Flags);  
01129 
01130     // Deal with cusps
01131     if (IsStartCusp || IsEndCusp)
01132     {
01133         // Go find out about the path
01134         PathFlags* AllFlags = LongPath->GetFlagArray();
01135         INT32 NumCoords = LongPath->GetNumCoords();
01136 
01137         if (IsStartCusp)
01138         {
01139             // Patch up the flags of the bits near that start
01140             AllFlags[NumCoords-3].IsRotate = FALSE;
01141         }
01142     
01143         if (IsEndCusp)
01144         {
01145             // Patch up the flags of the bits near that end
01146             AllFlags[NumCoords-2].IsRotate = FALSE;
01147             AllFlags[NumCoords-1].IsRotate = FALSE;
01148         }
01149     }
01150 }

void CurveFitObject::InsertStraightLine const DocCoord End  )  [private]
 

Inserts a straight Line into the path. This is used in cases where the Line segment must be kept as a straight line (ie by using Straight Line Mode of the FreeHand tool) Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
25/4/94
Parameters:
End - the coord of the end point of the line [INPUTS]

Definition at line 1169 of file fitcurve.cpp.

01170 {
01171     // Prepare some flags
01172     PathFlags Flags;
01173     Flags.IsSelected = FALSE;
01174     Flags.IsRotate = FALSE;
01175     Flags.IsSmooth = FALSE;
01176 
01177     // Insert the line
01178     LongPath->InsertLineTo(End, &Flags);    
01179 }

FitPoint CurveFitObject::LeftTangent INT32  Start  )  [private]
 

Finds the Left tangent at the given point in the path Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
Start - the index of the point at the start of the segment to fit [INPUTS]
Returns:
The tangent at the point Start

Definition at line 890 of file fitcurve.cpp.

00891 {
00892     FitPoint Tangent;
00893 
00894     // check for empty point array
00895     if (TotalCoords == 0)
00896     {
00897         Tangent.x = 1;
00898         Tangent.y = 0;
00899 
00900         return Tangent;
00901     }
00902     
00903     // check for start outside the array
00904     if ((Start >= TotalCoords) || (Start < 0))
00905         Start = TotalCoords / 2;
00906 
00907     // Find out which point to look to
00908     INT32 Forward = Start+2;
00909     if (Forward > TotalCoords-1)
00910         Forward = TotalCoords-1;
00911 
00912     // Calc the tangent from the left of the curve segment
00913     Tangent.x = PathArray[Forward].x - PathArray[Start].x;
00914     Tangent.y = PathArray[Forward].y - PathArray[Start].y;
00915 
00916     // Make sure that is not of zero length
00917     if ((Tangent.x==0) && (Tangent.y==0))
00918     {
00919         TRACEALL( _T("Tangent was a zero length vector in the curve fitter (left)\n"));
00920         Tangent.x = 1;
00921     }
00922     
00923     return Tangent;
00924 }

FitPoint CurveFitObject::RightTangent INT32  End  )  [private]
 

Finds the Right tangent at the given point in the path Scope: private.

Author:
Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
Date:
7/3/94
Parameters:
End - the index of the point at the end of the segment to fit [INPUTS]
Returns:
The tangent at the point End

Definition at line 940 of file fitcurve.cpp.

00941 {
00942     FitPoint Tangent;
00943 
00944     // Find out which point to look to
00945     INT32 Backward = End-2;
00946     if (Backward<0)
00947         Backward = 0;
00948 
00949     Tangent.x = PathArray[Backward].x - PathArray[End].x;
00950     Tangent.y = PathArray[Backward].y - PathArray[End].y;
00951 
00952     // Make sure that is not of zero length
00953     if ((Tangent.x==0) && (Tangent.y==0))
00954     {
00955         TRACEALL( _T("Tangent was a zero length vector in the curve fitter (Right)\n"));
00956         Tangent.x = -1;
00957     }
00958 
00959     return Tangent;
00960 }


Member Data Documentation

INT32* CurveFitObject::Distances [private]
 

Definition at line 236 of file fitcurve.h.

double CurveFitObject::Error [private]
 

Definition at line 240 of file fitcurve.h.

INT32* CurveFitObject::LineArray [private]
 

Definition at line 233 of file fitcurve.h.

Path* CurveFitObject::LongPath [private]
 

Definition at line 231 of file fitcurve.h.

DocCoord* CurveFitObject::PathArray [private]
 

Definition at line 232 of file fitcurve.h.

INT32 CurveFitObject::TotalCoords [private]
 

Definition at line 243 of file fitcurve.h.

INT32 CurveFitObject::TotalStraightLines [private]
 

Definition at line 244 of file fitcurve.h.


The documentation for this class was generated from the following files:
Generated on Sat Nov 10 03:53:19 2007 for Camelot by  doxygen 1.4.4