Problem:
Problem D: Area Separation

Mr. Yamada Springfield Tanaka は、国家区画整理事業局局長補佐代理という大任を任されていた。
現在、彼の国は大規模な区画整理の最中であり、この区画整理をスムーズに終わらせることができたならば彼の昇進は間違いなしであるとされている。

ところが、そんな彼の出世を快く思わない者も多くいるのだ。 そんな人間の 1 人に、Mr.Sato Seabreeze Suzuki がいた。
彼は、ことあるごとに Mr. Yamada の足を引っ張ろうと画策してきた。 今回も Mr. Sato は足を引っ張るために、実際の区画整理を担当している組織に圧力をかけて、区画整理の結果を非常に分かりにくいものにしてしまった。

そのため、Mr. Yamada に渡された結果は、 ある正方形の土地をどの直線で分割したかという情報のみになっていた。
最低限、その正方形の土地がいくつに分割されたかだけでも分からなければ、Mr. Yamada は昇進どころか解雇されること間違いなしである。

あなたの仕事は、(-100,-100)、(100,-100)、(100,100)、(-100,100) を頂点とする正方形領域が、与えられた n 本の直線によっていくつに分割されているかを調べるプログラムを書いて、Mr. Yamada を解雇の危機から救うことである。

Input

入力は複数のテストケースからなる。

それぞれのテストケースの最初の行では、直線数を表す整数 n が与えられる（1 <= n <= 100）。 その後の n 行にはそれぞれ 4 つの整数 x1 、y1 、 x2 、y2 が含まれる。
これらの整数は直線上の相異なる 2 点 (x1 , y1 ) と (x2 , y2 ) を表す。
与えられる 2 点は常に正方形の辺上の点であることが保証されている。 与えられる n 本の直線は互いに異なり、直線同士が重なることはない。 また、直線が正方形の辺と重なることもない。

入力の終了は n = 0 で表される。

Output

それぞれのテストケースについて、n 本の直線によって分割された領域の数を 1 行で出力せよ。

なお、距離が 10-10 未満の 2 点は一致するとみなしてよい。 また、|PQ| < 10-10、|QR| < 10-10 でかつ |PR| >= 10-10となるような交点の組 P、Q、R は存在しない。

Sample Input

2
-100 -20 100 20
-20 -100 20 100
2
-100 -20 -20 -100
20 100 100 20
0

Output for the Sample Input

4
3

Solution in JAVA (judge verdict: Accepted)

import java.util.*;
import java.awt.geom.*;

public class Main{
	int k = 101;
	double EPS = 1.0e-10;
	
	private void doit(){
		Scanner sc = new Scanner(System.in);
		while(true){
			int n = sc.nextInt();
			if(n == 0) break;
			Line2D [] list = new Line2D[n];
			for(int i = 0; i < n; i++){
				int x1 = sc.nextInt();
				int y1 = sc.nextInt();
				Point2D p1 = new Point2D.Double(x1, y1);
				int x2 = sc.nextInt();
				int y2 = sc.nextInt();
				Point2D p2 = new Point2D.Double(x2, y2);
				Point2D pvec = mul(k, sub(p2, p1));
				Point2D p2after = new Point2D.Double(pvec.getX() + p2.getX(), pvec.getY() + p2.getY());
				Point2D p1after = new Point2D.Double(pvec.getX() * -1 + p1.getX(), pvec.getY() * -1 + p1.getY());
				list[i] = new Line2D.Double(p1after, p2after);
			}
			int count = 1;
			for(int i = 0; i < n; i++){
				ArrayList<Point2D> now = new ArrayList<Point2D>();
				for(int j = i-1; j >= 0; j--){
					if(list[i].intersectsLine(list[j])){
						Point2D p = intersectPtSS(list[i], list[j]);
						if(! isOK(p)) continue;
						if(contain(now, p)) continue;
						
						now.add(p);
						
					}
				}
				count += 1 + now.size();
			}
			System.out.println(count);
		}
	}
	private boolean contain(ArrayList<Point2D> now, Point2D p) {
		for(int i = 0; i < now.size(); i++){
			if(Math.abs(p.getX() - now.get(i).getX()) < EPS && 
					Math.abs(p.getY() - now.get(i).getY()) < EPS) return true;
		}
		return false;
	}
	private boolean isOK(Point2D p) {
		if(-100 + EPS < p.getX() && p.getX() < 100 - EPS && -100 + EPS < p.getY() && p.getY() < 100 - EPS){
			return true;
		}
		return false;
	}
	private Point2D intersectPtSS(Line2D l, Line2D m) {
		Point2D lVec = sub(l.getP2(), l.getP1());
		Point2D mVec = sub(m.getP2(), m.getP1());
		Point2D m1l1Vec = sub(m.getP1(), l.getP1());
		double a = cross(m1l1Vec, lVec);
		double b = cross(lVec, mVec);
		if(Math.abs(a) < EPS && Math.abs(b) < EPS){
			//平行な直線同士の場合
			if(l.getP1().distance(m.getP1()) < EPS) return l.getP1();
			if(l.getP1().distance(m.getP2()) < EPS) return l.getP1();
			return l.getP2();
		}
		double t = a / b;
		double resx = m.getX1() + t * mVec.getX();
		double resy = m.getY1() + t * mVec.getY();
		return new Point2D.Double(resx, resy);
	}
	
	private double cross(Point2D p1, Point2D p2) {
		double res = p1.getX() * p2.getY() - p1.getY() * p2.getX();
		return res;
	}
	
	private Point2D sub(Point2D p2, Point2D p1) {
		double x = p2.getX() - p1.getX();
		double y = p2.getY() - p1.getY();
		return new Point2D.Double(x, y);
	}
	
	private Point2D mul(double value, Point2D p) {
		return new Point2D.Double(p.getX() * value, p.getY() * value);
	}

	private void debug(Object... o) {
		System.out.println("debug = " + Arrays.deepToString(o));
	}

	public static void main(String[] args) {
		new Main().doit();
	}
}