ProcessPathToTrapezoids Class Reference

Process a path to produce a trapezoid list suitable for variable- width or vector-brushed stroke generation. More...

#include <pathtrap.h>

Inheritance diagram for ProcessPathToTrapezoids:

ProcessPath CCObject SimpleCCObject List of all members.

Public Member Functions

 ProcessPathToTrapezoids (const double flat)
 The One True Constructor. Don't call any other graven constructors.
virtual BOOL Init (Path *pSource, TrapsList *pOutputList)
 Initialises the PathProcessor in preparation for processing.
virtual BOOL Process (const ProcessFlags &PFlags, TrapTravelType TravelType, JointType JoinStyle=RoundJoin)
 Processes the path given in Init() to produce a trapezoid list in the TrapsList given to Init().
virtual BOOL NewPoint (PathVerb Verb, DocCoord *pCoord)
 Constructor.
virtual BOOL CloseElement (BOOL done, PathVerb Verb, INT32 Index)
 Processes the close of LINETO and BEZIERTO elements to allow us to correctly handle joins in the path.
virtual void CloseFigure (void)
 Derived-class interface. Called after closing a LINETO or BEZIERTO element which constitutes the end of this figure (subpath) (as indicated by this element having the PT_CLOSEFIGURE flag set).

Protected Member Functions

BOOL CalculateMitreIntersection (DocCoord *p1, DocCoord *p2, DocCoord *p3, double *pMitreRatio=NULL)
 Mitred joins revert to bevelled joins when are so tight that the mitre exceeds the "mitre limit". This function determines and returns whether a given join should be rendered mitred or bevelled. In the former case, it also provides an output, which is based upon the distance from the center of the join (point 2, below) to the mitre outline intersection ("*" below). The distance is not an absolute length, but rather, the ratio of that length to the line width.

Private Attributes

TrapsListpTraps
BOOL PointFollowsJoin
JointType JoinType
INT32 RepeatLength
DocCoord LastPoint

Friends

class TrapEdgeList

Detailed Description

Process a path to produce a trapezoid list suitable for variable- width or vector-brushed stroke generation.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/12/96

Definition at line 424 of file pathtrap.h.


Constructor & Destructor Documentation

ProcessPathToTrapezoids::ProcessPathToTrapezoids const double  flat  ) 
 

The One True Constructor. Don't call any other graven constructors.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/12/96
Parameters:
flat - Flatness value to use (see PathProcessor class) [INPUTS]

Definition at line 913 of file pathtrap.cpp.

00914                         : ProcessPath(flat)
00915 {
00916     pTraps           = NULL;
00917     PointFollowsJoin = FALSE;
00918     JoinType         = RoundJoin;
00919 }


Member Function Documentation

BOOL ProcessPathToTrapezoids::CalculateMitreIntersection DocCoord p1,
DocCoord p2,
DocCoord p3,
double *  pMitreRatio = NULL
[protected]
 

Mitred joins revert to bevelled joins when are so tight that the mitre exceeds the "mitre limit". This function determines and returns whether a given join should be rendered mitred or bevelled. In the former case, it also provides an output, which is based upon the distance from the center of the join (point 2, below) to the mitre outline intersection ("*" below). The distance is not an absolute length, but rather, the ratio of that length to the line width.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
17/1/97
Parameters:
p1 - Centreline point prior to the join (see the diagram below) [INPUTS] p2 - Centreline point where the join occurs p3 - Centreline point subsequent to the join
pMitreRatio - if non-NULL, and if the return value is TRUE, this will [OUTPUTS] be returned with the distance-ratio in it (see below)
Returns:
TRUE - if the join should be mitred, and the pIntersectionDist output contains the mitre chord ratio. FALSE - if the join should be bevelled. The pIntersectionDist param will be untouched in this case.
i.e. if you take point 2, and add it's "normal" (the vector toward the mitre point) and multiply it by Width*pIntersectionRatio, you'll arrive at the mitre intersection point. This may sound like an odd number to return, but in fact it is precisely the number I need.

+--------:-----* / 1,2,3 are the inputs p1, p2, p3 1--------2 / / : ':' are the points where stroke outline meets join --- / / / / / * is the pIntersection output / 3 +

Definition at line 1314 of file pathtrap.cpp.

01316 {
01317     // Camelot never seems to actually set the MitreLimit in any render regions, so I have
01318     // taken on a default value which is the same as GDraw uses (GDraw uses 10.0).
01319     // Anyway, Gavin's MitreLimit is sensibly based on the angle/width ratio, whereas
01320     // our attributes are a random value in millipoints, which seems daft to me.
01321     const double MitreLimit = 1.0 / 10.0;   // (10.0 plus a bit of precalculation)
01322 
01323     // Work out the normalised direction vectors for the incoming and outgoing lines
01324     NormCoord v1(p1->x - p2->x, p1->y - p2->y);
01325     v1.Normalise();
01326 
01327     NormCoord v2(p3->x - p2->x, p3->y - p2->y);
01328     v2.Normalise();
01329 
01330     // From these vectors, we can now calculate cos(theta) using a dot product 
01331     // (where theta is the angle between the vectors), and taking the arc-cosine
01332     // of that gives us a huge surprise as a theta drops out.
01333     const double Theta = acos(v1.DotProduct(v2));
01334     const double SinHalfTheta = sin(Theta / 2.0);
01335 
01336     // If the angle is too tight, then we must bevel this (this also stops a divide by zero)
01337     if (fabs(SinHalfTheta) < MitreLimit)
01338         return(FALSE);
01339 
01340     if (pMitreRatio != NULL)
01341         *pMitreRatio = 1.0 / SinHalfTheta;
01342 
01343     return(TRUE);
01344 }

BOOL ProcessPathToTrapezoids::CloseElement BOOL  done,
PathVerb  Verb,
INT32  Index
[virtual]
 

Processes the close of LINETO and BEZIERTO elements to allow us to correctly handle joins in the path.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/1/97
Parameters:
done = true if the NewPoint function procesed all new points in the [INPUTS] open element correctly, false if it did not. Verb = verb of closing element. index = index of closing element.
[OUTPUTS] 
Returns:
FALSE to continue processing the next element TRUE to stop processing and return done

Reimplemented from ProcessPath.

Definition at line 1037 of file pathtrap.cpp.

01038 {
01039     // If it's the end of a line/bezier, then it's a proper join. In this case,
01040     // we set a flag so we will know that the next point added follows a join.
01041     // For some join types we need to know which direction the path takes after
01042     // the join in order to determine what to output.
01043     if (Verb == PT_LINETO || Verb == PT_BEZIERTO)
01044         PointFollowsJoin = TRUE;
01045 
01046     return(FALSE);      // continue processing - all is well
01047 }

void ProcessPathToTrapezoids::CloseFigure void   )  [virtual]
 

Derived-class interface. Called after closing a LINETO or BEZIERTO element which constitutes the end of this figure (subpath) (as indicated by this element having the PT_CLOSEFIGURE flag set).

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
16/1/97
Used by the path stroking ProcessPathToTrapezoids class to allow it to correctly handle joining the start & end of a closed figure.

Reimplemented from ProcessPath.

Definition at line 1068 of file pathtrap.cpp.

01069 {
01070     // Find this subpath's edge list
01071     TrapEdgeList *pEdgeList = pTraps->GetLastTrapEdgeList();
01072     if (pEdgeList == NULL)
01073         return;
01074 
01075     // Find the first and last TrapEdges for this subpath. If either is NULL
01076     // or if they are the same, then we don't have enough trapezoids to bake
01077     // a cake, so we throw in the towel.
01078     TrapEdge *pFirstEdge = pEdgeList->GetTrapEdge(0);
01079     TrapEdge *pLastEdge  = pEdgeList->GetLastTrapEdge();
01080     if (pFirstEdge == NULL || pLastEdge == NULL || pFirstEdge == pLastEdge)
01081         return;
01082 
01083     // Now, compare the edge points. If they are coincident, we must add a join
01084     // to complete the shape, but if they are not, we leave the path unclosed
01085     if (pFirstEdge->Centre == pLastEdge->Centre)
01086     {
01087         PointFollowsJoin = TRUE;
01088         NewPoint(PT_LINETO, NULL);
01089     }
01090 }

BOOL ProcessPathToTrapezoids::Init Path pSource,
TrapsList pOutputList
[virtual]
 

Initialises the PathProcessor in preparation for processing.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/12/96
Parameters:
pSource - The path for which you want to build trapezoid lists [INPUTS]
pOutputList - A pointer to the trapezoid list to be filled in when you invoke the Process() function. Note that all generated trapezoid edge lists are APPENDED to this TrapsList, rather than overwriting it.

JoinStyle - RoundJoin, MitredJoin, or BevelledJoin

Notes: Call this version of Init, not the base class one!

Definition at line 945 of file pathtrap.cpp.

00946 {
00947     ERROR3IF(pOutputList == NULL, "Illegal NULL param");
00948     pTraps = pOutputList;
00949 
00950     // And init the base class
00951     return(ProcessPath::Init(pSource));
00952 }

BOOL ProcessPathToTrapezoids::NewPoint PathVerb  Verb,
DocCoord pCoord
[virtual]
 

Constructor.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/12/96
Parameters:
Verb - Descriptor indicating the type of point to add [INPUTS] pCoord - The coordinate of the point (if NULL, this will add a closing join to the trapezoid list)
The new point will have been appended to the member trapezoid list [OUTPUTS] in an appropriate manner. If preceeded by a bezier knot (join), appropriate trapezoidal elements will have been added to represent the join.
Returns:
TRUE if it wishes to continue processing the path (FALSE if it's run out of memory)

Implements ProcessPath.

Definition at line 1117 of file pathtrap.cpp.

01118 {
01119     // Process any join we've just gone past. We have to delay processing of joins
01120     // until we know which way the curve headed off after the join, which is why
01121     // we are processing it now. If the new point is a MOVETO, then there is no join
01122     if (PointFollowsJoin && Verb == PT_LINETO)
01123     {
01124         // Find the last edge in the current edge list. If we can't find one, there is
01125         // nothing to "join to"
01126         TrapEdgeList *pEdgeList = pTraps->GetLastTrapEdgeList();
01127         TrapEdge *pEdge = NULL;
01128         if (pEdgeList != NULL)
01129             pEdge = pEdgeList->GetLastTrapEdge();
01130 
01131         if (pEdge != NULL)
01132         {
01133             switch(JoinType)
01134             {
01135                 case MitreJoin:
01136                     // A mitred join involves extending the previous and next segments of the outline
01137                     // to their intersection. If there is no intersection, or if the intersection
01138                     // is beyond the "MitreLimit", then we revert to a simple Bevelled join.
01139                     // Otherwise, we need to add 2 line segments (3 trapezoid edges) joining the
01140                     // end of the last segment to the intersection, and then from the intersection
01141                     // to the start of this new segment.
01142                     // These new segments are marked as being part of a join so that they will be
01143                     // stroked as straight line segments rather than interpolating normals to make
01144                     // a smoothed/curved join.
01145 
01146                     {
01147                         ERROR3IF(pEdgeList->GetNumEdges() < 2, "Not enough traps for mitred join");
01148                         TrapEdge *pPrevEdge = pEdgeList->GetTrapEdge(pEdgeList->GetNumEdges() - 2);
01149 
01150                         BOOL Mitred;
01151                         if (pCoord != NULL)
01152                         {
01153                             Mitred = CalculateMitreIntersection(&pPrevEdge->Centre, &pEdge->Centre, pCoord);
01154                         }
01155                         else
01156                         {
01157                             // No pCoord passed in, so this is the join at the end. Use the 1st point
01158                             // in the subpath as the "next point". (Well, the 2nd in the array, because point
01159                             // 1 is coincident! We use point 2 which is the end of the 1st line)
01160                             DocCoord NextCoord = pEdgeList->GetTrapEdge(1)->Centre;
01161                             Mitred = CalculateMitreIntersection(&pPrevEdge->Centre, &pEdge->Centre, &NextCoord);
01162                         }
01163 
01164                         //BLOCK
01165                         {
01166                             // Nasty bodge - Because AddEdge can re-alloc the array, we CANNOT keep pointers
01167                             // to array entries around over calls to AddEdge. We thus copy the edge point
01168                             // into a temporary variable which we can safely use over the 2 calls the AddEdge
01169                             DocCoord Temp = pEdge->Centre;
01170 
01171                             // Add a single point for this join - by default this gives a Bevelled join
01172                             pEdgeList->AddEdge(&Temp, TrapJoin_MitredOrBevelled);
01173 
01174                             // And if it's Mitred, then add another point for this join
01175                             if (Mitred)
01176                                 pEdgeList->AddEdge(&Temp, TrapJoin_MitredOrBevelled);
01177                         }
01178                     }
01179                     break;
01180 
01181                 case RoundJoin:
01182                     // To make a rounded join, you might think we need to output a number of trapezoids,
01183                     // but in fact the recursive flattened-mapping algorithm employed by the path
01184                     // stroker will "smooth" a single trapezoid into a proper round join!
01185                     // Thus, we simply insert another trapezoid on the join point (but do NOT mark
01186                     // it as "part of a join") so that it will be mapped as a round join.
01187                     pEdgeList->AddEdge(&pEdge->Centre, TrapJoin_Round);
01188                     break;
01189 
01190                 case BevelledJoin:
01191                     // To make a bevelled join, we simply add another TrapEdge on the join point for
01192                     // the start of the next segment, which will be joined with a straight line. 
01193                     // However, the stroking mechanism will actually output that "line" as a round
01194                     // join (due to its recursive flattened-mapping algorithm), so we have to
01195                     // mark this point as "part of a join" so that it simply plonks down the
01196                     // straight segment we want! (Hence the TRUE)
01197                     pEdgeList->AddEdge(&pEdge->Centre, TrapJoin_MitredOrBevelled);
01198                     break;
01199 
01200                 default:
01201                     ERROR3("Unsupported join type in ProcessPathToTrapezoids");
01202                     break;
01203             }           
01204         }
01205     }
01206 
01207     // Clear the join flag, as any pending join has been processed
01208     PointFollowsJoin = FALSE;
01209 
01210     // If the provided coordinate was NULL, then they only wanted to add the join
01211     // information, so we exit now
01212     if (pCoord == NULL)
01213         return(TRUE);
01214 
01215     // Add the new point to the current trapezoid list
01216     switch(Verb)
01217     {
01218         case PT_MOVETO:
01219             {
01220                 // A MoveTo signifies the start of a new (sub)path, so we start a new TrapList
01221                 TrapEdgeList *pEdgeList = pTraps->AddEdgeList();
01222                 if (pEdgeList == NULL)
01223                     return(FALSE);
01224 
01225                 pEdgeList->AddEdge(pCoord);
01226                 LastPoint = *pCoord;
01227             }
01228             break;
01229 
01230 
01231         case PT_LINETO:
01232             {
01233                 // Append each new point as a new trapezoid edge in the current TrapList
01234                 // Find the last TrapEdgeList
01235                 TrapEdgeList *pEdgeList = pTraps->GetLastTrapEdgeList();
01236 
01237                 if (pEdgeList == NULL)
01238                 {
01239                     // We have started a path with a LineTo!
01240                     // Create a new Trapezoid List (imply that this point is really a MOVETO)
01241                     ERROR3("LINETO added to traplist with no preceding MOVETO");
01242 
01243                     LastPoint = DocCoord(0,0);
01244                     pEdgeList = pTraps->AddEdgeList();
01245                     if (pEdgeList == NULL)
01246                         return(FALSE);
01247                 }
01248 
01249                 // Append the new point to the current trap list. Check first to eliminate
01250                 // coincident points (places where the source path has coincident points),
01251                 // as we only want coincident points to occur in the special case of joins.
01252                 if (pEdgeList->GetNumEdges() < 1 || LastPoint != *pCoord)
01253                 {
01254                     pEdgeList->AddEdge(pCoord);
01255                     LastPoint = *pCoord;
01256                 }
01257             }
01258             break;
01259 
01260         default:
01261             ERROR3("ProcessPathToTrapezoids only handles MOVETO and LINETO!");
01262             break;
01263     }
01264 
01265     return(TRUE);
01266 }

BOOL ProcessPathToTrapezoids::Process const ProcessFlags PFlags,
TrapTravelType  TravelType,
JointType  JoinStyle = RoundJoin
[virtual]
 

Processes the path given in Init() to produce a trapezoid list in the TrapsList given to Init().

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/12/96
Parameters:
PFlags - the ProcessPath flags indicating how to process the path [INPUTS] (Note that some flags should not be used with this process)
TravelType - Describes how to record "positions" along the path: TrapTravel_None Don't record travel (FASTEST) TrapTravel_Parametric 0.0 to 1.0 parametric range TrapTravel_Millipoint Absolute millipoints distance

JoinStyle - The type of joins in this path. (RoundJoin, MitredJoin, or BevelledJoin)

Notes: * Call this version of Process, not the base class one!

To process a path, you should write code like this:

ProcessPathToTrapezoids GenerateTraps(64); TrapsList OutputTraps; if (GenerateTraps.Init(pPath, &OutputTraps)) { Flags are: Flatten, QuantiseLines, QuantiseAll ProcessFlags PFlags(TRUE, FALSE, FALSE); if (!GenerateTraps.Process(PFlags, TrapTravel_Parametric, JoinStyle)) return; }

TrapTravel_None will leave edge "Position" values TOTALLY UNINITIALISED because to initialise them will waste time if you're not going to use 'em

Definition at line 998 of file pathtrap.cpp.

01000 {
01001     ERROR2IF(pTraps == NULL, FALSE, "Call Init to initialise the ProcessPathToTrapezoids object first!");
01002 
01003     JoinType         = JoinStyle;
01004     PointFollowsJoin = FALSE;
01005     LastPoint        = DocCoord(0,0);
01006 
01007     BOOL ok = ProcessPath::Process(PFlags);
01008 
01009     if (ok)
01010         ok = pTraps->PostProcessLists(this, TravelType);
01011 
01012     return(ok);
01013 }


Friends And Related Function Documentation

friend class TrapEdgeList [friend]
 

Definition at line 426 of file pathtrap.h.


Member Data Documentation

JointType ProcessPathToTrapezoids::JoinType [private]
 

Definition at line 453 of file pathtrap.h.

DocCoord ProcessPathToTrapezoids::LastPoint [private]
 

Definition at line 455 of file pathtrap.h.

BOOL ProcessPathToTrapezoids::PointFollowsJoin [private]
 

Definition at line 452 of file pathtrap.h.

TrapsList* ProcessPathToTrapezoids::pTraps [private]
 

Definition at line 451 of file pathtrap.h.

INT32 ProcessPathToTrapezoids::RepeatLength [private]
 

Definition at line 454 of file pathtrap.h.


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