Blame onefile/svg-path.inc.h

a5e8d6
a5e8d6
#define SP_PRECISION 0.5
a5e8d6
a5e8d6
a5e8d6
int spStarted = FALSE;
a5e8d6
double spStartX = 0, spStartY = 0;
a5e8d6
double spPenX = 0, spPenY = 0;
a5e8d6
a5e8d6
a5e8d6
void spSkipSpace(const char **pos)
a5e8d6
  { while(**pos && isspace(**pos)) ++*pos; }
a5e8d6
a5e8d6
a5e8d6
double spReadNum(const char **pos) {
a5e8d6
  spSkipSpace(pos);
a5e8d6
  char *end = "";
a5e8d6
  double x = strtod(*pos, &end);
a5e8d6
  *pos = end;
a5e8d6
  return x;
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
double spMax(double a, double b)
a5e8d6
  { return a > b ? a : b; }
a5e8d6
a5e8d6
a5e8d6
void spMoveTo(double x, double y) {
a5e8d6
  if (spStarted) strokePath();
a5e8d6
  spStarted = TRUE;
a5e8d6
  moveTo(x, y);
a5e8d6
  spStartX = spPenX = x;
a5e8d6
  spStartY = spPenY = y;
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void spLineTo(double x, double y) {
a5e8d6
  if (!spStarted) spMoveTo(spPenX, spPenY);
a5e8d6
  lineTo(x, y);
a5e8d6
  spPenX = x;
a5e8d6
  spPenY = y;
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void spClose() {
a5e8d6
  if (spStarted) { lineTo(spStartX, spStartY); closePath(); }
a5e8d6
  spMoveTo(spStartX, spStartY);
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void spQuadraticTo(double x1, double y1, double x2, double y2) {
a5e8d6
  double dx = spMax(x1 - spPenX, x2 - spPenX);
a5e8d6
  double dy = spMax(y1 - spPenY, y2 - spPenY);
a5e8d6
  if (dx*dx + dy*dy <= SP_PRECISION*SP_PRECISION) {
a5e8d6
    spLineTo(x2, y2);
a5e8d6
    return;
a5e8d6
  }
a5e8d6
a5e8d6
  double xx0 = 0.5*(spPenX + x1);
a5e8d6
  double yy0 = 0.5*(spPenY + y1);
a5e8d6
a5e8d6
  double xx1 = 0.5*(x1 + x2);
a5e8d6
  double yy1 = 0.5*(y1 + y2);
a5e8d6
a5e8d6
  double xxx0 = 0.5*(xx0 + xx1);
a5e8d6
  double yyy0 = 0.5*(yy0 + yy1);
a5e8d6
a5e8d6
  spQuadraticTo(xx0, yy0, xxx0, yyy0);
a5e8d6
  spQuadraticTo(xx1, yy1, x2, y2);
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void spCurveTo(double x1, double y1, double x2, double y2, double x3, double y3) {
a5e8d6
  double dx = spMax(spMax(x1 - spPenX, x2 - spPenX), x3 - spPenX);
a5e8d6
  double dy = spMax(spMax(y1 - spPenY, y2 - spPenY), y3 - spPenY);
a5e8d6
  if (dx*dx + dy*dy <= SP_PRECISION*SP_PRECISION) {
a5e8d6
    spLineTo(x2, y2);
a5e8d6
    return;
a5e8d6
  }
a5e8d6
a5e8d6
  double xx0 = 0.5*(spPenX + x1);
a5e8d6
  double yy0 = 0.5*(spPenY + y1);
a5e8d6
a5e8d6
  double xx1 = 0.5*(x1 + x2);
a5e8d6
  double yy1 = 0.5*(y1 + y2);
a5e8d6
a5e8d6
  double xx2 = 0.5*(x2 + x3);
a5e8d6
  double yy2 = 0.5*(y2 + y3);
a5e8d6
a5e8d6
  double xxx0 = 0.5*(xx0 + xx1);
a5e8d6
  double yyy0 = 0.5*(yy0 + yy1);
a5e8d6
a5e8d6
  double xxx1 = 0.5*(xx1 + xx2);
a5e8d6
  double yyy1 = 0.5*(yy1 + yy2);
a5e8d6
a5e8d6
  double xxxx0 = 0.5*(xxx0 + xxx1);
a5e8d6
  double yyyy0 = 0.5*(yyy0 + yyy1);
a5e8d6
a5e8d6
  spCurveTo(xx0, yy0, xxx0, yyy0, xxxx0, yyyy0);
a5e8d6
  spCurveTo(xxx1, yyy1, xx2, yy2, x3, y3);
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void spParse(const char *path) {
a5e8d6
  double x1, x2, x3;
a5e8d6
  double y1, y2, y3;
a5e8d6
  const char *c = path;
a5e8d6
  spSkipSpace(&c);
a5e8d6
  while(*c) {
a5e8d6
    switch(*c++) {
a5e8d6
    case 'M':
a5e8d6
      x1 = spReadNum(&c);
a5e8d6
      y1 = spReadNum(&c);
a5e8d6
      spMoveTo(x1, y1);
a5e8d6
      break;
a5e8d6
    case 'm':
a5e8d6
      x1 = spPenX + spReadNum(&c);
a5e8d6
      y1 = spPenY + spReadNum(&c);
a5e8d6
      spMoveTo(x1, y1);
a5e8d6
      break;
a5e8d6
    case 'L':
a5e8d6
      x1 = spReadNum(&c);
a5e8d6
      y1 = spReadNum(&c);
a5e8d6
      spLineTo(x1, y1);
a5e8d6
      break;
a5e8d6
    case 'l':
a5e8d6
      x1 = spPenX + spReadNum(&c);
a5e8d6
      y1 = spPenY + spReadNum(&c);
a5e8d6
      spLineTo(x1, y1);
a5e8d6
      break;
a5e8d6
    case 'Q':
a5e8d6
      x1 = spReadNum(&c);
a5e8d6
      y1 = spReadNum(&c);
a5e8d6
      x2 = spReadNum(&c);
a5e8d6
      y2 = spReadNum(&c);
a5e8d6
      spQuadraticTo(x1, y1, x2, y2);
a5e8d6
      break;
a5e8d6
    case 'q':
a5e8d6
      x1 = spPenX + spReadNum(&c);
a5e8d6
      y1 = spPenY + spReadNum(&c);
a5e8d6
      x2 = spPenX + spReadNum(&c);
a5e8d6
      y2 = spPenY + spReadNum(&c);
a5e8d6
      spQuadraticTo(x1, y1, x2, y2);
a5e8d6
      break;
a5e8d6
    case 'C':
a5e8d6
      x1 = spReadNum(&c);
a5e8d6
      y1 = spReadNum(&c);
a5e8d6
      x2 = spReadNum(&c);
a5e8d6
      y2 = spReadNum(&c);
a5e8d6
      x3 = spReadNum(&c);
a5e8d6
      y3 = spReadNum(&c);
a5e8d6
      spCurveTo(x1, y1, x2, y2, x3, y3);
a5e8d6
      break;
a5e8d6
    case 'c':
a5e8d6
      x1 = spPenX + spReadNum(&c);
a5e8d6
      y1 = spPenY + spReadNum(&c);
a5e8d6
      x2 = spPenX + spReadNum(&c);
a5e8d6
      y2 = spPenY + spReadNum(&c);
a5e8d6
      x3 = spPenX + spReadNum(&c);
a5e8d6
      y3 = spPenY + spReadNum(&c);
a5e8d6
      spCurveTo(x1, y1, x2, y2, x3, y3);
a5e8d6
      break;
a5e8d6
    case 'Z':
a5e8d6
    case 'z':
a5e8d6
      spClose();
a5e8d6
      break;
a5e8d6
    default:
a5e8d6
      printf("unknown path command \'%c\'\n", *(c - 1));
a5e8d6
    }
a5e8d6
    spSkipSpace(&c);
a5e8d6
  }
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void spTrack(const char *path, double *x, double *y) {
a5e8d6
  double sx = *x, sy = *y;
a5e8d6
  const char *c = path;
a5e8d6
  spSkipSpace(&c);
a5e8d6
  while(*c) {
a5e8d6
    switch(*c++) {
a5e8d6
    case 'M':
a5e8d6
      sx = (*x = spReadNum(&c));
a5e8d6
      sy = (*y = spReadNum(&c));
a5e8d6
      break;
a5e8d6
    case 'm':
a5e8d6
      sx = (*x += spReadNum(&c));
a5e8d6
      sy = (*y += spReadNum(&c));
a5e8d6
      break;
a5e8d6
a5e8d6
    case 'C':
a5e8d6
      spReadNum(&c);
a5e8d6
      spReadNum(&c);
a5e8d6
    case 'Q':
a5e8d6
      spReadNum(&c);
a5e8d6
      spReadNum(&c);
a5e8d6
    case 'L':
a5e8d6
      *x = spReadNum(&c);
a5e8d6
      *y = spReadNum(&c);
a5e8d6
      break;
a5e8d6
a5e8d6
    case 'c':
a5e8d6
      spReadNum(&c);
a5e8d6
      spReadNum(&c);
a5e8d6
    case 'q':
a5e8d6
      spReadNum(&c);
a5e8d6
      spReadNum(&c);
a5e8d6
    case 'l':
a5e8d6
      *x += spReadNum(&c);
a5e8d6
      *y += spReadNum(&c);
a5e8d6
      break;
a5e8d6
a5e8d6
    case 'Z':
a5e8d6
    case 'z':
a5e8d6
      *x = sx;
a5e8d6
      *y = sy;
a5e8d6
      break;
a5e8d6
    default:
a5e8d6
      printf("unknown path command \'%c\'\n", *(c - 1));
a5e8d6
    }
a5e8d6
    spSkipSpace(&c);
a5e8d6
  }
a5e8d6
}
a5e8d6