/**
   * Computes the center of the circumscribed circle of the three input points.
   *
   * @throws ColinearPoints2DException if the 3 points are colinear
   */
  public static Point2D circumCenter(Point2D p1, Point2D p2, Point2D p3) {
    if (Point2D.isColinear(p1, p2, p3)) throw new ColinearPoints2DException(p1, p2, p3);

    // create two median lines
    StraightLine2D line12 = StraightLine2D.createMedian(p1, p2);
    StraightLine2D line23 = StraightLine2D.createMedian(p2, p3);

    // check medians are not parallel
    assert !AbstractLine2D.isParallel(line12, line23)
        : "If points are not colinear, medians should not be parallel";

    // Compute intersection of the medians, and circle radius
    Point2D center = AbstractLine2D.getIntersection(line12, line23);

    // return the center
    return center;
  }
  /**
   * Computes intersections of a circle with a line. Returns an array of Point2D, of size 0, 1 or 2
   * depending on the distance between circle and line. If there are 2 intersections points, the
   * first one in the array is the first one on the line.
   *
   * @return a collection of intersection points
   * @since 0.11.1
   */
  public static Collection<Point2D> lineCircleIntersections(
      LinearShape2D line, CircularShape2D circle) {
    // initialize array of points (maximum 2 intersections)
    ArrayList<Point2D> intersections = new ArrayList<Point2D>(2);

    // extract parameters of the circle
    Circle2D parent = circle.supportingCircle();
    Point2D center = parent.center();
    double radius = parent.radius();

    // Compute line perpendicular to the test line, and going through the
    // circle center
    StraightLine2D perp = StraightLine2D.createPerpendicular(line, center);

    // Compute distance between line and circle center
    Point2D inter = perp.intersection(new StraightLine2D(line));
    if (inter == null) {
      throw new RuntimeException(
          "Could not compute intersection point when computing line-cicle intersection");
    }
    double dist = inter.distance(center);

    // if the distance is the radius of the circle, return the
    // intersection point
    if (abs(dist - radius) < Shape2D.ACCURACY) {
      if (line.contains(inter) && circle.contains(inter)) intersections.add(inter);
      return intersections;
    }

    // compute angle of the line, and distance between 'inter' point and
    // each intersection point
    double angle = line.horizontalAngle();
    double d2 = sqrt(radius * radius - dist * dist);

    // Compute position and angle of intersection points
    Point2D p1 = Point2D.createPolar(inter, d2, angle + Math.PI);
    Point2D p2 = Point2D.createPolar(inter, d2, angle);

    // add points to the array only if they belong to the line
    if (line.contains(p1) && circle.contains(p1)) intersections.add(p1);
    if (line.contains(p2) && circle.contains(p2)) intersections.add(p2);

    // return the result
    return intersections;
  }
  /* (non-Javadoc)
   * @see math.geom2d.circulinear.CirculinearCurve2D#transform(math.geom2d.transform.CircleInversion2D)
   */
  public CircleLine2D transform(CircleInversion2D inv) {
    // Extract inversion parameters
    Point2D center = inv.center();
    Point2D c1 = this.center();

    // If circles are concentric, creates directly the new circle
    if (center.distance(c1) < Shape2D.ACCURACY) {
      double r0 = inv.radius();
      double r2 = r0 * r0 / this.r;
      return new Circle2D(center, r2, this.direct);
    }

    // line joining centers of the two circles
    StraightLine2D centersLine = new StraightLine2D(center, c1);

    // get the two intersection points with the line joining the circle centers
    Collection<Point2D> points = this.intersections(centersLine);
    if (points.size() < 2) {
      throw new RuntimeException(
          "Intersection of circle with line through center has less than 2 points");
    }
    Iterator<Point2D> iter = points.iterator();
    Point2D p1 = iter.next();
    Point2D p2 = iter.next();

    // If the circle contains the inversion center, it transforms into a
    // straight line
    if (this.distance(center) < Shape2D.ACCURACY) {
      // choose the intersection point that is not the center
      double dist1 = center.distance(p1);
      double dist2 = center.distance(p2);
      Point2D p0 = dist1 < dist2 ? p2 : p1;

      // transform the point, and return the perpendicular
      p0 = p0.transform(inv);
      return StraightLine2D.createPerpendicular(centersLine, p0);
    }

    // For regular cases, the circle transforms into an other circle

    // transform the two extreme points of the circle,
    // resulting in a diameter of the new circle
    p1 = p1.transform(inv);
    p2 = p2.transform(inv);

    // compute center and diameter of transformed circle
    double diam = p1.distance(p2);
    c1 = Point2D.midPoint(p1, p2);

    // create the transformed circle
    boolean direct = !this.isDirect() ^ this.isInside(inv.center());
    return new Circle2D(c1, diam / 2, direct);
  }