bool Playback::Order::Prev( int & iCur, int iMax ) { switch( iCurOrder ) { case ORDER_SINGLE: return false; case ORDER_SINGLE_REPEAT: return true; case ORDER_NORMAL: return NextInverse( iCur, iMax ); case ORDER_NORMAL_REPEAT: return NextInverseRepeat( iCur, iMax ); case ORDER_INVERSE: return NextNormal( iCur, iMax ); case ORDER_INVERSE_REPEAT: return NextNormalRepeat( iCur, iMax ); case ORDER_RANDOM: return NextRandom( iCur, iMax ); default: return false; } }
BOOL TrapEdgeList::ProcessEdgeNormals(ProcessPathToTrapezoids *pProcessor) { if (Used < 2) // Sanity check { ERROR3("Not enough coordinates in trapezoid list!"); return(FALSE); } TrapEdge *pPrevEdge = NULL; TrapEdge *pEdge = NULL; NormCoord PrevNormal(1.0, 0.0); BOOL CompletingAMitre = FALSE; // --- First, scan the trapezoid list, and calculate the normal of each edge for (UINT32 Index = 0; Index < Used; Index++) { // Start by finding a pointer to the edge record and previous record (if any) pPrevEdge = pEdge; pEdge = &(pEdges[Index]); // Calculate the path normal for this trapezoid edge. if (pPrevEdge == NULL) { // It's the very first point. The normal is just the normal to the first segment TrapEdge *pNextEdge = &(pEdges[Index+1]); pEdge->Normal.SetNormalToLine(pEdge->Centre, pNextEdge->Centre); PrevNormal = pEdge->Normal; // Remember this edge's normal for the next pass } else if (pEdge->Centre == pPrevEdge->Centre) { // Two points are coincident. That means a joint (or a degenerate source path element). // // The following cases can apply: // if (the next point is ALSO coincident) // * We have a mitred join. The normal is the average of the previous and next normals // with some jiggery-pokery to make the normal also have a length which will get the // outline out to the mitre intersection point (rather than being normalised) // else // * We have the last 2 points of the 3-point mitred join, or // * We have a simple bevelled or rounded join // (both of which are treated in the same manner) // Find the "next" edge. Care must be taken for the last join to make sure // that the first edge is treated as "next". Note that we don't use point 0 // in this case, as that is coincident! We use point 1 which is the point // at the end of that first line. TrapEdge *pNextEdge = &pEdges[1]; if (Index < Used-1) pNextEdge = &pEdges[Index+1]; if (pNextEdge->Centre == pEdge->Centre) { // We have found 3 coincident points, so we've hit a mitred join. // The middle Edge of the mitred join has a normal which is in the direction // of the average of the preceeding/next edge normals (i.e. points towards the // mitre intersection), but it has a non-unit-length, so as to stretch the // outline out to the mitre point. // In this case, we don't bother to do anything yet, as we'll calculate // the next normal on the next pass, so we just flag the case and let // the next pass come back and fix up our normal once it has all the facts. CompletingAMitre = TRUE; // NOTE that we leave PrevNormal containing the previous normal - we'll need it // on the next pass. } else { // The completing trap of any join simply uses the normal of the "next" edge, // so we simply calculate this for all cases. if (Index >= Used-1) { // At the end of the curve - we can just copy the normal from the first point pEdge->Normal = pEdges[0].Normal; } else { // Inside the path - just use the next edge to generate a normal pEdge->Normal.SetNormalToLine(pEdge->Centre, pNextEdge->Centre); } // However, now we must check if we've just completed a mitred join, in // which case we have to go back to fill in the previous edge normal if (CompletingAMitre) { // Find the vector pointing towards the mitre point pPrevEdge->Normal.Average(PrevNormal, pEdge->Normal); // We now know the direction the mitre intersection (pointy bit) lies in. // Now, we will "stretch" that normal by the ratio of the distance to // the intersection over the stroke width. // We pass in the point before the join, the join centre, and the point // after the join. (Note that the join centre point occupies 3 edge entries) double MitreChordRatio = 1.0; pProcessor->CalculateMitreIntersection( &pEdges[Index-3].Centre, &pEdge->Centre, &pNextEdge->Centre, /*TO*/ &MitreChordRatio); pPrevEdge->Normal.x *= MitreChordRatio; pPrevEdge->Normal.y *= MitreChordRatio; } CompletingAMitre = FALSE; // Clear the mitre flag PrevNormal = pEdge->Normal; // Remember this edge's normal for the next pass } } else { // This isn't the first point. It also is not "inside" a joint (although it could be // the last edge preceeding a join) if (Index >= Used-1) { // Last point - the normal is merely at right-angles to last line, so = (lineY,-lineX) // NOTE that this is not true if this is a closed path, but we will fix that after // the loop if it needs fixing pEdge->Normal = PrevNormal; } else { // Find normal to next line NormCoord NextNormal(pEdge->Centre.y - pEdges[Index+1].Centre.y, -(pEdge->Centre.x - pEdges[Index+1].Centre.x)); if (NextNormal.x == 0.0 && NextNormal.y == 0.0) { // This point and the next point are coincident, so we must have hit a cusp join // (or rampant discontinuity) The normal is simply perpendicular to the last line pEdge->Normal = PrevNormal; } else { // This point lies between 2 flattened source path segments, so we simply average // their normals to get the path normal at the point. NextNormal.Normalise(); pEdge->Normal.Average(PrevNormal, NextNormal); PrevNormal = NextNormal; // Remember this normal for the next pass } } } } return(TRUE); }