Reading SVG into a path
Posted: Thu Aug 07, 2014 7:49 am
Z/multiple M/and arcs are not supported, but this otherwise loads an SVG path:
This code will then take the path and work magic on it, by creating offsets, including changing offsets, and creating things like roads with lanes that expand and contract.
Code: Select all
void read_svg(wxString path, fill_path& fpaths) {
bool not_started_flag = true, last_cubic = false, last_quad = false;
for (std::size_t i = 0; i < path.Length; ++i) {
switch (static_cast<char>(path[i])) {
case 'M':
case 'm':
case 'V':
case 'v':
case 'H':
case 'h':
case 'L':
case 'l':
case 'q':
case 'Q':
case 't':
case 'T':
case 'c':
case 'C':
case 's':
case 'S':
case 'a':
case 'A':
path.insert(i + 1, " ");
}
}
wxStringTokenizer tkn(path, ", \t\r\n", wxTOKEN_STRTOK);
wxPoint2DDouble P0(0.0, 0.0);
wxPoint2DDouble P1(0.0, 0.0);
wxPoint2DDouble P2(0.0, 0.0);
wxPoint2DDouble P3(0.0, 0.0);
wxPoint2DDouble Q1(0.0, 0.0);
wxPoint2DDouble Q2(0.0, 0.0);
while (tkn.HasMoreTokens()) {
bool rel = false;
wxString get_tok = tkn.NextToken();
switch (static_cast<char>(get_tok[0])) {
case 'Z': //z not supported
case 'z':
return;
case 'M':
case 'm':
if (not_started_flag) {
not_started_flag = false;
tkn.NextToken().ToCDouble(&static_cast<double>(P0.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(P0.m_y));
}
else return; //multiple m's not supported
break;
case 'v':
rel = true;
case 'V':
P3.m_x = P0.m_x;
tkn.NextToken().ToCDouble(&static_cast<double>(P3.m_y));
if (rel) {
P3.m_y += P0.m_y;
}
P1 = P0;
P2 = P3;
fpaths.insert_line(P0, P3);
P0 = P3;
last_cubic = false;
last_quad = false;
break;
case 'h':
rel = true;
case 'H':
tkn.NextToken().ToCDouble(&static_cast<double>(P3.m_x));
P3.m_y = P0.m_y;
if (rel) {
P3.m_x += P0.m_x;
}
P1 = P0;
P2 = P3;
fpaths.insert_line(P0, P3);
P0 = P3;
last_cubic = false;
last_quad = false;
break;
case 'l':
rel = true;
case 'L':
tkn.NextToken().ToCDouble(&static_cast<double>(P3.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(P3.m_y));
if (rel) {
P3.m_x += P0.m_x;
P3.m_y += P0.m_y;
}
P1 = P0;
P2 = P3;
fpaths.insert_line(P0, P3);
P0 = P3;
last_cubic = false;
last_quad = false;
break;
case 'q':
rel = true;
case 'Q':
tkn.NextToken().ToCDouble(&static_cast<double>(Q1.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(Q1.m_y));
tkn.NextToken().ToCDouble(&static_cast<double>(Q2.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(Q2.m_y));
if (rel) {
Q1.m_x += P0.m_x;
Q1.m_y += P0.m_y;
Q2.m_x += P0.m_x;
Q2.m_y += P0.m_y;
}
//degree elevation here
P1.m_x = (P0.m_x + 2.0 * Q1.m_x) / 3.0;
P1.m_y = (P0.m_y + 2.0 * Q1.m_y) / 3.0;
P2.m_x = (2.0 * Q1.m_x + Q2.m_x) / 3.0;
P2.m_y = (2.0 * Q1.m_y + Q2.m_y) / 3.0;
P3.m_x = Q2.m_x;
P3.m_y = Q2.m_y;
fpaths.insert_path(P0, P1, P2, P3);
P0 = P3;
last_cubic = false;
last_quad = true;
break;
case 't':
rel = true;
case 'T':
if (!last_quad) return;
Q1.m_x = 2.0 * Q2.m_x - Q1.m_x;
Q1.m_y = 2.0 * Q2.m_x - Q1.m_x;
tkn.NextToken().ToCDouble(&static_cast<double>(Q2.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(Q2.m_y));
if (rel) {
Q2.m_x += P0.m_x;
Q2.m_y += P0.m_y;
}
//degree elevation here
P1.m_x = (P0.m_x + 2.0 * Q1.m_x) / 3.0;
P1.m_y = (P0.m_y + 2.0 * Q1.m_y) / 3.0;
P2.m_x = (2.0 * Q1.m_x + Q2.m_x) / 3.0;
P2.m_y = (2.0 * Q1.m_y + Q2.m_y) / 3.0;
P3.m_x = Q2.m_x;
P3.m_y = Q2.m_y;
fpaths.insert_path(P0, P1, P2, P3);
P0 = P3;
break;
case 'c':
rel = true;
case 'C':
tkn.NextToken().ToCDouble(&static_cast<double>(P1.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(P1.m_y));
tkn.NextToken().ToCDouble(&static_cast<double>(P2.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(P2.m_y));
tkn.NextToken().ToCDouble(&static_cast<double>(P3.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(P3.m_y));
if (rel) {
P1.m_x += P0.m_x;
P1.m_y += P0.m_y;
P2.m_x += P0.m_x;
P2.m_y += P0.m_y;
P3.m_x += P0.m_x;
P3.m_y += P0.m_y;
}
fpaths.insert_path(P0, P1, P2, P3);
P0 = P3;
last_cubic = true;
last_quad = false;
break;
case 's':
rel = true;
case 'S':
if (!last_cubic) return;
tkn.NextToken().ToCDouble(&static_cast<double>(P2.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(P2.m_y));
tkn.NextToken().ToCDouble(&static_cast<double>(P3.m_x));
tkn.NextToken().ToCDouble(&static_cast<double>(P3.m_y));
if (rel) {
P2.m_x += P0.m_x;
P2.m_y += P0.m_y;
P3.m_x += P0.m_x;
P3.m_y += P0.m_y;
}
fpaths.insert_path(P2, P3);
P0 = P3;
break;
default:
return; //arcs not supported
}
}
}