mirror of https://github.com/Chlumsky/msdfgen.git
SVG importer fixes: S, T curve commands, surplus commas
This commit is contained in:
parent
746767a62b
commit
28ee740a33
|
|
@ -21,11 +21,16 @@ namespace msdfgen {
|
|||
#define REQUIRE(cond) { if (!(cond)) return false; }
|
||||
#endif
|
||||
|
||||
static void skipExtraChars(const char *&pathDef) {
|
||||
while (*pathDef == ',' || *pathDef == ' ' || *pathDef == '\t' || *pathDef == '\r' || *pathDef == '\n')
|
||||
++pathDef;
|
||||
}
|
||||
|
||||
static bool readNodeType(char &output, const char *&pathDef) {
|
||||
int shift;
|
||||
char nodeType;
|
||||
if (sscanf(pathDef, " %c%n", &nodeType, &shift) == 1 && nodeType != '+' && nodeType != '-' && nodeType != '.' && nodeType != ',' && (nodeType < '0' || nodeType > '9')) {
|
||||
pathDef += shift;
|
||||
skipExtraChars(pathDef);
|
||||
char nodeType = *pathDef;
|
||||
if (nodeType && nodeType != '+' && nodeType != '-' && nodeType != '.' && nodeType != ',' && (nodeType < '0' || nodeType > '9')) {
|
||||
++pathDef;
|
||||
output = nodeType;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -33,9 +38,10 @@ static bool readNodeType(char &output, const char *&pathDef) {
|
|||
}
|
||||
|
||||
static bool readCoord(Point2 &output, const char *&pathDef) {
|
||||
skipExtraChars(pathDef);
|
||||
int shift;
|
||||
double x, y;
|
||||
if (sscanf(pathDef, " %lf%lf%n", &x, &y, &shift) == 2 || sscanf(pathDef, " %lf , %lf%n", &x, &y, &shift) == 2) {
|
||||
if (sscanf(pathDef, "%lf%lf%n", &x, &y, &shift) == 2 || sscanf(pathDef, "%lf , %lf%n", &x, &y, &shift) == 2) {
|
||||
output.x = x;
|
||||
output.y = y;
|
||||
pathDef += shift;
|
||||
|
|
@ -45,9 +51,10 @@ static bool readCoord(Point2 &output, const char *&pathDef) {
|
|||
}
|
||||
|
||||
static bool readDouble(double &output, const char *&pathDef) {
|
||||
skipExtraChars(pathDef);
|
||||
int shift;
|
||||
double v;
|
||||
if (sscanf(pathDef, " %lf%n", &v, &shift) == 1) {
|
||||
if (sscanf(pathDef, "%lf%n", &v, &shift) == 1) {
|
||||
pathDef += shift;
|
||||
output = v;
|
||||
return true;
|
||||
|
|
@ -56,9 +63,10 @@ static bool readDouble(double &output, const char *&pathDef) {
|
|||
}
|
||||
|
||||
static bool readBool(bool &output, const char *&pathDef) {
|
||||
skipExtraChars(pathDef);
|
||||
int shift;
|
||||
int v;
|
||||
if (sscanf(pathDef, " %d%n", &v, &shift) == 1) {
|
||||
if (sscanf(pathDef, "%d%n", &v, &shift) == 1) {
|
||||
pathDef += shift;
|
||||
output = v != 0;
|
||||
return true;
|
||||
|
|
@ -66,17 +74,6 @@ static bool readBool(bool &output, const char *&pathDef) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static void consumeWhitespace(const char *&pathDef) {
|
||||
while (*pathDef == ' ' || *pathDef == '\t' || *pathDef == '\r' || *pathDef == '\n')
|
||||
++pathDef;
|
||||
}
|
||||
|
||||
static void consumeOptionalComma(const char *&pathDef) {
|
||||
consumeWhitespace(pathDef);
|
||||
if (*pathDef == ',')
|
||||
++pathDef;
|
||||
}
|
||||
|
||||
static double arcAngle(Vector2 u, Vector2 v) {
|
||||
return nonZeroSign(crossProduct(u, v))*acos(clamp(dotProduct(u, v)/(u.length()*v.length()), -1., +1.));
|
||||
}
|
||||
|
|
@ -136,7 +133,8 @@ static void addArcApproximate(Contour &contour, Point2 startPoint, Point2 endPoi
|
|||
}
|
||||
|
||||
static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
||||
char nodeType;
|
||||
char nodeType = '\0';
|
||||
char prevNodeType = '\0';
|
||||
Point2 prevNode(0, 0);
|
||||
bool nodeTypePreread = false;
|
||||
while (nodeTypePreread || readNodeType(nodeType, pathDef)) {
|
||||
|
|
@ -184,7 +182,6 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
|||
break;
|
||||
case 'Q': case 'q':
|
||||
REQUIRE(readCoord(controlPoint[0], pathDef));
|
||||
consumeOptionalComma(pathDef);
|
||||
REQUIRE(readCoord(node, pathDef));
|
||||
if (nodeType == 'q') {
|
||||
controlPoint[0] += prevNode;
|
||||
|
|
@ -193,7 +190,10 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
|||
contour.addEdge(new QuadraticSegment(prevNode, controlPoint[0], node));
|
||||
break;
|
||||
case 'T': case 't':
|
||||
controlPoint[0] = node+node-controlPoint[0];
|
||||
if (prevNodeType == 'Q' || prevNodeType == 'q' || prevNodeType == 'T' || prevNodeType == 't')
|
||||
controlPoint[0] = node+node-controlPoint[0];
|
||||
else
|
||||
controlPoint[0] = node;
|
||||
REQUIRE(readCoord(node, pathDef));
|
||||
if (nodeType == 't')
|
||||
node += prevNode;
|
||||
|
|
@ -201,9 +201,7 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
|||
break;
|
||||
case 'C': case 'c':
|
||||
REQUIRE(readCoord(controlPoint[0], pathDef));
|
||||
consumeOptionalComma(pathDef);
|
||||
REQUIRE(readCoord(controlPoint[1], pathDef));
|
||||
consumeOptionalComma(pathDef);
|
||||
REQUIRE(readCoord(node, pathDef));
|
||||
if (nodeType == 'c') {
|
||||
controlPoint[0] += prevNode;
|
||||
|
|
@ -213,9 +211,11 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
|||
contour.addEdge(new CubicSegment(prevNode, controlPoint[0], controlPoint[1], node));
|
||||
break;
|
||||
case 'S': case 's':
|
||||
controlPoint[0] = node+node-controlPoint[1];
|
||||
if (prevNodeType == 'C' || prevNodeType == 'c' || prevNodeType == 'S' || prevNodeType == 's')
|
||||
controlPoint[0] = node+node-controlPoint[1];
|
||||
else
|
||||
controlPoint[0] = node;
|
||||
REQUIRE(readCoord(controlPoint[1], pathDef));
|
||||
consumeOptionalComma(pathDef);
|
||||
REQUIRE(readCoord(node, pathDef));
|
||||
if (nodeType == 's') {
|
||||
controlPoint[1] += prevNode;
|
||||
|
|
@ -230,13 +230,9 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
|||
bool largeArg;
|
||||
bool sweep;
|
||||
REQUIRE(readCoord(radius, pathDef));
|
||||
consumeOptionalComma(pathDef);
|
||||
REQUIRE(readDouble(angle, pathDef));
|
||||
consumeOptionalComma(pathDef);
|
||||
REQUIRE(readBool(largeArg, pathDef));
|
||||
consumeOptionalComma(pathDef);
|
||||
REQUIRE(readBool(sweep, pathDef));
|
||||
consumeOptionalComma(pathDef);
|
||||
REQUIRE(readCoord(node, pathDef));
|
||||
if (nodeType == 'a')
|
||||
node += prevNode;
|
||||
|
|
@ -249,8 +245,8 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
|||
}
|
||||
contourStart &= nodeType == 'M' || nodeType == 'm';
|
||||
prevNode = node;
|
||||
prevNodeType = nodeType;
|
||||
readNodeType(nodeType, pathDef);
|
||||
consumeWhitespace(pathDef);
|
||||
}
|
||||
NEXT_CONTOUR:
|
||||
// Fix contour if it isn't properly closed
|
||||
|
|
@ -261,6 +257,7 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
|||
contour.addEdge(new LinearSegment(prevNode, startPoint));
|
||||
}
|
||||
prevNode = startPoint;
|
||||
prevNodeType = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue