diff --git a/core/EdgeHolder.cpp b/core/EdgeHolder.cpp index cffcff4..f552e98 100644 --- a/core/EdgeHolder.cpp +++ b/core/EdgeHolder.cpp @@ -9,16 +9,6 @@ void EdgeHolder::swap(EdgeHolder &a, EdgeHolder &b) { b.edgeSegment = tmp; } -EdgeHolder::EdgeHolder() : edgeSegment(NULL) { } - -EdgeHolder::EdgeHolder(EdgeSegment *segment) : edgeSegment(segment) { } - -EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor) : edgeSegment(new LinearSegment(p0, p1, edgeColor)) { } - -EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor) : edgeSegment(new QuadraticSegment(p0, p1, p2, edgeColor)) { } - -EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) : edgeSegment(new CubicSegment(p0, p1, p2, p3, edgeColor)) { } - EdgeHolder::EdgeHolder(const EdgeHolder &orig) : edgeSegment(orig.edgeSegment ? orig.edgeSegment->clone() : NULL) { } #ifdef MSDFGEN_USE_CPP11 diff --git a/core/EdgeHolder.h b/core/EdgeHolder.h index 50a59b2..5ae2dc2 100644 --- a/core/EdgeHolder.h +++ b/core/EdgeHolder.h @@ -12,11 +12,11 @@ public: /// Swaps the edges held by a and b. static void swap(EdgeHolder &a, EdgeHolder &b); - EdgeHolder(); - EdgeHolder(EdgeSegment *segment); - EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE); - EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE); - EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE); + inline EdgeHolder() : edgeSegment() { } + inline EdgeHolder(EdgeSegment *segment) : edgeSegment(segment) { } + inline EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, edgeColor)) { } + inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, edgeColor)) { } + inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, p3, edgeColor)) { } EdgeHolder(const EdgeHolder &orig); #ifdef MSDFGEN_USE_CPP11 EdgeHolder(EdgeHolder &&orig); diff --git a/core/edge-segments.cpp b/core/edge-segments.cpp index 4fef89b..aad32e2 100644 --- a/core/edge-segments.cpp +++ b/core/edge-segments.cpp @@ -6,6 +6,25 @@ namespace msdfgen { +EdgeSegment *EdgeSegment::create(Point2 p0, Point2 p1, EdgeColor edgeColor) { + return new LinearSegment(p0, p1, edgeColor); +} + +EdgeSegment *EdgeSegment::create(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor) { + if (!crossProduct(p1-p0, p2-p1)) + return new LinearSegment(p0, p2, edgeColor); + return new QuadraticSegment(p0, p1, p2, edgeColor); +} + +EdgeSegment *EdgeSegment::create(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) { + Vector2 p12 = p2-p1; + if (!crossProduct(p1-p0, p12) && !crossProduct(p12, p3-p2)) + return new LinearSegment(p0, p3, edgeColor); + if ((p12 = 1.5*p1-.5*p0) == 1.5*p2-.5*p3) + return new QuadraticSegment(p0, p12, p3, edgeColor); + return new CubicSegment(p0, p1, p2, p3, edgeColor); +} + void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const { if (param < 0) { Vector2 dir = direction(0).normalize(); @@ -38,18 +57,12 @@ LinearSegment::LinearSegment(Point2 p0, Point2 p1, EdgeColor edgeColor) : EdgeSe } QuadraticSegment::QuadraticSegment(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor) : EdgeSegment(edgeColor) { - if (p1 == p0 || p1 == p2) - p1 = 0.5*(p0+p2); p[0] = p0; p[1] = p1; p[2] = p2; } CubicSegment::CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) : EdgeSegment(edgeColor) { - if ((p1 == p0 || p1 == p3) && (p2 == p0 || p2 == p3)) { - p1 = mix(p0, p3, 1/3.); - p2 = mix(p0, p3, 2/3.); - } p[0] = p0; p[1] = p1; p[2] = p2; @@ -486,25 +499,25 @@ void CubicSegment::moveEndPoint(Point2 to) { p[3] = to; } -void LinearSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const { - part1 = new LinearSegment(p[0], point(1/3.), color); - part2 = new LinearSegment(point(1/3.), point(2/3.), color); - part3 = new LinearSegment(point(2/3.), p[1], color); +void LinearSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const { + part0 = new LinearSegment(p[0], point(1/3.), color); + part1 = new LinearSegment(point(1/3.), point(2/3.), color); + part2 = new LinearSegment(point(2/3.), p[1], color); } -void QuadraticSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const { - part1 = new QuadraticSegment(p[0], mix(p[0], p[1], 1/3.), point(1/3.), color); - part2 = new QuadraticSegment(point(1/3.), mix(mix(p[0], p[1], 5/9.), mix(p[1], p[2], 4/9.), .5), point(2/3.), color); - part3 = new QuadraticSegment(point(2/3.), mix(p[1], p[2], 2/3.), p[2], color); +void QuadraticSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const { + part0 = new QuadraticSegment(p[0], mix(p[0], p[1], 1/3.), point(1/3.), color); + part1 = new QuadraticSegment(point(1/3.), mix(mix(p[0], p[1], 5/9.), mix(p[1], p[2], 4/9.), .5), point(2/3.), color); + part2 = new QuadraticSegment(point(2/3.), mix(p[1], p[2], 2/3.), p[2], color); } -void CubicSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const { - part1 = new CubicSegment(p[0], p[0] == p[1] ? p[0] : mix(p[0], p[1], 1/3.), mix(mix(p[0], p[1], 1/3.), mix(p[1], p[2], 1/3.), 1/3.), point(1/3.), color); - part2 = new CubicSegment(point(1/3.), +void CubicSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const { + part0 = new CubicSegment(p[0], p[0] == p[1] ? p[0] : mix(p[0], p[1], 1/3.), mix(mix(p[0], p[1], 1/3.), mix(p[1], p[2], 1/3.), 1/3.), point(1/3.), color); + part1 = new CubicSegment(point(1/3.), mix(mix(mix(p[0], p[1], 1/3.), mix(p[1], p[2], 1/3.), 1/3.), mix(mix(p[1], p[2], 1/3.), mix(p[2], p[3], 1/3.), 1/3.), 2/3.), mix(mix(mix(p[0], p[1], 2/3.), mix(p[1], p[2], 2/3.), 2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), 1/3.), point(2/3.), color); - part3 = new CubicSegment(point(2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), p[2] == p[3] ? p[3] : mix(p[2], p[3], 2/3.), p[3], color); + part2 = new CubicSegment(point(2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), p[2] == p[3] ? p[3] : mix(p[2], p[3], 2/3.), p[3], color); } EdgeSegment *QuadraticSegment::convertToCubic() const { diff --git a/core/edge-segments.h b/core/edge-segments.h index 71ce8fc..e34982f 100644 --- a/core/edge-segments.h +++ b/core/edge-segments.h @@ -17,6 +17,10 @@ class EdgeSegment { public: EdgeColor color; + static EdgeSegment *create(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE); + static EdgeSegment *create(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE); + static EdgeSegment *create(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE); + EdgeSegment(EdgeColor edgeColor = WHITE) : color(edgeColor) { } virtual ~EdgeSegment() { } /// Creates a copy of the edge segment. @@ -47,7 +51,7 @@ public: /// Moves the end point of the edge segment. virtual void moveEndPoint(Point2 to) = 0; /// Splits the edge segments into thirds which together represent the original edge. - virtual void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const = 0; + virtual void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const = 0; }; @@ -76,7 +80,7 @@ public: void reverse(); void moveStartPoint(Point2 to); void moveEndPoint(Point2 to); - void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const; + void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const; }; @@ -105,7 +109,7 @@ public: void reverse(); void moveStartPoint(Point2 to); void moveEndPoint(Point2 to); - void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const; + void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const; EdgeSegment *convertToCubic() const; @@ -135,7 +139,7 @@ public: void reverse(); void moveStartPoint(Point2 to); void moveEndPoint(Point2 to); - void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const; + void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const; void deconverge(int param, double amount); diff --git a/ext/import-font.cpp b/ext/import-font.cpp index a4a144c..0281fb1 100644 --- a/ext/import-font.cpp +++ b/ext/import-font.cpp @@ -74,7 +74,7 @@ static int ftLineTo(const FT_Vector *to, void *user) { FtContext *context = reinterpret_cast(user); Point2 endpoint = ftPoint2(*to); if (endpoint != context->position) { - context->contour->addEdge(new LinearSegment(context->position, endpoint)); + context->contour->addEdge(EdgeHolder(context->position, endpoint)); context->position = endpoint; } return 0; @@ -82,15 +82,21 @@ static int ftLineTo(const FT_Vector *to, void *user) { static int ftConicTo(const FT_Vector *control, const FT_Vector *to, void *user) { FtContext *context = reinterpret_cast(user); - context->contour->addEdge(new QuadraticSegment(context->position, ftPoint2(*control), ftPoint2(*to))); - context->position = ftPoint2(*to); + Point2 endpoint = ftPoint2(*to); + if (endpoint != context->position) { + context->contour->addEdge(EdgeHolder(context->position, ftPoint2(*control), endpoint)); + context->position = endpoint; + } return 0; } static int ftCubicTo(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) { FtContext *context = reinterpret_cast(user); - context->contour->addEdge(new CubicSegment(context->position, ftPoint2(*control1), ftPoint2(*control2), ftPoint2(*to))); - context->position = ftPoint2(*to); + Point2 endpoint = ftPoint2(*to); + if (endpoint != context->position || crossProduct(ftPoint2(*control1)-endpoint, ftPoint2(*control2)-endpoint)) { + context->contour->addEdge(EdgeHolder(context->position, ftPoint2(*control1), ftPoint2(*control2), endpoint)); + context->position = endpoint; + } return 0; } diff --git a/ext/import-svg.cpp b/ext/import-svg.cpp index 8cbb527..86cac76 100644 --- a/ext/import-svg.cpp +++ b/ext/import-svg.cpp @@ -101,7 +101,7 @@ static void addArcApproximate(Contour &contour, Point2 startPoint, Point2 endPoi if (endPoint == startPoint) return; if (radius.x == 0 || radius.y == 0) - return contour.addEdge(new LinearSegment(startPoint, endPoint)); + return contour.addEdge(EdgeHolder(startPoint, endPoint)); radius.x = fabs(radius.x); radius.y = fabs(radius.y); @@ -142,7 +142,7 @@ static void addArcApproximate(Contour &contour, Point2 startPoint, Point2 endPoi d.set(cos(angle), sin(angle)); controlPoint[1] = center+rotateVector(Vector2(d.x+cl*d.y, d.y-cl*d.x)*radius, axis); Point2 node = i == segments-1 ? endPoint : center+rotateVector(d*radius, axis); - contour.addEdge(new CubicSegment(prevNode, controlPoint[0], controlPoint[1], node)); + contour.addEdge(EdgeHolder(prevNode, controlPoint[0], controlPoint[1], node)); prevNode = node; } } @@ -221,19 +221,19 @@ bool buildShapeFromSvgPath(Shape &shape, const char *pathDef, double endpointSna REQUIRE(readCoord(node, pathDef)); if (nodeType == 'l') node += prevNode; - contour.addEdge(new LinearSegment(prevNode, node)); + contour.addEdge(EdgeHolder(prevNode, node)); break; case 'H': case 'h': REQUIRE(readDouble(node.x, pathDef)); if (nodeType == 'h') node.x += prevNode.x; - contour.addEdge(new LinearSegment(prevNode, node)); + contour.addEdge(EdgeHolder(prevNode, node)); break; case 'V': case 'v': REQUIRE(readDouble(node.y, pathDef)); if (nodeType == 'v') node.y += prevNode.y; - contour.addEdge(new LinearSegment(prevNode, node)); + contour.addEdge(EdgeHolder(prevNode, node)); break; case 'Q': case 'q': REQUIRE(readCoord(controlPoint[0], pathDef)); @@ -242,7 +242,7 @@ bool buildShapeFromSvgPath(Shape &shape, const char *pathDef, double endpointSna controlPoint[0] += prevNode; node += prevNode; } - contour.addEdge(new QuadraticSegment(prevNode, controlPoint[0], node)); + contour.addEdge(EdgeHolder(prevNode, controlPoint[0], node)); break; case 'T': case 't': if (prevNodeType == 'Q' || prevNodeType == 'q' || prevNodeType == 'T' || prevNodeType == 't') @@ -252,7 +252,7 @@ bool buildShapeFromSvgPath(Shape &shape, const char *pathDef, double endpointSna REQUIRE(readCoord(node, pathDef)); if (nodeType == 't') node += prevNode; - contour.addEdge(new QuadraticSegment(prevNode, controlPoint[0], node)); + contour.addEdge(EdgeHolder(prevNode, controlPoint[0], node)); break; case 'C': case 'c': REQUIRE(readCoord(controlPoint[0], pathDef)); @@ -263,7 +263,7 @@ bool buildShapeFromSvgPath(Shape &shape, const char *pathDef, double endpointSna controlPoint[1] += prevNode; node += prevNode; } - contour.addEdge(new CubicSegment(prevNode, controlPoint[0], controlPoint[1], node)); + contour.addEdge(EdgeHolder(prevNode, controlPoint[0], controlPoint[1], node)); break; case 'S': case 's': if (prevNodeType == 'C' || prevNodeType == 'c' || prevNodeType == 'S' || prevNodeType == 's') @@ -276,7 +276,7 @@ bool buildShapeFromSvgPath(Shape &shape, const char *pathDef, double endpointSna controlPoint[1] += prevNode; node += prevNode; } - contour.addEdge(new CubicSegment(prevNode, controlPoint[0], controlPoint[1], node)); + contour.addEdge(EdgeHolder(prevNode, controlPoint[0], controlPoint[1], node)); break; case 'A': case 'a': { @@ -309,7 +309,7 @@ bool buildShapeFromSvgPath(Shape &shape, const char *pathDef, double endpointSna if ((contour.edges.back()->point(1)-contour.edges[0]->point(0)).length() < endpointSnapRange) contour.edges.back()->moveEndPoint(contour.edges[0]->point(0)); else - contour.addEdge(new LinearSegment(prevNode, startPoint)); + contour.addEdge(EdgeHolder(prevNode, startPoint)); } prevNode = startPoint; prevNodeType = '\0'; diff --git a/ext/resolve-shape-geometry.cpp b/ext/resolve-shape-geometry.cpp index 9d31d17..3bc1aef 100644 --- a/ext/resolve-shape-geometry.cpp +++ b/ext/resolve-shape-geometry.cpp @@ -53,20 +53,20 @@ void shapeFromSkiaPath(Shape &shape, const SkPath &skPath) { contour = &shape.addContour(); break; case SkPath::kLine_Verb: - contour->addEdge(new LinearSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]))); + contour->addEdge(EdgeHolder(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]))); break; case SkPath::kQuad_Verb: - contour->addEdge(new QuadraticSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]), pointFromSkiaPoint(edgePoints[2]))); + contour->addEdge(EdgeHolder(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]), pointFromSkiaPoint(edgePoints[2]))); break; case SkPath::kCubic_Verb: - contour->addEdge(new CubicSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]), pointFromSkiaPoint(edgePoints[2]), pointFromSkiaPoint(edgePoints[3]))); + contour->addEdge(EdgeHolder(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]), pointFromSkiaPoint(edgePoints[2]), pointFromSkiaPoint(edgePoints[3]))); break; case SkPath::kConic_Verb: { SkPoint quadPoints[5]; SkPath::ConvertConicToQuads(edgePoints[0], edgePoints[1], edgePoints[2], pathIterator.conicWeight(), quadPoints, 1); - contour->addEdge(new QuadraticSegment(pointFromSkiaPoint(quadPoints[0]), pointFromSkiaPoint(quadPoints[1]), pointFromSkiaPoint(quadPoints[2]))); - contour->addEdge(new QuadraticSegment(pointFromSkiaPoint(quadPoints[2]), pointFromSkiaPoint(quadPoints[3]), pointFromSkiaPoint(quadPoints[4]))); + contour->addEdge(EdgeHolder(pointFromSkiaPoint(quadPoints[0]), pointFromSkiaPoint(quadPoints[1]), pointFromSkiaPoint(quadPoints[2]))); + contour->addEdge(EdgeHolder(pointFromSkiaPoint(quadPoints[2]), pointFromSkiaPoint(quadPoints[3]), pointFromSkiaPoint(quadPoints[4]))); } break; case SkPath::kClose_Verb: