/**
   * build an accented character out of two pre-defined glyphs.
   *
   * @param x the x offset of the accent
   * @param y the y offset of the accent
   * @param b the index of the base glyph
   * @param a the index of the accent glyph
   * @param gp the GeneralPath into which the combined glyph will be written.
   */
  private void buildAccentChar(float x, float y, char b, char a, Path gp) {
    // get the outline of the accent
    Path pathA = getOutline(a, getWidth(a, null));

    // undo the effect of the transform applied in read
    Matrix xformA = new Matrix();
    xformA.setTranslate(x, y);
    Matrix tmp = new Matrix(at);
    if (at.invert(tmp)) {
      xformA.preConcat(tmp);
    } else {
      // oh well ...
    }
    pathA.transform(xformA);

    Path pathB = getOutline(b, getWidth(b, null));

    Matrix xformB = new Matrix();
    if (at.invert(xformB)) {
      pathB.transform(xformB);
    } else {
      // ignore
    }

    gp.addPath(pathB);
    gp.addPath(pathA);
  }
Пример #2
0
  private void computePath(Rect bounds) {
    final float currentScale = mCurrentScale;
    final Path path = mPath;
    final RectF rect = mRect;
    final Matrix matrix = mMatrix;

    path.reset();
    int totalSize = Math.min(bounds.width(), bounds.height());

    float initial = mClosedStateSize;
    float destination = totalSize;
    float currentSize = initial + (destination - initial) * currentScale;

    float halfSize = currentSize / 2f;
    float inverseScale = 1f - currentScale;
    float cornerSize = halfSize * inverseScale;
    float[] corners =
        new float[] {
          halfSize, halfSize, halfSize, halfSize, halfSize, halfSize, cornerSize, cornerSize
        };
    rect.set(bounds.left, bounds.top, bounds.left + currentSize, bounds.top + currentSize);
    path.addRoundRect(rect, corners, Path.Direction.CCW);
    matrix.reset();
    matrix.postRotate(-45, bounds.left + halfSize, bounds.top + halfSize);
    matrix.postTranslate((bounds.width() - currentSize) / 2, 0);
    float hDiff = (bounds.bottom - currentSize - mExternalOffset) * inverseScale;
    matrix.postTranslate(0, hDiff);
    path.transform(matrix);
  }
Пример #3
0
  private void computeGlyphPath() {
    drawableArea.set(getBounds());
    drawableArea.inset(padding, padding);
    glyphPaint.getTextPath(glyph, 0, 1, 0, 0, glyphPath);
    // Add an extra path point to fix the icon remaining blank on a Galaxy Note 2 running 4.1.2.
    glyphPath.computeBounds(glyphPathBounds, false);
    final float centerX = glyphPathBounds.centerX();
    final float centerY = glyphPathBounds.centerY();
    glyphPath.moveTo(centerX, centerY);
    glyphPath.lineTo(centerX + 0.001f, centerY + 0.001f);
    final float areaWidthF = (float) drawableArea.width();
    final float areaHeightF = (float) drawableArea.height();
    final float scaleX = areaWidthF / glyphPathBounds.width();
    final float scaleY = areaHeightF / glyphPathBounds.height();
    final float scaleFactor = Math.min(scaleX, scaleY);
    glyphPathTransform.setScale(scaleFactor, scaleFactor);
    glyphPath.transform(glyphPathTransform);

    // TODO this two pass calculation irks me.
    // It has to be possible to push this into a single Matrix transform; what makes it hard is
    // that the origin of Text is not top-left, but baseline-left so need to account for that.
    glyphPath.computeBounds(glyphPathBounds, false);
    final float areaLeftF = (float) drawableArea.left;
    final float areaTopF = (float) drawableArea.top;
    float transX = areaLeftF - glyphPathBounds.left;
    transX += 0.5f * Math.abs(areaWidthF - glyphPathBounds.width());
    float transY = areaTopF - glyphPathBounds.top;
    transY += 0.5f * Math.abs(areaHeightF - glyphPathBounds.height());
    glyphPath.offset(transX, transY);

    invalidateSelf();
  }
Пример #4
0
 @Override
 protected void onBoundsChange(Rect bounds) {
   if (pathForTurn != null) {
     Matrix m = new Matrix();
     m.setScale(bounds.width() / 72f, bounds.height() / 72f);
     pathForTurn.transform(m, pathForTurn);
   }
 }
Пример #5
0
  private void drawArrow(Canvas c) {
    int height = getHeight();
    int width = getWidth();

    // Create a buffer around the arrow so when it rotates it doesn't get clipped by view edge
    final float BUFFER = width / 5;

    // Height of the cutout in the bottom of the triangle that makes it an arrow (0=triangle)
    final float CUTOUT_HEIGHT = getHeight() / 5;

    float x1, y1; // Tip of arrow
    x1 = width / 2;
    y1 = BUFFER;

    float x2, y2; // lower left
    x2 = BUFFER;
    y2 = height - BUFFER;

    float x3, y3; // cutout in arrow bottom
    x3 = width / 2;
    y3 = height - CUTOUT_HEIGHT - BUFFER;

    float x4, y4; // lower right
    x4 = width - BUFFER;
    y4 = height - BUFFER;

    Path path = new Path();
    path.setFillType(Path.FillType.EVEN_ODD);
    path.moveTo(x1, y1);
    path.lineTo(x2, y2);
    path.lineTo(x3, y3);
    path.lineTo(x4, y4);
    path.lineTo(x1, y1);
    path.close();

    float direction = mHeading - mBearingToStop;
    // Make sure value is between 0-360
    direction = MathUtils.mod(direction, 360.0f);

    // Rotate arrow around center point
    Matrix matrix = new Matrix();
    matrix.postRotate((float) -direction, width / 2, height / 2);
    path.transform(matrix);

    c.drawPath(path, mArrowPaint);
    c.drawPath(path, mArrowFillPaint);

    // Update content description, so screen readers can announce direction to stop
    String[] spokenDirections = getResources().getStringArray(R.array.spoken_compass_directions);
    String directionName = spokenDirections[MathUtils.getHalfWindIndex(direction)];
    setContentDescription(directionName);
  }
  @Override
  public void draw(Canvas canvas) {
    String file = getEnvObject().getCurrentRepresentation().getIcon();
    Path objectPath =
        DrawingUtils.freedomPolygonToPath(
            (FreedomPolygon) getEnvObject().getCurrentRepresentation().getShape());
    RectF box = new RectF();
    objectPath.computeBounds(box, true);
    System.out.print("GPT box: box widht:" + box.width() + " box heigh" + box.height());
    drawingMatrix = new Matrix();
    float rotation = (float) getEnvObject().getCurrentRepresentation().getRotation();
    drawingMatrix.postRotate(rotation);
    drawingMatrix.postTranslate(
        getEnvObject().getCurrentRepresentation().getOffset().getX(),
        getEnvObject().getCurrentRepresentation().getOffset().getY());
    Bitmap bmp = null;
    if (file != null) { // TODO: Asign the bmp in the setEnvObject
      bmp = BitmapUtils.getImage(file, (int) box.width(), (int) box.height());
    }
    if (bmp != null) {
      ghostBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Config.ARGB_8888);
      canvas.drawBitmap(bmp, drawingMatrix, null);

    } else {
      // TODO: Cache path
      Paint paint = new Paint();
      paint.setStyle(Style.FILL);

      ghostPath = new Path();
      objectPath.transform(drawingMatrix, ghostPath);
      int fillColor = -1;
      try {
        fillColor = Color.parseColor(getEnvObject().getCurrentRepresentation().getFillColor());
        paint.setColor(fillColor);
        canvas.drawPath(ghostPath, paint);
      } catch (IllegalArgumentException ex) {
        System.out.println("ParseColor exception in fill");
      }
      int borderColor = -1;
      try {
        borderColor = Color.parseColor(getEnvObject().getCurrentRepresentation().getBorderColor());
        paint.setColor(borderColor);
        paint.setStyle(Style.STROKE);
        canvas.drawPath(ghostPath, paint);
      } catch (IllegalArgumentException ex) {
        System.out.println("ParseColor exception in border");
      }
    }
  }
Пример #7
0
  Path smoothPath(Coordinate[] coords) {
    Path path = new Path();
    path.moveTo((float) coords[0].x, (float) coords[0].y);

    Iterator<Coordinate> ctrl = cubicSplineControlPoints(coords, 0).iterator();

    for (int i = 1; i < coords.length; i++) {
      Coordinate c = coords[i];
      Coordinate ctrl1 = ctrl.next();
      Coordinate ctrl2 = ctrl.next();

      path.cubicTo(
          (float) ctrl1.x,
          (float) ctrl1.y,
          (float) ctrl2.x,
          (float) ctrl2.y,
          (float) c.x,
          (float) c.y);
    }
    path.transform(tx.worldToCanvas);
    return path;
  }
  /**
   * Read the data for a glyph from the glyph table, and transform it based on the current
   * transform.
   *
   * @param base the start of the glyph table
   * @param offset the index of this glyph in the glyph table
   */
  private synchronized Path readGlyph(int base, int offset) {
    FlPoint pt = new FlPoint();

    // find this entry
    Range r = getIndexEntry(base, offset);

    // create a path
    Path gp = new Path();

    // rember the start position (for recursive calls due to seac)
    int hold = pos;

    // read the glyph itself
    stackptr = 0;
    parseGlyph(r, gp, pt);

    // restore the start position
    pos = hold;

    gp.transform(at);

    return gp;
  }
Пример #9
0
  /**
   * Creates a bus stop icon with the given direction arrow, or without a direction arrow if the
   * direction is NO_DIRECTION
   *
   * @param direction Bus stop direction, obtained from ObaStop.getDirection() and defined in
   *     constants in this class, or NO_DIRECTION if the stop icon shouldn't have a direction arrow
   * @return a bus stop icon bitmap with the arrow pointing the given direction, or with no arrow if
   *     direction is NO_DIRECTION
   */
  private static Bitmap createBusStopIcon(String direction) throws NullPointerException {
    if (direction == null) {
      throw new IllegalArgumentException(direction);
    }

    Resources r = Application.get().getResources();
    Context context = Application.get();

    Float directionAngle = null; // 0-360 degrees
    Bitmap bm;
    Canvas c;
    Drawable shape;
    Float rotationX = null, rotationY = null; // Point around which to rotate the arrow

    Paint arrowPaintFill = new Paint();
    arrowPaintFill.setStyle(Paint.Style.FILL);
    arrowPaintFill.setAntiAlias(true);

    if (direction.equals(NO_DIRECTION)) {
      // Don't draw the arrow
      bm = Bitmap.createBitmap(mPx, mPx, Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds(0, 0, bm.getWidth(), bm.getHeight());
    } else if (direction.equals(NORTH)) {
      directionAngle = 0f;
      bm = Bitmap.createBitmap(mPx, (int) (mPx + mBuffer), Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds(0, (int) mBuffer, mPx, bm.getHeight());
      // Shade with darkest color at tip of arrow
      arrowPaintFill.setShader(
          new LinearGradient(
              bm.getWidth() / 2,
              0,
              bm.getWidth() / 2,
              mArrowHeightPx,
              r.getColor(R.color.theme_primary),
              r.getColor(R.color.theme_accent),
              Shader.TileMode.MIRROR));
      // For NORTH, no rotation occurs - use center of image anyway so we have some value
      rotationX = bm.getWidth() / 2f;
      rotationY = bm.getHeight() / 2f;
    } else if (direction.equals(NORTH_WEST)) {
      directionAngle = 315f; // Arrow is drawn N, rotate 315 degrees
      bm =
          Bitmap.createBitmap(
              (int) (mPx + mBuffer), (int) (mPx + mBuffer), Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds((int) mBuffer, (int) mBuffer, bm.getWidth(), bm.getHeight());
      // Shade with darkest color at tip of arrow
      arrowPaintFill.setShader(
          new LinearGradient(
              0,
              0,
              mBuffer,
              mBuffer,
              r.getColor(R.color.theme_primary),
              r.getColor(R.color.theme_accent),
              Shader.TileMode.MIRROR));
      // Rotate around below coordinates (trial and error)
      rotationX = mPx / 2f + mBuffer / 2f;
      rotationY = bm.getHeight() / 2f - mBuffer / 2f;
    } else if (direction.equals(WEST)) {
      directionAngle = 0f; // Arrow is drawn pointing West, so no rotation
      bm = Bitmap.createBitmap((int) (mPx + mBuffer), mPx, Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds((int) mBuffer, 0, bm.getWidth(), bm.getHeight());
      arrowPaintFill.setShader(
          new LinearGradient(
              0,
              bm.getHeight() / 2,
              mArrowHeightPx,
              bm.getHeight() / 2,
              r.getColor(R.color.theme_primary),
              r.getColor(R.color.theme_accent),
              Shader.TileMode.MIRROR));
      // For WEST
      rotationX = bm.getHeight() / 2f;
      rotationY = bm.getHeight() / 2f;
    } else if (direction.equals(SOUTH_WEST)) {
      directionAngle = 225f; // Arrow is drawn N, rotate 225 degrees
      bm =
          Bitmap.createBitmap(
              (int) (mPx + mBuffer), (int) (mPx + mBuffer), Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds((int) mBuffer, 0, bm.getWidth(), mPx);
      arrowPaintFill.setShader(
          new LinearGradient(
              0,
              bm.getHeight(),
              mBuffer,
              bm.getHeight() - mBuffer,
              r.getColor(R.color.theme_primary),
              r.getColor(R.color.theme_accent),
              Shader.TileMode.MIRROR));
      // Rotate around below coordinates (trial and error)
      rotationX = bm.getWidth() / 2f - mBuffer / 4f;
      rotationY = mPx / 2f + mBuffer / 4f;
    } else if (direction.equals(SOUTH)) {
      directionAngle = 180f; // Arrow is drawn N, rotate 180 degrees
      bm = Bitmap.createBitmap(mPx, (int) (mPx + mBuffer), Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds(0, 0, bm.getWidth(), (int) (bm.getHeight() - mBuffer));
      arrowPaintFill.setShader(
          new LinearGradient(
              bm.getWidth() / 2,
              bm.getHeight(),
              bm.getWidth() / 2,
              bm.getHeight() - mArrowHeightPx,
              r.getColor(R.color.theme_primary),
              r.getColor(R.color.theme_accent),
              Shader.TileMode.MIRROR));
      rotationX = bm.getWidth() / 2f;
      rotationY = bm.getHeight() / 2f;
    } else if (direction.equals(SOUTH_EAST)) {
      directionAngle = 135f; // Arrow is drawn N, rotate 135 degrees
      bm =
          Bitmap.createBitmap(
              (int) (mPx + mBuffer), (int) (mPx + mBuffer), Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds(0, 0, mPx, mPx);
      arrowPaintFill.setShader(
          new LinearGradient(
              bm.getWidth(),
              bm.getHeight(),
              bm.getWidth() - mBuffer,
              bm.getHeight() - mBuffer,
              r.getColor(R.color.theme_primary),
              r.getColor(R.color.theme_accent),
              Shader.TileMode.MIRROR));
      // Rotate around below coordinates (trial and error)
      rotationX = (mPx + mBuffer / 2) / 2f;
      rotationY = bm.getHeight() / 2f;
    } else if (direction.equals(EAST)) {
      directionAngle = 180f; // Arrow is drawn pointing West, so rotate 180
      bm = Bitmap.createBitmap((int) (mPx + mBuffer), mPx, Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds(0, 0, mPx, bm.getHeight());
      arrowPaintFill.setShader(
          new LinearGradient(
              bm.getWidth(),
              bm.getHeight() / 2,
              bm.getWidth() - mArrowHeightPx,
              bm.getHeight() / 2,
              r.getColor(R.color.theme_primary),
              r.getColor(R.color.theme_accent),
              Shader.TileMode.MIRROR));
      rotationX = bm.getWidth() / 2f;
      rotationY = bm.getHeight() / 2f;
    } else if (direction.equals(NORTH_EAST)) {
      directionAngle = 45f; // Arrow is drawn pointing N, so rotate 45 degrees
      bm =
          Bitmap.createBitmap(
              (int) (mPx + mBuffer), (int) (mPx + mBuffer), Bitmap.Config.ARGB_8888);
      c = new Canvas(bm);
      shape = ContextCompat.getDrawable(context, R.drawable.map_stop_icon);
      shape.setBounds(0, (int) mBuffer, mPx, bm.getHeight());
      // Shade with darkest color at tip of arrow
      arrowPaintFill.setShader(
          new LinearGradient(
              bm.getWidth(),
              0,
              bm.getWidth() - mBuffer,
              mBuffer,
              r.getColor(R.color.theme_primary),
              r.getColor(R.color.theme_accent),
              Shader.TileMode.MIRROR));
      // Rotate around middle of circle
      rotationX = (float) mPx / 2;
      rotationY = bm.getHeight() - (float) mPx / 2;
    } else {
      throw new IllegalArgumentException(direction);
    }

    shape.draw(c);

    if (direction.equals(NO_DIRECTION)) {
      // Everything after this point is for drawing the arrow image, so return the bitmap as-is for
      // no arrow
      return bm;
    }

    /**
     * Draw the arrow - all dimensions should be relative to px so the arrow is drawn the same size
     * for all orientations
     */
    // Height of the cutout in the bottom of the triangle that makes it an arrow (0=triangle)
    final float CUTOUT_HEIGHT = mPx / 12;
    Path path = new Path();
    float x1 = 0, y1 = 0; // Tip of arrow
    float x2 = 0, y2 = 0; // lower left
    float x3 = 0, y3 = 0; // cutout in arrow bottom
    float x4 = 0, y4 = 0; // lower right

    if (direction.equals(NORTH)
        || direction.equals(SOUTH)
        || direction.equals(NORTH_EAST)
        || direction.equals(SOUTH_EAST)
        || direction.equals(NORTH_WEST)
        || direction.equals(SOUTH_WEST)) {
      // Arrow is drawn pointing NORTH
      // Tip of arrow
      x1 = mPx / 2;
      y1 = 0;

      // lower left
      x2 = (mPx / 2) - (mArrowWidthPx / 2);
      y2 = mArrowHeightPx;

      // cutout in arrow bottom
      x3 = mPx / 2;
      y3 = mArrowHeightPx - CUTOUT_HEIGHT;

      // lower right
      x4 = (mPx / 2) + (mArrowWidthPx / 2);
      y4 = mArrowHeightPx;
    } else if (direction.equals(EAST) || direction.equals(WEST)) {
      // Arrow is drawn pointing WEST
      // Tip of arrow
      x1 = 0;
      y1 = mPx / 2;

      // lower left
      x2 = mArrowHeightPx;
      y2 = (mPx / 2) - (mArrowWidthPx / 2);

      // cutout in arrow bottom
      x3 = mArrowHeightPx - CUTOUT_HEIGHT;
      y3 = mPx / 2;

      // lower right
      x4 = mArrowHeightPx;
      y4 = (mPx / 2) + (mArrowWidthPx / 2);
    }

    path.setFillType(Path.FillType.EVEN_ODD);
    path.moveTo(x1, y1);
    path.lineTo(x2, y2);
    path.lineTo(x3, y3);
    path.lineTo(x4, y4);
    path.lineTo(x1, y1);
    path.close();

    // Rotate arrow around (rotationX, rotationY) point
    Matrix matrix = new Matrix();
    matrix.postRotate(directionAngle, rotationX, rotationY);
    path.transform(matrix);

    c.drawPath(path, arrowPaintFill);
    c.drawPath(path, mArrowPaintStroke);

    return bm;
  }
Пример #10
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);
    }
  }
  /**
   * transform a path with all the given matrices VERY IMPORTANT: keep order to value-touch-offset
   *
   * @param path
   */
  public void pathValueToPixel(Path path) {

    path.transform(mMatrixValueToPx);
    path.transform(mViewPortHandler.getMatrixTouch());
    path.transform(mMatrixOffset);
  }