mirror of https://github.com/Chlumsky/msdfgen.git
Improved edge segment construction
This commit is contained in:
parent
51f6b5b053
commit
2357140784
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ static int ftLineTo(const FT_Vector *to, void *user) {
|
|||
FtContext *context = reinterpret_cast<FtContext *>(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<FtContext *>(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<FtContext *>(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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue