// This function is nearly identical to the one written for the
  // original port of the F3 graphics/UI library:
  // javafx.ui.canvas.ArcTo#addTo
  private void addArcTo(NGPath pgPath, Path2D path, final double x0, final double y0) {
    double localX = getX();
    double localY = getY();
    boolean localSweepFlag = isSweepFlag();
    boolean localLargeArcFlag = isLargeArcFlag();

    // Determine target "to" position
    final double xto = (isAbsolute()) ? localX : localX + x0;
    final double yto = (isAbsolute()) ? localY : localY + y0;
    // Compute the half distance between the current and the final point
    final double dx2 = (x0 - xto) / 2.0;
    final double dy2 = (y0 - yto) / 2.0;
    // Convert angle from degrees to radians
    final double xAxisRotationR = Math.toRadians(getXAxisRotation());
    final double cosAngle = Math.cos(xAxisRotationR);
    final double sinAngle = Math.sin(xAxisRotationR);

    //
    // Step 1 : Compute (x1, y1)
    //
    final double x1 = (cosAngle * dx2 + sinAngle * dy2);
    final double y1 = (-sinAngle * dx2 + cosAngle * dy2);
    // Ensure radii are large enough
    double rx = Math.abs(getRadiusX());
    double ry = Math.abs(getRadiusY());
    double Prx = rx * rx;
    double Pry = ry * ry;
    final double Px1 = x1 * x1;
    final double Py1 = y1 * y1;
    // check that radii are large enough
    final double radiiCheck = Px1 / Prx + Py1 / Pry;
    if (radiiCheck > 1.0) {
      rx = Math.sqrt(radiiCheck) * rx;
      ry = Math.sqrt(radiiCheck) * ry;
      if (rx == rx && ry == ry) {
        /* not NANs */
      } else {
        if (pgPath == null) {
          path.lineTo((float) xto, (float) yto);
        } else {
          pgPath.addLineTo((float) xto, (float) yto);
        }
        return;
      }
      Prx = rx * rx;
      Pry = ry * ry;
    }

    //
    // Step 2 : Compute (cx1, cy1)
    //
    double sign = ((localLargeArcFlag == localSweepFlag) ? -1.0 : 1.0);
    double sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1));
    sq = (sq < 0.0) ? 0.0 : sq;
    final double coef = (sign * Math.sqrt(sq));
    final double cx1 = coef * ((rx * y1) / ry);
    final double cy1 = coef * -((ry * x1) / rx);

    //
    // Step 3 : Compute (cx, cy) from (cx1, cy1)
    //
    final double sx2 = (x0 + xto) / 2.0;
    final double sy2 = (y0 + yto) / 2.0;
    final double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1);
    final double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1);

    //
    // Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)
    //
    final double ux = (x1 - cx1) / rx;
    final double uy = (y1 - cy1) / ry;
    final double vx = (-x1 - cx1) / rx;
    final double vy = (-y1 - cy1) / ry;
    // Compute the angle start
    double n = Math.sqrt((ux * ux) + (uy * uy));
    double p = ux; // (1 * ux) + (0 * uy)
    sign = ((uy < 0.0) ? -1.0 : 1.0);
    double angleStart = Math.toDegrees(sign * Math.acos(p / n));

    // Compute the angle extent
    n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
    p = ux * vx + uy * vy;
    sign = ((ux * vy - uy * vx < 0.0) ? -1.0 : 1.0);
    double angleExtent = Math.toDegrees(sign * Math.acos(p / n));
    if (!localSweepFlag && (angleExtent > 0)) {
      angleExtent -= 360.0;
    } else if (localSweepFlag && (angleExtent < 0)) {
      angleExtent += 360.0;
    }
    angleExtent = angleExtent % 360;
    angleStart = angleStart % 360;

    //
    // We can now build the resulting Arc2D
    //
    final float arcX = (float) (cx - rx);
    final float arcY = (float) (cy - ry);
    final float arcW = (float) (rx * 2.0);
    final float arcH = (float) (ry * 2.0);
    final float arcStart = (float) -angleStart;
    final float arcExtent = (float) -angleExtent;

    if (pgPath == null) {
      final Arc2D arc = new Arc2D(arcX, arcY, arcW, arcH, arcStart, arcExtent, Arc2D.OPEN);
      BaseTransform xform =
          (xAxisRotationR == 0) ? null : BaseTransform.getRotateInstance(xAxisRotationR, cx, cy);
      PathIterator pi = arc.getPathIterator(xform);
      // RT-8926, append(true) converts the initial moveTo into a
      // lineTo which can generate huge miter joins if the segment
      // is small enough.  So, we manually skip it here instead.
      pi.next();
      path.append(pi, true);
    } else {
      pgPath.addArcTo(arcX, arcY, arcW, arcH, arcStart, arcExtent, (float) xAxisRotationR);
    }
  }
 @Override
 void addTo(NGPath pgPath) {
   addArcTo(pgPath, null, pgPath.getCurrentX(), pgPath.getCurrentY());
 }