/**
   * This is where the hard-to-parse paths are handled. Uppercase rules are absolute positions,
   * lowercase are relative. Types of path rules:
   *
   * <p>
   *
   * <ol>
   *   <li>M/m - (x y)+ - Move to (without drawing)
   *   <li>Z/z - (no params) - Close path (back to starting point)
   *   <li>L/l - (x y)+ - Line to
   *   <li>H/h - x+ - Horizontal ine to
   *   <li>V/v - y+ - Vertical line to
   *   <li>C/c - (x1 y1 x2 y2 x y)+ - Cubic bezier to
   *   <li>S/s - (x2 y2 x y)+ - Smooth cubic bezier to (shorthand that assumes the x2, y2 from
   *       previous C/S is the x1, y1 of this bezier)
   *   <li>Q/q - (x1 y1 x y)+ - Quadratic bezier to
   *   <li>T/t - (x y)+ - Smooth quadratic bezier to (assumes previous control point is "reflection"
   *       of last one w.r.t. to current point)
   * </ol>
   *
   * <p>Numbers are separate by whitespace, comma or nothing at all (!) if they are self-delimiting,
   * (ie. begin with a - sign)
   *
   * @param s the path string from the XML
   */
  private static Path doPath(String s) {
    int n = s.length();
    ParserHelper ph = new ParserHelper(s, 0);
    ph.skipWhitespace();
    Path p = new Path();
    float lastX = 0;
    float lastY = 0;
    float lastX1 = 0;
    float lastY1 = 0;
    float subPathStartX = 0;
    float subPathStartY = 0;
    char prevCmd = 0;
    while (ph.pos < n) {
      char cmd = s.charAt(ph.pos);
      switch (cmd) {
        case '-':
        case '+':
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          if (prevCmd == 'm' || prevCmd == 'M') {
            cmd = (char) (((int) prevCmd) - 1);
            break;
          } else if (prevCmd == 'c' || prevCmd == 'C') {
            cmd = prevCmd;
            break;
          } else if (prevCmd == 'l' || prevCmd == 'L') {
            cmd = prevCmd;
            break;
          }
        default:
          {
            ph.advance();
            prevCmd = cmd;
          }
      }

      boolean wasCurve = false;
      switch (cmd) {
        case 'M':
        case 'm':
          {
            float x = ph.nextFloat();
            float y = ph.nextFloat();
            if (cmd == 'm') {
              subPathStartX += x;
              subPathStartY += y;
              p.rMoveTo(x, y);
              lastX += x;
              lastY += y;
            } else {
              subPathStartX = x;
              subPathStartY = y;
              p.moveTo(x, y);
              lastX = x;
              lastY = y;
            }
            break;
          }
        case 'Z':
        case 'z':
          {
            p.close();
            p.moveTo(subPathStartX, subPathStartY);
            lastX = subPathStartX;
            lastY = subPathStartY;
            lastX1 = subPathStartX;
            lastY1 = subPathStartY;
            wasCurve = true;
            break;
          }
        case 'L':
        case 'l':
          {
            float x = ph.nextFloat();
            float y = ph.nextFloat();
            if (cmd == 'l') {
              p.rLineTo(x, y);
              lastX += x;
              lastY += y;
            } else {
              p.lineTo(x, y);
              lastX = x;
              lastY = y;
            }
            break;
          }
        case 'H':
        case 'h':
          {
            float x = ph.nextFloat();
            if (cmd == 'h') {
              p.rLineTo(x, 0);
              lastX += x;
            } else {
              p.lineTo(x, lastY);
              lastX = x;
            }
            break;
          }
        case 'V':
        case 'v':
          {
            float y = ph.nextFloat();
            if (cmd == 'v') {
              p.rLineTo(0, y);
              lastY += y;
            } else {
              p.lineTo(lastX, y);
              lastY = y;
            }
            break;
          }
        case 'C':
        case 'c':
          {
            wasCurve = true;
            float x1 = ph.nextFloat();
            float y1 = ph.nextFloat();
            float x2 = ph.nextFloat();
            float y2 = ph.nextFloat();
            float x = ph.nextFloat();
            float y = ph.nextFloat();
            if (cmd == 'c') {
              x1 += lastX;
              x2 += lastX;
              x += lastX;
              y1 += lastY;
              y2 += lastY;
              y += lastY;
            }
            p.cubicTo(x1, y1, x2, y2, x, y);
            lastX1 = x2;
            lastY1 = y2;
            lastX = x;
            lastY = y;
            break;
          }
        case 'S':
        case 's':
          {
            wasCurve = true;
            float x2 = ph.nextFloat();
            float y2 = ph.nextFloat();
            float x = ph.nextFloat();
            float y = ph.nextFloat();
            if (cmd == 's') {
              x2 += lastX;
              x += lastX;
              y2 += lastY;
              y += lastY;
            }
            float x1 = 2 * lastX - lastX1;
            float y1 = 2 * lastY - lastY1;
            p.cubicTo(x1, y1, x2, y2, x, y);
            lastX1 = x2;
            lastY1 = y2;
            lastX = x;
            lastY = y;
            break;
          }
        case 'A':
        case 'a':
          {
            float rx = ph.nextFloat();
            float ry = ph.nextFloat();
            float theta = ph.nextFloat();
            int largeArc = (int) ph.nextFloat();
            int sweepArc = (int) ph.nextFloat();
            float x = ph.nextFloat();
            float y = ph.nextFloat();
            drawArc(p, lastX, lastY, x, y, rx, ry, theta, largeArc, sweepArc);
            lastX = x;
            lastY = y;
            break;
          }
      }
      if (!wasCurve) {
        lastX1 = lastX;
        lastY1 = lastY;
      }
      ph.skipWhitespace();
    }
    return p;
  }
