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; }
|
#define REQUIRE(cond) { if (!(cond)) return false; }
|
||||||
#endif
|
#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) {
|
static bool readNodeType(char &output, const char *&pathDef) {
|
||||||
int shift;
|
skipExtraChars(pathDef);
|
||||||
char nodeType;
|
char nodeType = *pathDef;
|
||||||
if (sscanf(pathDef, " %c%n", &nodeType, &shift) == 1 && nodeType != '+' && nodeType != '-' && nodeType != '.' && nodeType != ',' && (nodeType < '0' || nodeType > '9')) {
|
if (nodeType && nodeType != '+' && nodeType != '-' && nodeType != '.' && nodeType != ',' && (nodeType < '0' || nodeType > '9')) {
|
||||||
pathDef += shift;
|
++pathDef;
|
||||||
output = nodeType;
|
output = nodeType;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -33,6 +38,7 @@ static bool readNodeType(char &output, const char *&pathDef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool readCoord(Point2 &output, const char *&pathDef) {
|
static bool readCoord(Point2 &output, const char *&pathDef) {
|
||||||
|
skipExtraChars(pathDef);
|
||||||
int shift;
|
int shift;
|
||||||
double x, y;
|
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) {
|
||||||
|
|
@ -45,6 +51,7 @@ static bool readCoord(Point2 &output, const char *&pathDef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool readDouble(double &output, const char *&pathDef) {
|
static bool readDouble(double &output, const char *&pathDef) {
|
||||||
|
skipExtraChars(pathDef);
|
||||||
int shift;
|
int shift;
|
||||||
double v;
|
double v;
|
||||||
if (sscanf(pathDef, "%lf%n", &v, &shift) == 1) {
|
if (sscanf(pathDef, "%lf%n", &v, &shift) == 1) {
|
||||||
|
|
@ -56,6 +63,7 @@ static bool readDouble(double &output, const char *&pathDef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool readBool(bool &output, const char *&pathDef) {
|
static bool readBool(bool &output, const char *&pathDef) {
|
||||||
|
skipExtraChars(pathDef);
|
||||||
int shift;
|
int shift;
|
||||||
int v;
|
int v;
|
||||||
if (sscanf(pathDef, "%d%n", &v, &shift) == 1) {
|
if (sscanf(pathDef, "%d%n", &v, &shift) == 1) {
|
||||||
|
|
@ -66,17 +74,6 @@ static bool readBool(bool &output, const char *&pathDef) {
|
||||||
return false;
|
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) {
|
static double arcAngle(Vector2 u, Vector2 v) {
|
||||||
return nonZeroSign(crossProduct(u, v))*acos(clamp(dotProduct(u, v)/(u.length()*v.length()), -1., +1.));
|
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) {
|
static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
||||||
char nodeType;
|
char nodeType = '\0';
|
||||||
|
char prevNodeType = '\0';
|
||||||
Point2 prevNode(0, 0);
|
Point2 prevNode(0, 0);
|
||||||
bool nodeTypePreread = false;
|
bool nodeTypePreread = false;
|
||||||
while (nodeTypePreread || readNodeType(nodeType, pathDef)) {
|
while (nodeTypePreread || readNodeType(nodeType, pathDef)) {
|
||||||
|
|
@ -184,7 +182,6 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
||||||
break;
|
break;
|
||||||
case 'Q': case 'q':
|
case 'Q': case 'q':
|
||||||
REQUIRE(readCoord(controlPoint[0], pathDef));
|
REQUIRE(readCoord(controlPoint[0], pathDef));
|
||||||
consumeOptionalComma(pathDef);
|
|
||||||
REQUIRE(readCoord(node, pathDef));
|
REQUIRE(readCoord(node, pathDef));
|
||||||
if (nodeType == 'q') {
|
if (nodeType == 'q') {
|
||||||
controlPoint[0] += prevNode;
|
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));
|
contour.addEdge(new QuadraticSegment(prevNode, controlPoint[0], node));
|
||||||
break;
|
break;
|
||||||
case 'T': case 't':
|
case 'T': case 't':
|
||||||
|
if (prevNodeType == 'Q' || prevNodeType == 'q' || prevNodeType == 'T' || prevNodeType == 't')
|
||||||
controlPoint[0] = node+node-controlPoint[0];
|
controlPoint[0] = node+node-controlPoint[0];
|
||||||
|
else
|
||||||
|
controlPoint[0] = node;
|
||||||
REQUIRE(readCoord(node, pathDef));
|
REQUIRE(readCoord(node, pathDef));
|
||||||
if (nodeType == 't')
|
if (nodeType == 't')
|
||||||
node += prevNode;
|
node += prevNode;
|
||||||
|
|
@ -201,9 +201,7 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
||||||
break;
|
break;
|
||||||
case 'C': case 'c':
|
case 'C': case 'c':
|
||||||
REQUIRE(readCoord(controlPoint[0], pathDef));
|
REQUIRE(readCoord(controlPoint[0], pathDef));
|
||||||
consumeOptionalComma(pathDef);
|
|
||||||
REQUIRE(readCoord(controlPoint[1], pathDef));
|
REQUIRE(readCoord(controlPoint[1], pathDef));
|
||||||
consumeOptionalComma(pathDef);
|
|
||||||
REQUIRE(readCoord(node, pathDef));
|
REQUIRE(readCoord(node, pathDef));
|
||||||
if (nodeType == 'c') {
|
if (nodeType == 'c') {
|
||||||
controlPoint[0] += prevNode;
|
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));
|
contour.addEdge(new CubicSegment(prevNode, controlPoint[0], controlPoint[1], node));
|
||||||
break;
|
break;
|
||||||
case 'S': case 's':
|
case 'S': case 's':
|
||||||
|
if (prevNodeType == 'C' || prevNodeType == 'c' || prevNodeType == 'S' || prevNodeType == 's')
|
||||||
controlPoint[0] = node+node-controlPoint[1];
|
controlPoint[0] = node+node-controlPoint[1];
|
||||||
|
else
|
||||||
|
controlPoint[0] = node;
|
||||||
REQUIRE(readCoord(controlPoint[1], pathDef));
|
REQUIRE(readCoord(controlPoint[1], pathDef));
|
||||||
consumeOptionalComma(pathDef);
|
|
||||||
REQUIRE(readCoord(node, pathDef));
|
REQUIRE(readCoord(node, pathDef));
|
||||||
if (nodeType == 's') {
|
if (nodeType == 's') {
|
||||||
controlPoint[1] += prevNode;
|
controlPoint[1] += prevNode;
|
||||||
|
|
@ -230,13 +230,9 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
||||||
bool largeArg;
|
bool largeArg;
|
||||||
bool sweep;
|
bool sweep;
|
||||||
REQUIRE(readCoord(radius, pathDef));
|
REQUIRE(readCoord(radius, pathDef));
|
||||||
consumeOptionalComma(pathDef);
|
|
||||||
REQUIRE(readDouble(angle, pathDef));
|
REQUIRE(readDouble(angle, pathDef));
|
||||||
consumeOptionalComma(pathDef);
|
|
||||||
REQUIRE(readBool(largeArg, pathDef));
|
REQUIRE(readBool(largeArg, pathDef));
|
||||||
consumeOptionalComma(pathDef);
|
|
||||||
REQUIRE(readBool(sweep, pathDef));
|
REQUIRE(readBool(sweep, pathDef));
|
||||||
consumeOptionalComma(pathDef);
|
|
||||||
REQUIRE(readCoord(node, pathDef));
|
REQUIRE(readCoord(node, pathDef));
|
||||||
if (nodeType == 'a')
|
if (nodeType == 'a')
|
||||||
node += prevNode;
|
node += prevNode;
|
||||||
|
|
@ -249,8 +245,8 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
|
||||||
}
|
}
|
||||||
contourStart &= nodeType == 'M' || nodeType == 'm';
|
contourStart &= nodeType == 'M' || nodeType == 'm';
|
||||||
prevNode = node;
|
prevNode = node;
|
||||||
|
prevNodeType = nodeType;
|
||||||
readNodeType(nodeType, pathDef);
|
readNodeType(nodeType, pathDef);
|
||||||
consumeWhitespace(pathDef);
|
|
||||||
}
|
}
|
||||||
NEXT_CONTOUR:
|
NEXT_CONTOUR:
|
||||||
// Fix contour if it isn't properly closed
|
// 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));
|
contour.addEdge(new LinearSegment(prevNode, startPoint));
|
||||||
}
|
}
|
||||||
prevNode = startPoint;
|
prevNode = startPoint;
|
||||||
|
prevNodeType = '\0';
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue