#include <pathtrap.h>
Inheritance diagram for ProcessPathToTrapezoids:
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 | |
TrapsList * | pTraps |
BOOL | PointFollowsJoin |
JointType | JoinType |
INT32 | RepeatLength |
DocCoord | LastPoint |
Friends | |
class | TrapEdgeList |
Definition at line 424 of file pathtrap.h.
|
The One True Constructor. Don't call any other graven constructors.
Definition at line 913 of file pathtrap.cpp. 00914 : ProcessPath(flat) 00915 { 00916 pTraps = NULL; 00917 PointFollowsJoin = FALSE; 00918 JoinType = RoundJoin; 00919 }
|
|
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.
+--------:-----* / 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 }
|
|
Processes the close of LINETO and BEZIERTO elements to allow us to correctly handle joins in the path.
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 }
|
|
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).
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 }
|
|
Initialises the PathProcessor in preparation for processing.
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 }
|
|
Constructor.
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 }
|
|
Processes the path given in Init() to produce a trapezoid list in the TrapsList given to Init().
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 }
|
|
Definition at line 426 of file pathtrap.h. |
|
Definition at line 453 of file pathtrap.h. |
|
Definition at line 455 of file pathtrap.h. |
|
Definition at line 452 of file pathtrap.h. |
|
Definition at line 451 of file pathtrap.h. |
|
Definition at line 454 of file pathtrap.h. |