void KoPathPoint::paint(QPainter &painter, int handleRadius, PointTypes types, bool active) { QRectF handle(-handleRadius, -handleRadius, 2*handleRadius, 2*handleRadius); bool drawControlPoint1 = types & ControlPoint1 && (!active || activeControlPoint1()); bool drawControlPoint2 = types & ControlPoint2 && (!active || activeControlPoint2()); // draw lines at the bottom if (drawControlPoint2) painter.drawLine(point(), controlPoint2()); if (drawControlPoint1) painter.drawLine(point(), controlPoint1()); QTransform worldMatrix = painter.worldTransform(); painter.setWorldTransform(QTransform()); // the point is lowest if (types & Node) { if (properties() & IsSmooth) painter.drawRect(handle.translated(worldMatrix.map(point()))); else if (properties() & IsSymmetric) { QTransform matrix; matrix.rotate(45.0); QPolygonF poly(handle); poly = matrix.map(poly); poly.translate(worldMatrix.map(point())); painter.drawPolygon(poly); } else painter.drawEllipse(handle.translated(worldMatrix.map(point()))); } // then comes control point 2 if (drawControlPoint2) painter.drawEllipse(handle.translated(worldMatrix.map(controlPoint2()))); // then comes control point 1 if (drawControlPoint1) painter.drawEllipse(handle.translated(worldMatrix.map(controlPoint1()))); painter.setWorldTransform(worldMatrix); }
bool KoPathPoint::isSmooth(KoPathPoint * prev, KoPathPoint * next) const { QPointF t1, t2; if (activeControlPoint1()) { t1 = point() - controlPoint1(); } else { // we need the previous path point but there is none provided if (! prev) return false; if (prev->activeControlPoint2()) t1 = point() - prev->controlPoint2(); else t1 = point() - prev->point(); } if (activeControlPoint2()) { t2 = controlPoint2() - point(); } else { // we need the next path point but there is none provided if (! next) return false; if (next->activeControlPoint1()) t2 = next->controlPoint1() - point(); else t2 = next->point() - point(); } // normalize tangent vectors qreal l1 = sqrt(t1.x() * t1.x() + t1.y() * t1.y()); qreal l2 = sqrt(t2.x() * t2.x() + t2.y() * t2.y()); if (qFuzzyCompare(l1 + 1, qreal(1.0)) || qFuzzyCompare(l2 + 1, qreal(1.0))) return true; t1 /= l1; t2 /= l2; qreal scalar = t1.x() * t2.x() + t1.y() * t2.y(); // tangents are parallel if t1*t2 = |t1|*|t2| return qFuzzyCompare(scalar, qreal(1.0)); }
static ofTTFCharacter makeContoursForCharacter(FT_Face &face){ //int num = face->glyph->outline.n_points; int nContours = face->glyph->outline.n_contours; int startPos = 0; char * tags = face->glyph->outline.tags; FT_Vector * vec = face->glyph->outline.points; ofTTFCharacter charOutlines; charOutlines.setUseShapeColor(false); for(int k = 0; k < nContours; k++){ if( k > 0 ){ startPos = face->glyph->outline.contours[k-1]+1; } int endPos = face->glyph->outline.contours[k]+1; if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "--NEW CONTOUR"; } //vector <ofPoint> testOutline; ofPoint lastPoint; for(int j = startPos; j < endPos; j++){ if( FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_ON ){ lastPoint.set((float)vec[j].x, (float)-vec[j].y, 0); if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "flag[" << j << "] is set to 1 - regular point - " << lastPoint.x << lastPoint.y; } charOutlines.lineTo(lastPoint/64); }else{ if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "flag[" << j << "] is set to 0 - control point"; } if( FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_CUBIC ){ if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "- bit 2 is set to 2 - CUBIC"; } int prevPoint = j-1; if( j == 0){ prevPoint = endPos-1; } int nextIndex = j+1; if( nextIndex >= endPos){ nextIndex = startPos; } ofPoint nextPoint( (float)vec[nextIndex].x, -(float)vec[nextIndex].y ); //we need two control points to draw a cubic bezier bool lastPointCubic = ( FT_CURVE_TAG(tags[prevPoint]) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG(tags[prevPoint]) == FT_CURVE_TAG_CUBIC); if( lastPointCubic ){ ofPoint controlPoint1((float)vec[prevPoint].x, (float)-vec[prevPoint].y); ofPoint controlPoint2((float)vec[j].x, (float)-vec[j].y); ofPoint nextPoint((float) vec[nextIndex].x, -(float) vec[nextIndex].y); //cubic_bezier(testOutline, lastPoint.x, lastPoint.y, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, nextPoint.x, nextPoint.y, 8); charOutlines.bezierTo(controlPoint1.x/64, controlPoint1.y/64, controlPoint2.x/64, controlPoint2.y/64, nextPoint.x/64, nextPoint.y/64); } }else{ ofPoint conicPoint( (float)vec[j].x, -(float)vec[j].y ); if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "- bit 2 is set to 0 - conic- "; ofLogNotice("ofTrueTypeFont") << "--- conicPoint point is " << conicPoint.x << conicPoint.y; } //If the first point is connic and the last point is connic then we need to create a virutal point which acts as a wrap around if( j == startPos ){ bool prevIsConnic = ( FT_CURVE_TAG( tags[endPos-1] ) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG( tags[endPos-1]) != FT_CURVE_TAG_CUBIC ); if( prevIsConnic ){ ofPoint lastConnic((float)vec[endPos - 1].x, (float)-vec[endPos - 1].y); lastPoint = (conicPoint + lastConnic) / 2; if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "NEED TO MIX WITH LAST"; ofLogNotice("ofTrueTypeFont") << "last is " << lastPoint.x << " " << lastPoint.y; } } } //bool doubleConic = false; int nextIndex = j+1; if( nextIndex >= endPos){ nextIndex = startPos; } ofPoint nextPoint( (float)vec[nextIndex].x, -(float)vec[nextIndex].y ); if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "--- last point is " << lastPoint.x << " " << lastPoint.y; } bool nextIsConnic = ( FT_CURVE_TAG( tags[nextIndex] ) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG( tags[nextIndex]) != FT_CURVE_TAG_CUBIC ); //create a 'virtual on point' if we have two connic points if( nextIsConnic ){ nextPoint = (conicPoint + nextPoint) / 2; if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "|_______ double connic!"; } } if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "--- next point is " << nextPoint.x << " " << nextPoint.y; } //quad_bezier(testOutline, lastPoint.x, lastPoint.y, conicPoint.x, conicPoint.y, nextPoint.x, nextPoint.y, 8); charOutlines.quadBezierTo(lastPoint.x/64, lastPoint.y/64, conicPoint.x/64, conicPoint.y/64, nextPoint.x/64, nextPoint.y/64); if( nextIsConnic ){ lastPoint = nextPoint; } } } //end for } charOutlines.close(); } return charOutlines; }
static ofTTFCharacter makeContoursForCharacter(FT_Face &face){ //int num = face->glyph->outline.n_points; int nContours = face->glyph->outline.n_contours; int startPos = 0; char * tags = face->glyph->outline.tags; FT_Vector * vec = face->glyph->outline.points; ofTTFCharacter charOutlines; for(int k = 0; k < nContours; k++){ if( k > 0 ){ startPos = face->glyph->outline.contours[k-1]+1; } int endPos = face->glyph->outline.contours[k]+1; if( printVectorInfo )printf("--NEW CONTOUR\n\n"); vector <ofPoint> testOutline; ofPoint lastPoint; for(int j = startPos; j < endPos; j++){ if( FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_ON ){ lastPoint.set((float)vec[j].x, (float)-vec[j].y, 0); if( printVectorInfo )printf("flag[%i] is set to 1 - regular point - %f %f \n", j, lastPoint.x, lastPoint.y); testOutline.push_back(lastPoint); }else{ if( printVectorInfo )printf("flag[%i] is set to 0 - control point \n", j); if( FT_CURVE_TAG(tags[j]) == FT_CURVE_TAG_CUBIC ){ if( printVectorInfo )printf("- bit 2 is set to 2 - CUBIC\n"); int prevPoint = j-1; if( j == 0){ prevPoint = endPos-1; } int nextIndex = j+1; if( nextIndex >= endPos){ nextIndex = startPos; } ofPoint nextPoint( (float)vec[nextIndex].x, -(float)vec[nextIndex].y ); //we need two control points to draw a cubic bezier bool lastPointCubic = ( FT_CURVE_TAG(tags[prevPoint]) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG(tags[prevPoint]) == FT_CURVE_TAG_CUBIC); if( lastPointCubic ){ ofPoint controlPoint1((float)vec[prevPoint].x, (float)-vec[prevPoint].y); ofPoint controlPoint2((float)vec[j].x, (float)-vec[j].y); ofPoint nextPoint((float) vec[nextIndex].x, -(float) vec[nextIndex].y); cubic_bezier(testOutline, lastPoint.x, lastPoint.y, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, nextPoint.x, nextPoint.y, 8); } }else{ ofPoint conicPoint( (float)vec[j].x, -(float)vec[j].y ); if( printVectorInfo )printf("- bit 2 is set to 0 - conic- \n"); if( printVectorInfo )printf("--- conicPoint point is %f %f \n", conicPoint.x, conicPoint.y); //If the first point is connic and the last point is connic then we need to create a virutal point which acts as a wrap around if( j == startPos ){ bool prevIsConnic = ( FT_CURVE_TAG( tags[endPos-1] ) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG( tags[endPos-1]) != FT_CURVE_TAG_CUBIC ); if( prevIsConnic ){ ofPoint lastConnic((float)vec[endPos - 1].x, (float)-vec[endPos - 1].y); lastPoint = (conicPoint + lastConnic) / 2; if( printVectorInfo ) printf("NEED TO MIX WITH LAST\n"); if( printVectorInfo )printf("last is %f %f \n", lastPoint.x, lastPoint.y); } } //bool doubleConic = false; int nextIndex = j+1; if( nextIndex >= endPos){ nextIndex = startPos; } ofPoint nextPoint( (float)vec[nextIndex].x, -(float)vec[nextIndex].y ); if( printVectorInfo )printf("--- last point is %f %f \n", lastPoint.x, lastPoint.y); bool nextIsConnic = ( FT_CURVE_TAG( tags[nextIndex] ) != FT_CURVE_TAG_ON ) && ( FT_CURVE_TAG( tags[nextIndex]) != FT_CURVE_TAG_CUBIC ); //create a 'virtual on point' if we have two connic points if( nextIsConnic ){ nextPoint = (conicPoint + nextPoint) / 2; if( printVectorInfo )printf("|_______ double connic!\n"); } if( printVectorInfo )printf("--- next point is %f %f \n", nextPoint.x, nextPoint.y); quad_bezier(testOutline, lastPoint.x, lastPoint.y, conicPoint.x, conicPoint.y, nextPoint.x, nextPoint.y, 8); if( nextIsConnic ){ lastPoint = nextPoint; } } } //end for } for(int g =0; g < (int)testOutline.size(); g++){ testOutline[g] /= 64.0f; } charOutlines.contours.push_back(ofTTFContour()); if( testOutline.size() ){ charOutlines.contours.back().pts = ofSimplifyContour(testOutline, (float)TTF_SHAPE_SIMPLIFICATION_AMNT); }else{ charOutlines.contours.back().pts = testOutline; } } return charOutlines; }
/* * Draw one cubic Bezier curve and repeat the same pattern long the the decoration's axis. * The start point (p1), controlPoint1, controlPoint2 and end point (p2) of the Bezier curve * form a diamond shape: * * step * |-----------| * * controlPoint1 * + * * * . . * . . * . . * (x1, y1) p1 + . + p2 (x2, y2) - <--- Decoration's axis * . . | * . . | * . . | controlPointDistance * | * | * + - * controlPoint2 * * |-----------| * step */ static void strokeWavyTextDecoration(GraphicsContext& context, const FloatPoint& start, const FloatPoint& end, float strokeThickness) { FloatPoint p1 = start; FloatPoint p2 = end; context.adjustLineToPixelBoundaries(p1, p2, strokeThickness, context.strokeStyle()); Path path; path.moveTo(p1); float controlPointDistance; float step; getWavyStrokeParameters(strokeThickness, controlPointDistance, step); bool isVerticalLine = (p1.x() == p2.x()); if (isVerticalLine) { ASSERT(p1.x() == p2.x()); float xAxis = p1.x(); float y1; float y2; if (p1.y() < p2.y()) { y1 = p1.y(); y2 = p2.y(); } else { y1 = p2.y(); y2 = p1.y(); } adjustStepToDecorationLength(step, controlPointDistance, y2 - y1); FloatPoint controlPoint1(xAxis + controlPointDistance, 0); FloatPoint controlPoint2(xAxis - controlPointDistance, 0); for (float y = y1; y + 2 * step <= y2;) { controlPoint1.setY(y + step); controlPoint2.setY(y + step); y += 2 * step; path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(xAxis, y)); } } else { ASSERT(p1.y() == p2.y()); float yAxis = p1.y(); float x1; float x2; if (p1.x() < p2.x()) { x1 = p1.x(); x2 = p2.x(); } else { x1 = p2.x(); x2 = p1.x(); } adjustStepToDecorationLength(step, controlPointDistance, x2 - x1); FloatPoint controlPoint1(0, yAxis + controlPointDistance); FloatPoint controlPoint2(0, yAxis - controlPointDistance); for (float x = x1; x + 2 * step <= x2;) { controlPoint1.setX(x + step); controlPoint2.setX(x + step); x += 2 * step; path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yAxis)); } } context.setShouldAntialias(true); context.strokePath(path); }