|
|
/**************************************************************************\
* * Copyright (c) 1998 Microsoft Corporation * * Module Name: * * XBezier.hpp * * Abstract: * * Interface of GpXBezier and its DDA classes * * Revision History: * * 11/05/1999 ikkof * Created it. * \**************************************************************************/
#ifndef _XBEZIER_HPP
#define _XBEZIER_HPP
#define FLATNESS_LIMIT 0.25
#define DISTANCE_LIMIT 2.0
#define BZ_BUFF_SIZE 32
class GpXPoints { friend class GpXPath; friend class GpXBezier;
public:
INT Dimension; INT Count; // Number of Points
REALD* Data;
protected: BOOL IsDataAllocated;
public:
GpXPoints() { Initialize(); }
// When XPoints is created from a given data with copyData = FALSE,
// the caller is responsible for deleting the data after XPoints is no longer
// used.
GpXPoints(REALD* data, INT dimension, INT count, BOOL copyData = TRUE) { Initialize(); SetData(data, dimension, count, copyData); }
GpXPoints(GpPointF* points, INT count) { Initialize();
if(points && count > 0) { Data = (REALD*) GpMalloc(2*count*sizeof(REALD)); if(Data) { INT i = 0, j = 0;
while(j < count) { Data[i++] = points[j].X; Data[i++] = points[j].Y; j++; } Dimension = 2; Count = count; IsDataAllocated = TRUE; } } }
GpXPoints(GpPointD* points, INT count) { Initialize();
if(points && count > 0) { Data = (REALD*) GpMalloc(2*count*sizeof(REALD)); if(Data) { INT i = 0, j = 0;
while(j < count) { Data[i++] = points[j].X; Data[i++] = points[j].Y; j++; } Dimension = 2; Count = count; IsDataAllocated = TRUE; } } }
REALD* GetData() {return Data;}
// When XPoints is created from a given data with copyData = FALSE,
// the caller is responsible for deleting the data after XPoints is no longer
// used.
GpStatus SetData(REALD* data, INT dimension, INT count, BOOL copyData = TRUE) { GpStatus status = Ok;
if(data && dimension > 0 || count > 0) { REALD* newData = NULL;
if(copyData) { INT totalSize = dimension*count*sizeof(REALD); if(IsDataAllocated) newData = (REALD*) GpRealloc(Data, totalSize); else newData = (REALD*) GpMalloc(totalSize);
if(newData) { GpMemcpy(newData, data, totalSize); IsDataAllocated; } else status = OutOfMemory; } else { if(Data && IsDataAllocated) GpFree(Data); newData = data; IsDataAllocated = FALSE; }
if(status == Ok) { Dimension = dimension; Count = count; Data = newData; } } else status = InvalidParameter;
return status; }
GpStatus Transform(const GpMatrix* matrix);
BOOL AreEqualPoints(INT index1, INT index2) { if(index1 < 0 || index1 >= Count || index2 < 0 || index2 >= Count || Data == NULL) return FALSE; // either index is out of the range or no data.
BOOL areEqual = TRUE; if(index1 != index2) { REALD* data1 = Data + index1*Dimension; REALD* data2 = Data + index2*Dimension; INT k = 0; while(k < Dimension && areEqual) { if(*data1++ != *data2++) areEqual = FALSE; k++; } }
return areEqual; } static GpStatus GpXPoints::TransformPoints( const GpMatrix* matrix, REALD* data, INT dimension, INT count );
~GpXPoints() { if(Data && IsDataAllocated) GpFree(Data); }
protected: VOID Initialize() { Dimension = 0; Count = 0; Data = NULL; IsDataAllocated = FALSE; } };
//********************************************************
// GpXBezierDDA class
//********************************************************
class GpXBezierConstants { friend class GpXBezierDDA;
private: REALD H[7][7]; // Half step
REALD D[7][7]; // Double step
REALD S[7][7]; // One step
REALD F[7][7]; // Polynomical transform.
REALD H6[7][7]; // Poly to Bez transform in 6th order.
REALD G6[7][7]; // Bez to Poly transform in 6th order.
public: GpXBezierConstants(); };
class GpXBezierDDA { protected: GpXBezierConstants C;
protected: REALD T; REALD Dt; REALD Q[16]; REALD P[16]; INT NthOrder; INT Dimension; INT NSteps; REAL FlatnessLimit; REAL DistanceLimit;
public:
public:
GpXBezierDDA() { Initialize(); }
GpXBezierDDA( const GpXPoints& xpoints, REAL flatnessLimit = FLATNESS_LIMIT, REAL distanceLimit = DISTANCE_LIMIT ) { Initialize(); SetBezier(xpoints, flatnessLimit, distanceLimit); }
VOID SetBezier( const GpXPoints& xpoints, REAL flatnessLimit = FLATNESS_LIMIT, REAL distanceLimit = DISTANCE_LIMIT );
INT GetSteps() { return NSteps; }
VOID InitDDA(GpPointF* pt); VOID HalveStepSize(); VOID DoubleStepSize(); VOID FastShrinkStepSize(INT shift); VOID TakeStep(); BOOL NeedsSubdivide(REAL itsFlatnessLimit); BOOL GetNextPoint(GpPointF* pt); VOID MoveForward(); INT GetControlPoints(GpXPoints* xpoints);
protected:
VOID Initialize(); VOID SetPolynomicalCoefficients(); VOID TakeConvergentStep(); BOOL Get2DDistanceVector(REALD* dx, REALD* dy, INT from, INT to); };
//************************************
// XBezier class
//************************************
#define NthOrderMax 6
class GpXBezier { private: // We now use an ObjectTag to determine if the object is valid
// instead of using a BOOL. This is much more robust and helps
// with debugging. It also enables us to version our objects
// more easily with a version number in the ObjectTag.
ObjectTag Tag; // Keep this as the 1st value in the object!
protected: VOID SetValid(BOOL valid) { Tag = valid ? ObjectTagGpBezier : ObjectTagInvalid; }
public: BOOL IsValid() const { ASSERT((Tag == ObjectTagGpBezier) || (Tag == ObjectTagInvalid)); #if DBG
if (Tag == ObjectTagInvalid) { WARNING1("Invalid GpBezier"); } #endif
return (Tag == ObjectTagGpBezier); }
GpXBezier() { Initialize(); }
GpXBezier(INT order, const GpPointF* points, INT count) { Initialize(); SetValid(SetBeziers(order, points, count)); }
GpXBezier(INT order, const GpXPoints& xpoints) { Initialize(); SetValid(SetBeziers(order, xpoints)); }
~GpXBezier();
GpStatus SetBeziers(INT order, const GpPointF* points, INT count);
GpStatus SetBeziers(INT order, const GpXPoints& xpoints);
virtual INT GetControlCount() {return Count;} virtual VOID GetBounds(GpMatrix* matrix, GpRect* bounds); virtual VOID Transform(GpMatrix* matrix); virtual GpStatus Flatten( DynPointFArray* flattenPts, const GpMatrix* matrix);
protected:
VOID Initialize() { NthOrder = 0; Dimension = 0; Count = 0; Data = NULL; FlatnessLimit = FLATNESS_LIMIT; DistanceLimit = DISTANCE_LIMIT; SetValid(TRUE); }
GpStatus FlattenEachBezier( DynPointFArray* flattenPts, GpXBezierDDA& dda, BOOL isFirstBezier, const GpMatrix* matrix, const REALD* bezierData );
GpStatus Get2DPoints( GpPointF* points, INT count, const REALD* dataPoints, const GpMatrix* matrix = NULL);
GpStatus CheckInputData(const GpPointF* points, INT count) { GpStatus status = InvalidParameter; if(NthOrder > 0) { if(count > NthOrder) { INT reminder = count % NthOrder; if(reminder == 1 && points !=NULL) status = Ok; } } else // NthOrder <= 0
{ if(count > 1 && points != NULL) { if(count <= NthOrderMax + 1) { NthOrder = count - 1; status = Ok; } } }
return status; }
protected: // GDI+ INTERNAL
// Following are the two values to determin the flatness.
REAL FlatnessLimit; // The maximum flateness.
REAL DistanceLimit; // The minimum distance.
private: // GDI+ INTERNAL
INT NthOrder; INT Dimension; INT Count; REALD* Data; };
#endif
|