Reading SVG into a path

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
beneficii
Earned some good credits
Earned some good credits
Posts: 107
Joined: Fri Nov 27, 2009 2:49 am

Reading SVG into a path

Postby beneficii » Thu Aug 07, 2014 7:49 am

Z/multiple M/and arcs are not supported, but this otherwise loads an SVG path:

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
      }
   }
}


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.

Return to “The Code Dump”

Who is online

Users browsing this forum: No registered users and 2 guests