Ejemplo n.º 2
0
  // draw path 96x96
  public static void calcTurnPath(Path pathForTurn, TurnType turnType, Matrix transform) {
    if (turnType == null) {
      return;
    }
    pathForTurn.reset();

    int c = 48;
    int w = 16;
    pathForTurn.moveTo(c, 94);
    float sarrowL = 30; // side of arrow
    float harrowL = (float) Math.sqrt(2) * sarrowL; // hypotenuse of arrow
    float spartArrowL = (float) ((sarrowL - w / Math.sqrt(2)) / 2);
    float hpartArrowL = (float) (harrowL - w) / 2;

    if (TurnType.C.equals(turnType.getValue())) {
      int h = 65;

      pathForTurn.rMoveTo(w / 2, 0);
      pathForTurn.rLineTo(0, -h);
      pathForTurn.rLineTo(hpartArrowL, 0);
      pathForTurn.rLineTo(-harrowL / 2, -harrowL / 2); // center
      pathForTurn.rLineTo(-harrowL / 2, harrowL / 2);
      pathForTurn.rLineTo(hpartArrowL, 0);
      pathForTurn.rLineTo(0, h);
    } else if (TurnType.TR.equals(turnType.getValue()) || TurnType.TL.equals(turnType.getValue())) {
      int b = TurnType.TR.equals(turnType.getValue()) ? 1 : -1;
      int h = 36;
      float quadShiftX = 22;
      float quadShiftY = 22;

      pathForTurn.rMoveTo(-b * 8, 0);
      pathForTurn.rLineTo(0, -h);
      pathForTurn.rQuadTo(0, -quadShiftY, b * quadShiftX, -quadShiftY);
      pathForTurn.rLineTo(0, hpartArrowL);
      pathForTurn.rLineTo(b * harrowL / 2, -harrowL / 2); // center
      pathForTurn.rLineTo(-b * harrowL / 2, -harrowL / 2);
      pathForTurn.rLineTo(0, hpartArrowL);
      pathForTurn.rQuadTo(-b * (quadShiftX + w), 0, -b * (quadShiftX + w), quadShiftY + w);
      pathForTurn.rLineTo(0, h);
    } else if (TurnType.TSLR.equals(turnType.getValue())
        || TurnType.TSLL.equals(turnType.getValue())) {
      int b = TurnType.TSLR.equals(turnType.getValue()) ? 1 : -1;
      int h = 40;
      int quadShiftY = 22;
      float quadShiftX = (float) (quadShiftY / (1 + Math.sqrt(2)));
      float nQuadShiftX = (sarrowL - 2 * spartArrowL) - quadShiftX - w;
      float nQuadShifty = quadShiftY + (sarrowL - 2 * spartArrowL);

      pathForTurn.rMoveTo(-b * 4, 0);
      pathForTurn.rLineTo(0, -h /* + partArrowL */);
      pathForTurn.rQuadTo(
          0,
          -quadShiftY + quadShiftX /*- partArrowL*/,
          b * quadShiftX,
          -quadShiftY /*- partArrowL*/);
      pathForTurn.rLineTo(b * spartArrowL, spartArrowL);
      pathForTurn.rLineTo(0, -sarrowL); // center
      pathForTurn.rLineTo(-b * sarrowL, 0);
      pathForTurn.rLineTo(b * spartArrowL, spartArrowL);
      pathForTurn.rQuadTo(b * nQuadShiftX, -nQuadShiftX, b * nQuadShiftX, nQuadShifty);
      pathForTurn.rLineTo(0, h);
    } else if (TurnType.TSHR.equals(turnType.getValue())
        || TurnType.TSHL.equals(turnType.getValue())) {
      int b = TurnType.TSHR.equals(turnType.getValue()) ? 1 : -1;
      int h = 45;
      float quadShiftX = 22;
      float quadShiftY = -(float) (quadShiftX / (1 + Math.sqrt(2)));
      float nQuadShiftX = -(sarrowL - 2 * spartArrowL) - quadShiftX - w;
      float nQuadShiftY = -quadShiftY + (sarrowL - 2 * spartArrowL);

      pathForTurn.rMoveTo(-b * 8, 0);
      pathForTurn.rLineTo(0, -h);
      pathForTurn.rQuadTo(0, -(quadShiftX - quadShiftY), b * quadShiftX, quadShiftY);
      pathForTurn.rLineTo(-b * spartArrowL, spartArrowL);
      pathForTurn.rLineTo(b * sarrowL, 0); // center
      pathForTurn.rLineTo(0, -sarrowL);
      pathForTurn.rLineTo(-b * spartArrowL, spartArrowL);
      pathForTurn.rCubicTo(
          b * nQuadShiftX / 2,
          nQuadShiftX / 2,
          b * nQuadShiftX,
          nQuadShiftX / 2,
          b * nQuadShiftX,
          nQuadShiftY);
      pathForTurn.rLineTo(0, h);
    } else if (TurnType.TU.equals(turnType.getValue())) {
      int h = 54;
      float quadShiftX = 13;
      float quadShiftY = 13;

      pathForTurn.rMoveTo(28, 0);
      pathForTurn.rLineTo(0, -h);
      pathForTurn.rQuadTo(0, -(quadShiftY + w), -(quadShiftX + w), -(quadShiftY + w));
      pathForTurn.rQuadTo(-(quadShiftX + w), 0, -(quadShiftX + w), (quadShiftY + w));
      pathForTurn.rLineTo(-hpartArrowL, 0);
      pathForTurn.rLineTo(harrowL / 2, harrowL / 2); // center
      pathForTurn.rLineTo(harrowL / 2, -harrowL / 2);
      pathForTurn.rLineTo(-hpartArrowL, 0);
      pathForTurn.rQuadTo(0, -quadShiftX, quadShiftX, -quadShiftY);
      pathForTurn.rQuadTo(quadShiftX, 0, quadShiftX, quadShiftY);
      pathForTurn.rLineTo(0, h);
    } else if (turnType != null && turnType.isRoundAbout()) {
      float t = turnType.getTurnAngle();
      if (t >= 170 && t < 220) {
        t = 220;
      } else if (t > 160 && t < 170) {
        t = 160;
      }
      float sweepAngle = (t - 360) - 180;
      if (sweepAngle < -360) {
        sweepAngle += 360;
      }
      float r1 = 32f;
      float r2 = 24f;
      float angleToRot = 0.3f;

      pathForTurn.moveTo(48, 48 + r1 + 8);
      pathForTurn.lineTo(48, 48 + r1);
      RectF r = new RectF(48 - r1, 48 - r1, 48 + r1, 48 + r1);
      pathForTurn.arcTo(r, 90, sweepAngle);
      float angleRad = (float) ((180 + sweepAngle) * Math.PI / 180f);

      pathForTurn.lineTo(
          48 + (r1 + 4) * FloatMath.sin(angleRad), 48 - (r1 + 4) * FloatMath.cos(angleRad));
      pathForTurn.lineTo(
          48 + (r1 + 6) * FloatMath.sin(angleRad + angleToRot / 2),
          48 - (r1 + 6) * FloatMath.cos(angleRad + angleToRot / 2));
      pathForTurn.lineTo(
          48 + (r1 + 12) * FloatMath.sin(angleRad - angleToRot / 2),
          48 - (r1 + 12) * FloatMath.cos(angleRad - angleToRot / 2));
      pathForTurn.lineTo(
          48 + (r1 + 6) * FloatMath.sin(angleRad - 3 * angleToRot / 2),
          48 - (r1 + 6) * FloatMath.cos(angleRad - 3 * angleToRot / 2));
      pathForTurn.lineTo(
          48 + (r1 + 4) * FloatMath.sin(angleRad - angleToRot),
          48 - (r1 + 4) * FloatMath.cos(angleRad - angleToRot));
      pathForTurn.lineTo(
          48 + r2 * FloatMath.sin(angleRad - angleToRot),
          48 - r2 * FloatMath.cos(angleRad - angleToRot));

      r.set(48 - r2, 48 - r2, 48 + r2, 48 + r2);
      pathForTurn.arcTo(r, 360 + sweepAngle + 90, -sweepAngle);
      pathForTurn.lineTo(40, 48 + r2);
      pathForTurn.lineTo(40, 48 + r1 + 8);
      pathForTurn.close();
    }
    pathForTurn.close();
    if (transform != null) {
      pathForTurn.transform(transform);
    }
  }