import java.awt.geom.Point2D; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Scanner; public class CakeCutting_zeil { class Line { public Point2D.Double p1; public Point2D.Double p2; public int inputNumber; public Line() { p1 = new Point2D.Double(); p2 = new Point2D.Double(); } public Line (Point2D.Double thruPoint1, Point2D.Double thruPoint2) { p1 = (Point2D.Double)thruPoint1.clone(); p2 = (Point2D.Double)thruPoint2.clone(); } public String toString() { return "[" + p1 + "," + p2 + "]"; } double y(double x) { if (p1.x == p2.x) return Double.MAX_VALUE; else return (double)p1.y + ((double)(p2.y - p1.y) / (p2.x - p1.x)) * (x - p1.x); } double x(double y) { if (p1.y == p2.y) return Double.MAX_VALUE; else return (double)p1.x + ( (double)(p2.x - p1.x) / (p2.y - p1.y)) * (y - p1.y); } boolean parallel (Line line2) { double c1 = (p2.y - p1.y) * (line2.p2.x - line2.p1.x); double c2 = (line2.p2.y - line2.p1.y) * (p2.x - p1.x); return c1 == c2; } Point2D.Double intersection (Line line2) { double rx = p2.x - p1.x; double ry = p2.y - p1.y; double sx = line2.p2.x - line2.p1.x; double sy = line2.p2.y - line2.p1.y; double d = rx * sy - sx * ry; double s = (-ry * (p1.x - line2.p1.x) + rx * (p1.y - line2.p1.y)) / d; double t = ( sx * (p1.y - line2.p1.y) - sy * (p1.x - line2.p1.x)) / d; return new Point2D.Double(p1.x + (t * rx), p1.y + (t * ry)); } double eval (Point2D.Double p) { double dx = p2.x - p1.x; double dy = p2.y - p1.y; double r = dx * (p.y - p1.y) - dy * (p.x - p1.x); double scale = dx*dx + dy*dy; return r / Math.sqrt(scale); } } private Point2D.Double center; private double radius; private Line[] lines; public class ApproxPoint { public long x; public long y; public ApproxPoint(Point2D.Double p) { x = Math.round (1000.0 * p.x); y = Math.round (1000.0 * p.y); } public boolean equals (Object obj) { ApproxPoint p = (ApproxPoint)obj; return x == p.x && y == p.y; } public int hashCode () { long k = 1301L * x + y; return (int)k; } } public class LinePair { int i; int j; LinePair (int i, int j) { this.i = i; this.j = j; } } HashMap priorIntersections; public CakeCutting_zeil(int xc, int yc, int rc, int n, Scanner input) { center = new Point2D.Double(xc, yc); radius = rc; lines = new Line[n]; for (int i = 0; i < n; ++i) { int x1, y1, x2, y2; x1 = input.nextInt(); y1 = input.nextInt(); Point2D.Double p1 = new Point2D.Double(x1, y1); x2 = input.nextInt(); y2 = input.nextInt(); Point2D.Double p2 = new Point2D.Double(x2, y2); lines[i] = new Line(p1, p2); } priorIntersections = new HashMap<>(); } void solve () { int pieces = 1; // Discard any lines that do not intersect the circle ArrayList candidates = new ArrayList<>(); for (int i = 0; i < lines.length; ++i) { lines[i].inputNumber = i; double d = lines[i].eval(center); if (Math.abs(d) < radius) candidates.add(lines[i]); } // Now count up the effects of the remaining lines for (int i = 0; i < candidates.size(); ++i) { ++pieces; for (int j = 0; j < i; ++j) { Point2D.Double p = candidates.get(i).intersection(candidates.get(j)); //System.out.format ("%.2f %.2f\n", p.x, p.y); // sjz if (p.distance(center) < radius) { // Intersection with other line is inside the circle ++pieces; ApproxPoint ap = new ApproxPoint(p); LinePair prior = priorIntersections.get(ap); if (prior != null) { System.out.println ("*** Common intersections: lines " + candidates.get(i).inputNumber + " and " + candidates.get(j).inputNumber + " with " + prior.i + " and " + prior.j); System.out.println (" " + candidates.get(i).inputNumber + ": " + candidates.get(i)); System.out.println (" " + candidates.get(j).inputNumber + ": " + candidates.get(j)); System.out.println (" intersect at " + p); System.out.println (" " + prior.i + ": " + lines[prior.i]); System.out.println (" " + prior.j + ": " + lines[prior.j]); System.out.println (" intersect at " + lines[prior.i].intersection(lines[prior.j])); } priorIntersections.put(ap, new LinePair(candidates.get(i).inputNumber, candidates.get(j).inputNumber)); } } } System.out.println (pieces); } /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) throws FileNotFoundException { InputStream in = null; if (args.length > 0) { in = new FileInputStream(args[0]); } else { in = System.in; } Scanner input = new Scanner(in); int xc, yc, rc, n; while (true) { rc = input.nextInt(); xc = input.nextInt(); yc = input.nextInt(); n = input.nextInt(); if (rc == 0) break; new CakeCutting_zeil(xc, yc, rc, n, input).solve(); } } }