Problem:
Problem E: Kuru-Kuru Robot

ロボット工学の研究者であるアシモフ博士は、新しいロボットの開発に成功した。このロボットは、床に張り巡らせた特殊なワイヤーに沿って自由に動くことができる。ロボットは常に現在いるワイヤーに平行な方向を向いて前進する。

すばらしいことに、このロボットはワイヤー上を移動するためにその距離にかかわらずエネルギーを消費しない。しかし、ワイヤーの端点やワイヤーの交点で向きを変えるためにはその点を中心に回転する必要があり、その回転角度だけエネルギーを消費する。

このロボットをスタート地点からゴール地点まで動かしたい。例えば、下図においてロボットを start に東向き（下図 x軸の正の向き）で配置し goal まで動かしてみよう。start から交点 A 交点 B を経由して goal にたどり着く経路と、交点 A 交点 C を経由する経路があるが、前者の方が移動距離が長いものの回転角度が少ないためエネルギー消費量は少ない。

あなたの仕事は、床にあるワイヤーの位置、スタート地点、ゴール地点を読み込み、スタート地点からゴール地点へ移動するために必要な回転角度の合計の最小値を報告するプログラムを作成することである。

ロボットはスタート地点においてどのような向きに配置してもよく、ゴール地点ではどの方向を向いていてもよい。

Input

入力は複数のデータセットからなる。各データセットの形式は以下のとおり：

n
x11 y11 x21 y21
x12 y12 x22 y22
.
.
.
x1n y1n x2n y2n
sx sy gx gy

n はワイヤーの数を示す整数である。x1i y1i は i 番目のワイヤーの一方の端点の座標、x2i y2i は i 番目のワイヤーのもう一方の端点の座標を示す。

sx sy、gx gy はそれぞれスタート地点とゴール地点の座標を示す。

与えられる座標はすべて整数値であり、x軸 y軸の値は -1000　以上 1000 以下である。また、スタート地点とゴール地点は与えられるワイヤーの端点上にあると仮定してよい。

n ≤ 50 であると仮定してよい。

n が 0 のとき入力の終了を示す。

Output

各データセットに対して、回転角度の合計の最小値を１行に出力せよ。ロボットがゴール地点にたどり着けない場合は "-1" と出力せよ。出力は 0.00001 以下の誤差を含んでもよい。

Sample Input

8
1 3 11 3
5 3 13 11
10 10 17 10
11 2 11 6
10 5 14 5
13 6 13 2
17 10 17 3
13 3 19 3
1 3 19 3
6
1 3 11 3
5 3 13 11
10 10 17 10
11 2 11 6
10 5 14 5
13 3 19 3
1 3 19 3
2
0 0 7 0
3 0 7 3
0 0 7 3
0

Output for the Sample Input

270.0000
-1
36.86989765

Solution in C++11 (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)
using namespace std;
typedef long long LL;

typedef complex<double> P;
const double EPS = 1e-8;

// 誤差を加味した符号判定
int sign(double x){ return x > EPS ? 1 : x < -EPS ? -1 : 0; }

// 内積・外積
double dot(P a, P b){return real(conj(a) * b);}
double cross(P a, P b){return imag(conj(a) * b);}

// OAとOBのなす符号付き角度 [-pi, pi]
// example : (1, 0), (0, 1) -> pi/2
double angle(P a, P b){return arg(conj(a) * b);}

// aをc中心にb[rad]回転
P rotate(P a, double b, P c = P()){return (a - c) * polar(1.0, b) + c;}

int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (cross(b, c) > +EPS)   return +1; // 反時計回り
    if (cross(b, c) < -EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}

enum{ OUT, ON, IN };

// Pointの比較をしたいときだけ定義する．
namespace std{
    bool operator < (const P& a, const P& b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
    }
};

typedef vector<P> L;
P vec(L l){return l[1] - l[0];}

// 線分と点の交差判定(端点の処理に注意)(端点は含むけれども誤差に注意)
// verify : AOJ1279, AOJ2506
bool iSP(L s, P p) {return ccw(s[0], s[1], p) == 0;}

// 直線と直線の交点
// Verified: AOJ2579
// size()によって場合分け
// *4 : 直線が重なる  *1 : 交点が1つ存在 *0 : 直線が交差しない
vector<P> pLL(L l, L m){
    double A = cross(vec(l), vec(m));
    double B = cross(vec(l), l[1] - m[0]);
    if(sign(A) == 0 && sign(B) == 0) return {l[0], l[1], m[0], m[1]}; // 二直線が重なっている
    if(sign(A) == 0) return{}; // 直線が交わらない
    return {m[0] + vec(m) * B / A};
}

