FTContour::FTContour( FT_Vector* contour, char* pointTags, unsigned int numberOfPoints) { for( unsigned int pointIndex = 0; pointIndex < numberOfPoints; ++ pointIndex) { char pointTag = pointTags[pointIndex]; if( pointTag == FT_Curve_Tag_On || numberOfPoints < 2) { AddPoint( contour[pointIndex].x, contour[pointIndex].y); continue; } FTPoint controlPoint( contour[pointIndex]); FTPoint previousPoint = ( 0 == pointIndex) ? FTPoint( contour[numberOfPoints - 1]) : pointList[pointList.size() - 1]; FTPoint nextPoint = ( pointIndex == numberOfPoints - 1) ? pointList[0] : FTPoint( contour[pointIndex + 1]); if( pointTag == FT_Curve_Tag_Conic) { char nextPointTag = ( pointIndex == numberOfPoints - 1) ? pointTags[0] : pointTags[pointIndex + 1]; while( nextPointTag == FT_Curve_Tag_Conic) { nextPoint = ( controlPoint + nextPoint) * 0.5f; controlPoints[0][0] = previousPoint.X(); controlPoints[0][1] = previousPoint.Y(); controlPoints[1][0] = controlPoint.X(); controlPoints[1][1] = controlPoint.Y(); controlPoints[2][0] = nextPoint.X(); controlPoints[2][1] = nextPoint.Y(); evaluateQuadraticCurve(); ++pointIndex; previousPoint = nextPoint; controlPoint = FTPoint( contour[pointIndex]); nextPoint = ( pointIndex == numberOfPoints - 1) ? pointList[0] : FTPoint( contour[pointIndex + 1]); nextPointTag = ( pointIndex == numberOfPoints - 1) ? pointTags[0] : pointTags[pointIndex + 1]; } controlPoints[0][0] = previousPoint.X(); controlPoints[0][1] = previousPoint.Y(); controlPoints[1][0] = controlPoint.X(); controlPoints[1][1] = controlPoint.Y(); controlPoints[2][0] = nextPoint.X(); controlPoints[2][1] = nextPoint.Y(); evaluateQuadraticCurve(); continue; } if( pointTag == FT_Curve_Tag_Cubic) { FTPoint controlPoint2 = nextPoint; FTPoint nextPoint = ( pointIndex == numberOfPoints - 2) ? pointList[0] : FTPoint( contour[pointIndex + 2]); controlPoints[0][0] = previousPoint.X(); controlPoints[0][1] = previousPoint.Y(); controlPoints[1][0] = controlPoint.X(); controlPoints[1][1] = controlPoint.Y(); controlPoints[2][0] = controlPoint2.X(); controlPoints[2][1] = controlPoint2.Y(); controlPoints[3][0] = nextPoint.X(); controlPoints[3][1] = nextPoint.Y(); evaluateCubicCurve(); ++pointIndex; continue; } } }
FTContour::FTContour(FT_Vector* contour, char* tags, unsigned int n) { FTPoint prev, cur(contour[(n - 1) % n]), next(contour[0]); FTPoint a, b = next - cur; double olddir, dir = atan2((next - cur).Y(), (next - cur).X()); double angle = 0.0; // See http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html // for a full description of FreeType tags. for(unsigned int i = 0; i < n; i++) { prev = cur; cur = next; next = FTPoint(contour[(i + 1) % n]); olddir = dir; dir = atan2((next - cur).Y(), (next - cur).X()); // Compute our path's new direction. double t = dir - olddir; if(t < -M_PI) t += 2 * M_PI; if(t > M_PI) t -= 2 * M_PI; angle += t; // Only process point tags we know. if(n < 2 || FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_On) { AddPoint(cur); } else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Conic) { FTPoint prev2 = prev, next2 = next; // Previous point is either the real previous point (an "on" // point), or the midpoint between the current one and the // previous "conic off" point. if(FT_CURVE_TAG(tags[(i - 1 + n) % n]) == FT_Curve_Tag_Conic) { prev2 = (cur + prev) * 0.5; AddPoint(prev2); } // Next point is either the real next point or the midpoint. if(FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Conic) { next2 = (cur + next) * 0.5; } evaluateQuadraticCurve(prev2, cur, next2); } else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Cubic && FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Cubic) { evaluateCubicCurve(prev, cur, next, FTPoint(contour[(i + 2) % n])); } } // If final angle is positive (+2PI), it's an anti-clockwise contour, // otherwise (-2PI) it's clockwise. clockwise = (angle < 0.0); }