예제 #1
0
 public Point2DDouble[] intersect(Circle2DDouble c, DoubleComparator dblComp) {
   double d = p.distance(c.p);
   if (dblComp.compare(d, radius + c.radius) > 0
       || dblComp.compare(d + Math.min(radius, c.radius), Math.max(radius, c.radius)) < 0) {
     return new Point2DDouble[0];
   }
   if (dblComp.compare(d, 0) == 0) {
     return null;
   }
   double diff = (radius * radius - c.radius * c.radius) / d;
   double d1 = (d + diff) * .5;
   Point2DDouble v = c.p.subtract(p);
   Point2DDouble v1 = v.multiply(d1 / v.length());
   double z = radius * radius - d1 * d1;
   Point2DDouble p0 = p.add(v1);
   //        if (dblComp.compare(z, 0) < 0) {
   //            System.out.println(this + " " + c);
   //            System.out.println(d + " " + (radius + c.radius));
   //            throw new AssertionError();
   //        }
   if (dblComp.compare(z, 0) <= 0) {
     return new Point2DDouble[] {p0};
   }
   z = Math.sqrt(z);
   Point2DDouble v2 = new Point2DDouble(-v.y, v.x).multiply(z / v.length());
   return new Point2DDouble[] {p0.add(v2), p0.subtract(v2)};
 }
예제 #2
0
 public Point2DDouble[][] getInternalTangents(Circle2DDouble c, DoubleComparator comp) {
   double d = p.distance(c.p);
   if (comp.compare(d, radius + c.radius) < 0) return new Point2DDouble[0][];
   if (comp.compare(d, radius + c.radius) == 0) {
     Point2DDouble v = c.p.subtract(p);
     v = v.multiply(radius / v.length());
     v = v.add(p);
     return new Point2DDouble[][] {{v, v}};
   }
   double nRadius = radius + c.radius;
   Point2DDouble[] tangentsFromPoint = new Circle2DDouble(p, nRadius).getTangents(c.p, comp);
   Point2DDouble vn1 = tangentsFromPoint[0].subtract(c.p);
   vn1 = new Point2DDouble(-vn1.y, vn1.x);
   vn1 = vn1.multiply(c.radius / vn1.length());
   Point2DDouble vn2 = tangentsFromPoint[1].subtract(c.p);
   vn2 = new Point2DDouble(vn2.y, -vn2.x);
   vn2 = vn2.multiply(c.radius / vn2.length());
   Point2DDouble[][] ret =
       new Point2DDouble[][] {
         {tangentsFromPoint[0].add(vn1), c.p.add(vn1)},
         {tangentsFromPoint[1].add(vn2), c.p.add(vn2)}
       };
   if (comp.compare(ret[0][0].distance(p), radius) != 0) throw new AssertionError();
   if (comp.compare(ret[1][0].distance(p), radius) != 0) throw new AssertionError();
   if (comp.compare(ret[0][1].distance(c.p), c.radius) != 0) throw new AssertionError();
   if (comp.compare(ret[1][1].distance(c.p), c.radius) != 0) throw new AssertionError();
   return ret;
 }
예제 #3
0
 public Point2DDouble[] getTangents(Point2DDouble q, DoubleComparator comp) {
   double d = p.distance(q);
   if (comp.compare(d, radius) < 0) {
     return null;
   }
   if (comp.compare(d, radius) == 0) {
     return new Point2DDouble[] {p};
   }
   double d1 = radius * radius / d;
   Point2DDouble v = q.subtract(p);
   Point2DDouble vn = new Point2DDouble(-v.y, v.x);
   v = v.multiply(d1 / v.length());
   Point2DDouble c = p.add(v);
   double d2 = radius * radius - d1 * d1;
   if (d2 < 0) d2 = 0;
   d2 = Math.sqrt(d2);
   vn = vn.multiply(d2 / vn.length());
   return new Point2DDouble[] {c.add(vn), c.subtract(vn)};
 }
예제 #4
0
 public Point2DDouble[][] getExternalTangents(Circle2DDouble c, DoubleComparator comp) {
   if (comp.compare(radius, c.radius) < 0) {
     Point2DDouble[][] ret = c.getExternalTangents(this, comp);
     for (Point2DDouble[] e : ret) {
       Point2DDouble t = e[0];
       e[0] = e[1];
       e[1] = t;
     }
     if (comp.compare(ret[0][0].distance(p), radius) != 0) throw new AssertionError();
     if (comp.compare(ret[1][0].distance(p), radius) != 0) throw new AssertionError();
     if (comp.compare(ret[0][1].distance(c.p), c.radius) != 0) throw new AssertionError();
     if (comp.compare(ret[1][1].distance(c.p), c.radius) != 0) throw new AssertionError();
     if (comp.compare(GeometryAlgorithms.distanceToLine(ret[0][0], ret[0][1], p), radius) != 0)
       throw new AssertionError();
     if (comp.compare(GeometryAlgorithms.distanceToLine(ret[0][0], ret[0][1], c.p), c.radius) != 0)
       throw new AssertionError();
     if (comp.compare(GeometryAlgorithms.distanceToLine(ret[1][0], ret[1][1], p), radius) != 0)
       throw new AssertionError();
     if (comp.compare(GeometryAlgorithms.distanceToLine(ret[1][0], ret[1][1], c.p), c.radius) != 0)
       throw new AssertionError();
     return ret;
   }
   double d = p.distance(c.p);
   if (comp.compare(d + Math.min(radius, c.radius), Math.max(radius, c.radius)) < 0) {
     return new Point2DDouble[0][];
   }
   if (comp.compare(d + Math.min(radius, c.radius), Math.max(radius, c.radius)) == 0) {
     Point2DDouble v = c.p.subtract(p);
     v = v.multiply(radius / v.length());
     v = v.add(p);
     return new Point2DDouble[][] {{v, v}};
   }
   Point2DDouble[] tangentsFromPoint =
       new Circle2DDouble(p, radius - c.radius).getTangents(c.p, comp);
   Point2DDouble vn1 = tangentsFromPoint[0].subtract(c.p);
   vn1 = new Point2DDouble(vn1.y, -vn1.x);
   vn1 = vn1.multiply(c.radius / vn1.length());
   Point2DDouble vn2 = tangentsFromPoint[1].subtract(c.p);
   vn2 = new Point2DDouble(-vn2.y, vn2.x);
   vn2 = vn2.multiply(c.radius / vn2.length());
   Point2DDouble[][] ret =
       new Point2DDouble[][] {
         {tangentsFromPoint[0].add(vn1), c.p.add(vn1)},
         {tangentsFromPoint[1].add(vn2), c.p.add(vn2)}
       };
   if (comp.compare(ret[0][0].distance(p), radius) != 0) throw new AssertionError();
   if (comp.compare(ret[1][0].distance(p), radius) != 0) throw new AssertionError();
   if (comp.compare(ret[0][1].distance(c.p), c.radius) != 0) throw new AssertionError();
   if (comp.compare(ret[1][1].distance(c.p), c.radius) != 0) throw new AssertionError();
   if (comp.compare(GeometryAlgorithms.distanceToLine(ret[0][0], ret[0][1], p), radius) != 0)
     throw new AssertionError();
   if (comp.compare(GeometryAlgorithms.distanceToLine(ret[0][0], ret[0][1], c.p), c.radius) != 0)
     throw new AssertionError();
   if (comp.compare(GeometryAlgorithms.distanceToLine(ret[1][0], ret[1][1], p), radius) != 0)
     throw new AssertionError();
   if (comp.compare(GeometryAlgorithms.distanceToLine(ret[1][0], ret[1][1], c.p), c.radius) != 0)
     throw new AssertionError();
   return ret;
 }
예제 #5
0
 public boolean containsOn(Point2DDouble p, DoubleComparator comp) {
   return comp.compare(p.distanceSquared(this.p), radius * radius) == 0;
 }