vector<P> pSS(L l, L m){
    vector<P> res;
    auto find = [&](P p){ 
        for(P r : res) if(sign(abs(r - p)) == 0)
                return true;
        return false;
    };
    for(P p : pLL(l, m))
        if(iSP(l,p) && iSP(m,p) && !find(p)) // 片方が直線の場合は適宜変えること
            res.push_back(p);
    return res;
}

// 入力
// ss : 線分のリスト
//
// 出力
// ps : グラフの頂点番号に対応する点が入る
// 返り値 : 上の説明のグラフ
//
// Verified
// AOJ 2113
typedef vector<int> Node;
typedef vector<Node> Graph;
Graph segment_arrangement(const vector<L> &ss, vector<P> &ps) {
    for (int i = 0; i < ss.size(); i++) {
        ps.push_back( ss[i][0] );
        ps.push_back( ss[i][1] );
        for (int j = i+1; j < ss.size(); j++){
            auto cp = pSS(ss[i], ss[j]);
            if (!cp.empty()) {
                assert(cp.size() == 1);
                ps.push_back( cp.back() );
            }
        }
    }
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());

    Graph g(ps.size());
    for (int i = 0; i < ss.size(); i++) {
        vector<int> on;
        for (int j = 0; j < ps.size(); j++){
            if (iSP(ss[i], ps[j])){
                on.push_back(j);
            }
        }
        for (int j = 0; j + 1 < on.size(); j++) {
            for(int k = j + 1; k < on.size(); k++) {
                int a = on[j], b = on[k];
                g[a].push_back( b );
                g[b].push_back( a );
            }
        }
    }
    return g;
}

// 線分併合
//
// 線分のリストからオーバーラップするものたちをまとめ,新しい線分のリストを作る.
// 元々の線分のリストにおける順番は破壊される．
//
// not verified
void merge_segments(vector<L>& segs) {
    auto merge_if_able = [](L& s, L t){
        if (abs(cross(s[1]-s[0], t[1]-t[0])) > EPS) return false;
        //if (sign(cross(vec(s), vec(t))) != 0) return false;
        if (ccw(s[0], t[0], s[1]) == +1 ||
                ccw(s[0], t[0], s[1]) == -1) return false; // not on the same line
        if (ccw(s[0], s[1], t[0]) == -2 ||
                ccw(t[0], t[1], s[0]) == -2) return false; // separated
        s = { min(s[0], t[0]), max(s[1], t[1]) };
        return true;
    };
    for (int i = 0; i < segs.size(); ++i)
        if (segs[i][1] < segs[i][0])
            swap(segs[i][1], segs[i][0]);
    for (int i = 0; i < segs.size(); ++i)
        for (int j = i+1; j < segs.size(); ++j)
            if (merge_if_able(segs[i], segs[j]))
                segs[j--] = segs.back(), segs.pop_back();
}
P input() {
    double x, y;
    cin >> x >> y;
    return {x, y};
}
typedef tuple<double, int, int> T;
const int MAX = 500;
const double INF = 1e64;

int main(){
    int n;
    while(cin >> n && n > 0){
        vector<L> lines(n);
        REP(i, n) {
            P a = input();
            P b = input();
            lines[i] = {a, b};
        }

        int size = lines.size();
        merge_segments(lines);
        //assert(size == lines.size());

        vector<P> ps;
        Graph G = segment_arrangement(lines, ps);
        assert(ps.size() < MAX);

        REP(i, ps.size()) REP(j, i) {
            assert(abs(ps[i] - ps[j]) > EPS);
        }

        auto find = [](const vector<P>& pv, P p) -> int {
            for(int i = 0; i < pv.size(); i++) {
                auto q = pv[i];
                if(abs(p - q) < EPS) {
                    return i;
                }
            }
            return -1;
        };
        
        P sp = input();
        P gp = input();
        int s = find(ps, sp);
        int g = find(ps, gp);

        if(s == g) {
            cout << 0 << endl;
            continue;
        }

        assert(s != -1 && g != -1);

        priority_queue<T, vector<T>, greater<T>> que;
        double dist[MAX][MAX] = {};
        REP(i, MAX) REP(j, MAX) dist[i][j] = INF;
        for(int u : G[s]) {
            dist[s][u] = 0.0;
            que.push(T(0.0, s, u));
        }
        double ans = INF;
        while(!que.empty()) {
            T t = que.top(); que.pop();
            double d;
            int u, v;
            if(v == g) {
                ans = d;
                break;
            }
            tie(d, u, v) = t;
            for(int w : G[v]) if(u != w) {
                P p = ps[v] - ps[u];
                P q = ps[w] - ps[v];
                double th = abs(angle(p, q)) / M_PI * 180.0;
                double nd = d + th;
                if(dist[v][w] > nd) {
                    dist[v][w] = nd;
                    que.push(T(nd, v, w));
                }
            }
        }
        if(ans == INF) {
            cout << -1 << endl;
        } else {
            printf("%.12f\n", ans);
        }
    }

    return 0;
}