/** @inheritDoc */
  public void lineTo(PointFP point) {
    if (point.equals(currPoint)) {
      return;
    }

    LineFP head, tail;
    calcHeadTail(currPoint, point, head = new LineFP(), tail = new LineFP());

    if (drawingCurve) {
      if (lastCurveTail != null) {
        curvePath1.addLineTo(lastCurveTail.pt1);
        curvePath2.addLineTo(lastCurveTail.pt2);
      }
      lastCurveTail = new LineFP(tail);
    } else {
      if (needDrawStartCap) {
        startCapP1 = new PointFP(currPoint);
        startCapP2 = new PointFP(point);
        needDrawStartCap = false;
      }
      addLineJoin(lastPoint, currPoint, point);

      outline.addMoveTo(head.pt1);
      outline.addLineTo(tail.pt1);
      outline.addLineTo(tail.pt2);
      outline.addLineTo(head.pt2);
      outline.addLineTo(head.pt1);
      outline.addClose();
      lastPoint = new PointFP(currPoint);
    }
    super.lineTo(point);
  }
  private void addLineJoin(PointFP lastPoint, PointFP currPoint, PointFP nextPoint) {
    if (lastPoint == null
        || currPoint == null
        || nextPoint == null
        || nextPoint.equals(currPoint)
        || lastPoint.equals(currPoint)) {
      return;
    }

    PointFP p1 = null, p2 = null;
    LineFP head, tail, lastHead, lastTail;
    calcHeadTail(currPoint, nextPoint, head = new LineFP(), tail = new LineFP());
    calcHeadTail(lastPoint, currPoint, lastHead = new LineFP(), lastTail = new LineFP());
    boolean cross1, cross2, needLineJoin = false;
    PointFP pi1 = new PointFP();
    PointFP pi2 = new PointFP();

    cross1 =
        LineFP.intersects(
            new LineFP(head.pt1, tail.pt1), new LineFP(lastHead.pt1, lastTail.pt1), pi1);
    cross2 =
        LineFP.intersects(
            new LineFP(head.pt2, tail.pt2), new LineFP(lastHead.pt2, lastTail.pt2), pi2);
    if (cross1 && !cross2 && pi1.x != SingleFP.NaN) {
      p1 = lastTail.pt2;
      p2 = head.pt2;
      needLineJoin = true;
    } else if (!cross1 && cross2 && pi2.x != SingleFP.NaN) {
      p1 = lastTail.pt1;
      p2 = head.pt1;
      needLineJoin = true;
    }
    if (needLineJoin) {
      outline.addMoveTo(cross1 ? pi1 : pi2);
      outline.addLineTo(cross1 ? p2 : p1);
      if (lineJoin == PenFP.LINEJOIN_MITER) {
        outline.addLineTo(cross1 ? pi2 : pi1);
      }
      outline.addLineTo(cross1 ? p1 : p2);
      outline.addClose();
      if (lineJoin == PenFP.LINEJOIN_ROUND) {
        addLineCap(cross2 ? pi2 : pi1, currPoint, PenFP.LINECAP_ROUND);
      }
    }
  }
  private void addLineCap(PointFP p1, PointFP p2, int lineCap) {
    if (lineCap == PenFP.LINECAP_BUTT || p1.equals(p2)) {
      return;
    }
    int dx = p2.x - p1.x;
    int dy = p2.y - p1.y;
    int len = PointFP.distance(dx, dy);
    PointFP[] cap =
        lineCap == PenFP.LINECAP_ROUND ? GraphicsPathFP.ROUNDCAP : GraphicsPathFP.SQUARECAP;

    dx = MathFP.mul(ff_rad, MathFP.div(dx, len));
    dy = MathFP.mul(ff_rad, MathFP.div(dy, len));

    MatrixFP m = new MatrixFP(dx, dx, dy, -dy, p2.x, p2.y);
    outline.addMoveTo(new PointFP(0, GraphicsPathFP.ONE).transform(m));
    for (int i = 0; i < cap.length; i++) {
      outline.addLineTo(new PointFP(cap[i]).transform(m));
    }
    outline.addLineTo(new PointFP(0, -GraphicsPathFP.ONE).transform(m));
    outline.addClose();
  }