예제 #6
0
  public void solve(int testNumber, FastScanner in, FastPrinter out) {
    Circle2DDouble c =
        new Circle2DDouble(new Point2DDouble(in.nextInt(), in.nextInt()), in.nextInt());
    Point2DDouble p1 = new Point2DDouble(in.nextInt(), in.nextInt());
    Point2DDouble p2 = new Point2DDouble(in.nextInt(), in.nextInt());
    if (p1.x > p2.x) {
      double t = p1.x;
      p1.x = p2.x;
      p2.x = t;
    }
    if (p1.y > p2.y) {
      double t = p1.y;
      p1.y = p2.y;
      p2.y = t;
    }
    List<Point2DDouble> allPoints = new ArrayList<>();
    allPoints.add(p1);
    allPoints.add(p2);
    allPoints.add(new Point2DDouble(p1.x, p2.y));
    allPoints.add(new Point2DDouble(p2.x, p1.y));
    allPoints.add(new Point2DDouble(c.p.x - c.radius, c.p.y));
    allPoints.add(new Point2DDouble(c.p.x + c.radius, c.p.y));
    allPoints.add(new Point2DDouble(c.p.x, c.p.y - c.radius));
    allPoints.add(new Point2DDouble(c.p.x, c.p.y + c.radius));
    for (double x : new double[] {p1.x, p2.x}) {
      if (comp.compare(x, c.p.x - c.radius) > 0 && comp.compare(x, c.p.x + c.radius) < 0) {
        double dx = c.p.x - x;
        double dy = Math.sqrt(c.radius * c.radius - dx * dx);
        allPoints.add(new Point2DDouble(x, c.p.y - dy));
        allPoints.add(new Point2DDouble(x, c.p.y + dy));
      }
    }
    for (double y : new double[] {p1.y, p2.y}) {
      if (comp.compare(y, c.p.y - c.radius) > 0 && comp.compare(y, c.p.y + c.radius) < 0) {
        double dy = c.p.y - y;
        double dx = Math.sqrt(c.radius * c.radius - dy * dy);
        allPoints.add(new Point2DDouble(c.p.x - dx, y));
        allPoints.add(new Point2DDouble(c.p.x + dx, y));
      }
    }
    List<Point2DDouble> onRect = new ArrayList<>();
    for (Point2DDouble e : allPoints) {
      if (inside(p1, p2, e)) {
        if (comp.compare(p1.x, e.x) < 0
            && comp.compare(e.x, p2.x) < 0
            && comp.compare(p1.y, e.y) < 0
            && comp.compare(e.y, p2.y) < 0) {
          continue;
        }
        onRect.add(e);
      }
    }
    List<Point2DDouble> onCircle = new ArrayList<>();
    for (Point2DDouble e : allPoints) {
      if (comp.compare(e.distance(c.p), c.radius) == 0) {
        onCircle.add(e);
      }
    }
    final Point2DDouble centerRect = p1.add(p2).multiply(0.5);
    Collections.sort(
        onRect,
        new Comparator<Point2DDouble>() {

          int get(Point2DDouble e) {
            int x = comp.compare(e.x, 0);
            int y = comp.compare(e.y, 0);
            if (x > 0) {
              return y > 0 ? 2 : y < 0 ? 8 : 1;
            } else if (x < 0) {
              return y > 0 ? 4 : y < 0 ? 6 : 5;
            } else {
              return y > 0 ? 3 : y < 0 ? 7 : 0;
            }
          }

          @Override
          public int compare(Point2DDouble o1, Point2DDouble o2) {
            o1 = o1.subtract(centerRect);
            o2 = o2.subtract(centerRect);
            int c = get(o1) - get(o2);
            if (c != 0) return c;
            return comp.compare(o2.vmul(o1), 0);
          }
        });
    final Point2DDouble circleCenter = c.p;
    Collections.sort(
        onCircle,
        new Comparator<Point2DDouble>() {

          int get(Point2DDouble e) {
            int x = comp.compare(e.x, 0);
            int y = comp.compare(e.y, 0);
            if (x > 0) {
              return y > 0 ? 2 : y < 0 ? 8 : 1;
            } else if (x < 0) {
              return y > 0 ? 4 : y < 0 ? 6 : 5;
            } else {
              return y > 0 ? 3 : y < 0 ? 7 : 0;
            }
          }

          @Override
          public int compare(Point2DDouble o1, Point2DDouble o2) {
            o1 = o1.subtract(circleCenter);
            o2 = o2.subtract(circleCenter);
            int c = get(o1) - get(o2);
            if (c != 0) return c;
            return comp.compare(o2.vmul(o1), 0);
          }
        });
    List<Segment> allSegments = new ArrayList<>();
    for (int i = 0; i < onRect.size(); i++) {
      Point2DDouble r1 = onRect.get(i);
      Point2DDouble r2 = onRect.get((i + 1) % onRect.size());
      if (pointsEqual(r1, r2)) continue;
      Point2DDouble r0 = r1.add(r2).multiply(0.5);
      if (comp.compare(r0.distance(c.p), c.radius) < 0) {
        allSegments.add(new Segment(r1, r2, 0));
      }
    }
    for (int i = 0; i < onCircle.size(); i++) {
      Point2DDouble r1 = onCircle.get(i);
      Point2DDouble r2 = onCircle.get((i + 1) % onCircle.size());
      if (pointsEqual(r1, r2)) continue;
      r1 = r1.subtract(c.p);
      r2 = r2.subtract(c.p);
      Point2DDouble r0 = r1.add(r2);
      r0 = r0.multiply(c.radius / r0.length());
      r0 = r0.add(c.p);
      if (inside(p1, p2, r0)) {
        allSegments.add(new Segment(r1.add(c.p), r2.add(c.p), c.radius));
      }
    }
    if (allSegments.isEmpty()) {
      out.println(0);
      return;
    }
    boolean[] was = new boolean[allSegments.size()];
    List<Segment> sortedSegments = new ArrayList<>();
    sortedSegments.add(allSegments.get(0));
    was[0] = true;
    Point2DDouble last = sortedSegments.get(sortedSegments.size() - 1).q;
    //        System.out.println(allSegments);
    while (!pointsEqual(sortedSegments.get(0).p, last)) {
      int id = -1;
      for (int i = 0; i < allSegments.size(); i++) {
        if (was[i]) continue;
        Segment e = allSegments.get(i);
        if (pointsEqual(e.p, last)) {
          id = i;
          break;
        }
      }
      if (id < 0) throw new AssertionError();
      was[id] = true;
      sortedSegments.add(allSegments.get(id));
      last = allSegments.get(id).q;
    }
    double area = 0;
    for (Segment e : sortedSegments) {
      area += e.p.vmul(e.q);
    }
    area = Math.abs(area) * .5;
    for (Segment e : sortedSegments) {
      if (comp.compare(e.r, 0) > 0) {
        double dist = e.p.distance(e.q);
        double sin = dist * .5 / c.radius;
        if (sin > 1) sin = 1;
        else if (sin < -1) sin = -1;
        double ang = Math.asin(sin) * 2;
        area += c.radius * c.radius * .5 * (ang - Math.sin(ang));
      }
    }
    out.println(area);
  }
예제 #7
0
 private boolean inside(Point2DDouble p1, Point2DDouble p2, Point2DDouble e) {
   return comp.compare(p1.x, e.x) <= 0
       && comp.compare(e.x, p2.x) <= 0
       && comp.compare(p1.y, e.y) <= 0
       && comp.compare(e.y, p2.y) <= 0;
 }
예제 #8
0
 static boolean pointsEqual(Point2DDouble p, Point2DDouble q) {
   return comp.compare(p.x, q.x) == 0 && comp.compare(p.y, q.y) == 0;
 }