Problem:
Problem G:
Walk under a Scorching Sun
Edward R. Nelson is visiting a strange town for some task today. This city is built on a two-dimensional
flat ground with several vertical buildings each of which forms a convex polygon when seen from above
on it (that is to say, the buidlings are convex polygon columns). Edward needs to move from the point
S
to the point
T
by walking along the roads on the ground. Since today the sun is scorching and it is very
hot, he wants to walk in the sunshine as less as possible.
Your task is to write program that outputs the route whose length in the sunshine is the shortest, given
the information of buildings, roads and the direction of the sun.
Input
The input consists of multiple data sets. Each data set is given in the following format:
N M
NV
1
H
1
X
1,1
Y
1,1
X
1,2
Y
1,2
. . .
X
1,
NV
1
Y
1,
NV
1
...
NV
N
H
N
X
N
,1
Y
N
,1
X
N
,2
Y
N
,2
. . .
X
N
,
NV
N
Y
N
,
NV
N
RX
1,1
RY
1,1
RX
1,2
RY
1,2
...
RX
M
,1
RY
M
,1
RX
M
,2
RY
M
,2
θ φ
SX SY TX TY
All numbers are integers.
N
is the number of the buildings (1 ≤
N
≤ 15).
M
is the number of the roads
(1 ≤
M
≤ 15).
NV
i
is the number of the vertices of the base of the
i
-th building (3 ≤
NV
i
≤ 10).
H
i
is the
height of the
i
-th building.
X
i
,
j
and
Y
i
,
j
are the (
x
,
y
)-coordinates of the
j
-th vertex of the base of the
i
-th
building.
RX
k
,.
and
RY
k
,.
are the coordinates of the endpoints of the k-th roads. θ is the direction of the
sun, which is given by a counterclockwise degree which starts in the positive direction of
x
(0 ≤ θ < 360).
φ is the elevation angle of the sun (0 < φ < 90). (
SX
,
SY
) and (
TX
,
TY
) are the coordinates of the points
S
and
T
, respectively. All coordinates range from 0 to 1000.
The end of the input is represented by a line with
N
=
M
= 0. This line should not be processed.
It is guaranteed that both the points
S
and
T
are on the roads. No pair of an edge of a shade and a road
is parallel. You should assume that the sun is located infinitely far away and that it doesn’t move while
Edward is walking.
Output
For each data set, output in one line the length for which he has to walk in the sunshine at least. Your
program may output an arbitrary number of digits after the decimal point. However, the error should be
0.001 or less.
Sample Input
1 1
4 10 0 0 10 0 10 10 0 10
-5 -20 30 15
135 45
0 -15 15 0
0 0
Output for the Sample Input
11.213

Submitted solutions:

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
#include <utility>
#include <map>
using namespace std;
const double EPS = 1e-6;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};
namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b

}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) &&
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}
bool intersectSP(const L& s, const P &p){
    return abs(cross(s[0]-p, s[1]-p))<EPS  && dot(s[0]-p, s[1]-p)<EPS;
}

bool isParallel(const P &a, const P &b){
    return abs(cross(a,b)) < EPS;
}
bool isParallel(const L &a, const L &b){
    return isParallel(a[1]-a[0], b[1]-b[0]);
}
P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1]-l[0], m[1]-m[0]);
  double B = cross(l[1]-l[0], l[1]-m[0]);
  return m[0] + B/A *(m[1]-m[0]);
}

int in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int ret = -1;
    for(int i=0; i<n; i++){
        P a = poly[i]-p;
        P b = poly[(i+1)%n]-p;
        if(a.Y > b.Y) swap(a,b);
        if(intersectSP(L(a,b), P(0,0))) return 0;
        if(a.Y<=0 && b.Y>0 && cross(a,b)<0) ret = -ret;
    }
    return ret;
}

VP convex(VP v){
    VP ret;
    int n = v.size();
    sort(v.begin(), v.end());
    for(int i=0; i<n; i++){
        while((int)ret.size()>1 && cross(ret.back()-ret[ret.size()-2], v[i]-ret.back()) < EPS){
            ret.pop_back();
        }
        ret.push_back(v[i]);
    }
    int t = ret.size();
    for(int i=n-2; i>=0; i--){
        while((int)ret.size()>t && cross(ret.back()-ret[ret.size()-2], v[i]-ret.back()) < EPS){
            ret.pop_back();
        }
        ret.push_back(v[i]);
    }
    if((int)ret.size() > 1) ret.pop_back();
    return ret;
}

pair<vector<vector<double> >, VP> arrangementEX(const vector<L> &l, const VP &p){
    vector<VP> cp(l.size());
    VP plist = p;
    for(int i=0; i<(int)l.size(); i++){
        for(int j=i+1; j<(int)l.size(); j++){
            if(!isParallel(l[i], l[j]) && intersectSS(l[i], l[j])){
                P cpij = crosspointLL(l[i], l[j]);
                cp[i].push_back(cpij);
                cp[j].push_back(cpij);
                plist.push_back(cpij);
            }
        }
        for(int j=0; j<(int)p.size(); j++){
            if(intersectSP(l[i], p[j])){
                cp[i].push_back(p[j]);
            }
        }
        cp[i].push_back(l[i][0]);
        cp[i].push_back(l[i][1]);
        plist.push_back(l[i][0]);
        plist.push_back(l[i][1]);
        sort(cp[i].begin(), cp[i].end());
        cp[i].erase(unique(cp[i].begin(), cp[i].end()), cp[i].end());
    }
    sort(plist.begin(), plist.end());
    plist.erase(unique(plist.begin(), plist.end()), plist.end());

    int n = plist.size();
    map<P, int> conv;
    for(int i=0; i<n; i++){
        conv[plist[i]] = i;
    }
    vector<vector<double> > adj(n, vector<double>(n, INF));
    for(int i=0; i<(int)cp.size(); i++){
        for(int j=0; j<(int)cp[i].size()-1; j++){
            int jidx = conv[cp[i][j]];
            int jp1idx = conv[cp[i][j+1]];
            adj[jidx][jp1idx] = adj[jp1idx][jidx] = 0;
        }
    }
    return make_pair(adj, plist);
}

int main(){
    while(1){
        //input
        int n,m;
        cin >> n >> m;
        if(n == 0) break;

        vector<VP> poly(n);
        vector<double> h(n);
        for(int i=0; i<n; i++){
            int nv;
            cin >> nv >> h[i];
            poly[i].resize(nv);
            for(int j=0; j<nv; j++){
                int x,y;
                cin >> x >> y;
                poly[i][j] = P(x, y);
            }
        }
        vector<L> lines(m);
        for(int i=0; i<m; i++){
            int xs,ys,xt,yt;
            cin >> xs >> ys >> xt >> yt;
            lines[i] = L(P(xs, ys), P(xt, yt));
        }

        double th,phi;
        cin >> th >> phi;
        th *= PI/180; phi *= PI/180;
        P dir = P(cos(th+PI), sin(th+PI)) /tan(phi);
        for(int i=0; i<n; i++){
            VP tmp = poly[i];
            P idir = dir *h[i];
            for(int j=0; j<(int)poly[i].size(); j++){
                tmp.push_back(poly[i][j] +idir);
            }
            poly[i] = convex(tmp);
        }

        VP sg(2);
        int sx,sy,tx,ty;
        cin >> sx >> sy >> tx >> ty;
        sg[0] = P(sx, sy);
        sg[1] = P(tx, ty);

        //calc costs of edges
        auto ret = arrangementEX(lines, sg);
        auto &adj = ret.first;
        VP &plist = ret.second;
        int pn = plist.size();
        int sidx = lower_bound(plist.begin(), plist.end(), sg[0]) -plist.begin();
        int gidx = lower_bound(plist.begin(), plist.end(), sg[1]) -plist.begin();
        for(int i=0; i<pn; i++){
            for(int j=i+1;j<pn; j++){
                if(adj[i][j] == INF) continue;
                L e(plist[i], plist[j]);
                VP cp(2);
                cp[0] = e[0];
                cp[1] = e[1];
                for(int k=0; k<n; k++){
                    int vn = poly[k].size();
                    for(int l=0; l<vn; l++){
                        L edge(poly[k][l], poly[k][(l+1)%vn]);
                        if(!isParallel(e, edge) && intersectSS(e, edge)){
                            cp.push_back(crosspointLL(e, edge));
                        }
                    }
                }
                sort(cp.begin(), cp.end());
                cp.erase(unique(cp.begin(), cp.end()), cp.end());
                double cost = 0;
                for(int k=0; k<(int)cp.size()-1; k++){
                    P mid = (cp[k] +cp[k+1]) /2.0;
                    bool in = false;
                    for(int l=0; l<n; l++){
                        if(in_poly(mid, poly[l]) >= 0){
                            in = true;
                            break;
                        }
                    }
                    if(!in){
                        cost += abs(cp[k+1] -cp[k]);
                    }
                }
                adj[i][j] = adj[j][i] = cost;
            }
        }

        for(int k=0; k<pn; k++){
            for(int i=0; i<pn; i++){
                for(int j=0; j<pn; j++){
                    adj[i][j] = min(adj[i][j], adj[i][k] +adj[k][j]);
                }
            }
        }
        cout << fixed << setprecision(4);
        cout << adj[sidx][gidx] << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 3872
final_rank: 2

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
#include <utility>
#include <map>
using namespace std;
const double EPS = 1e-6;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};
namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b

}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) &&
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}
bool intersectSP(const L& s, const P &p){
    return abs(cross(s[0]-p, s[1]-p))<EPS  && dot(s[0]-p, s[1]-p)<EPS;
}

bool isParallel(const P &a, const P &b){
    return abs(cross(a,b)) < EPS;
}
bool isParallel(const L &a, const L &b){
    return isParallel(a[1]-a[0], b[1]-b[0]);
}
P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1]-l[0], m[1]-m[0]);
  double B = cross(l[1]-l[0], l[1]-m[0]);
  return m[0] + B/A *(m[1]-m[0]);
}

int in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int ret = -1;
    for(int i=0; i<n; i++){
        P a = poly[i]-p;
        P b = poly[(i+1)%n]-p;
        if(a.Y > b.Y) swap(a,b);
        if(intersectSP(L(a,b), P(0,0))) return 0;
        if(a.Y<=0 && b.Y>0 && cross(a,b)<0) ret = -ret;
    }
    return ret;
}

VP convex(VP v){
    VP ret;
    int n = v.size();
    sort(v.begin(), v.end());
    for(int i=0; i<n; i++){
        while((int)ret.size()>1 && cross(ret.back()-ret[ret.size()-2], v[i]-ret.back()) < EPS){
            ret.pop_back();
        }
        ret.push_back(v[i]);
    }
    int t = ret.size();
    for(int i=n-2; i>=0; i--){
        while((int)ret.size()>t && cross(ret.back()-ret[ret.size()-2], v[i]-ret.back()) < EPS){
            ret.pop_back();
        }
        ret.push_back(v[i]);
    }
    if((int)ret.size() > 1) ret.pop_back();
    return ret;
}

pair<vector<vector<double> >, VP> arrangementEX(const vector<L> &l, const VP &p){
    vector<VP> cp(l.size());
    VP plist = p;
    for(int i=0; i<(int)l.size(); i++){
        for(int j=i+1; j<(int)l.size(); j++){
            if(!isParallel(l[i], l[j]) && intersectSS(l[i], l[j])){
                P cpij = crosspointLL(l[i], l[j]);
                cp[i].push_back(cpij);
                cp[j].push_back(cpij);
                plist.push_back(cpij);
            }
        }
        for(int j=0; j<(int)p.size(); j++){
            if(intersectSP(l[i], p[j])){
                cp[i].push_back(p[j]);
            }
        }
        cp[i].push_back(l[i][0]);
        cp[i].push_back(l[i][1]);
        plist.push_back(l[i][0]);
        plist.push_back(l[i][1]);
        sort(cp[i].begin(), cp[i].end());
        cp[i].erase(unique(cp[i].begin(), cp[i].end()), cp[i].end());
    }
    sort(plist.begin(), plist.end());
    plist.erase(unique(plist.begin(), plist.end()), plist.end());

    int n = plist.size();
    map<P, int> conv;
    for(int i=0; i<n; i++){
        conv[plist[i]] = i;
    }
    vector<vector<double> > adj(n, vector<double>(n, INF));
    for(int i=0; i<(int)cp.size(); i++){
        for(int j=0; j<(int)cp[i].size()-1; j++){
            int jidx = conv[cp[i][j]];
            int jp1idx = conv[cp[i][j+1]];
            adj[jidx][jp1idx] = adj[jp1idx][jidx] = 0;
        }
    }
    return make_pair(adj, plist);
}

int main(){
    while(1){
        //input
        int n,m;
        cin >> n >> m;
        if(n == 0) break;

        vector<VP> poly(n);
        vector<double> h(n);
        for(int i=0; i<n; i++){
            int nv;
            cin >> nv >> h[i];
            poly[i].resize(nv);
            for(int j=0; j<nv; j++){
                int x,y;
                cin >> x >> y;
                poly[i][j] = P(x, y);
            }
        }
        vector<L> lines(m);
        for(int i=0; i<m; i++){
            int xs,ys,xt,yt;
            cin >> xs >> ys >> xt >> yt;
            lines[i] = L(P(xs, ys), P(xt, yt));
        }

        double th,phi;
        cin >> th >> phi;
        th *= PI/180; phi *= PI/180;
        P dir = P(cos(th+PI), sin(th+PI)) /tan(phi);
        for(int i=0; i<n; i++){
            VP tmp = poly[i];
            P idir = dir *h[i];
            for(int j=0; j<(int)poly[i].size(); j++){
                tmp.push_back(poly[i][j] +idir);
            }
            poly[i] = convex(tmp);
        }

        VP sg(2);
        int sx,sy,tx,ty;
        cin >> sx >> sy >> tx >> ty;
        sg[0] = P(sx, sy);
        sg[1] = P(tx, ty);

        //calc costs of edges
        auto ret = arrangementEX(lines, sg);
        auto &adj = ret.first;
        VP &plist = ret.second;
        int pn = plist.size();
        int sidx = lower_bound(plist.begin(), plist.end(), sg[0]) -plist.begin();
        int gidx = lower_bound(plist.begin(), plist.end(), sg[1]) -plist.begin();
        for(int i=0; i<pn; i++){
            for(int j=i+1;j<pn; j++){
                if(adj[i][j] == INF) continue;
                L e(plist[i], plist[j]);
                VP cp(2);
                cp[0] = e[0];
                cp[1] = e[1];
                for(int k=0; k<n; k++){
                    int vn = poly[k].size();
                    for(int l=0; l<vn; l++){
                        L edge(poly[k][l], poly[k][(l+1)%vn]);
                        if(!isParallel(e, edge) && intersectSS(e, edge)){
                            cp.push_back(crosspointLL(e, edge));
                        }
                    }
                }
                sort(cp.begin(), cp.end());
                cp.erase(unique(cp.begin(), cp.end()), cp.end());
                double cost = 0;
                for(int k=0; k<(int)cp.size()-1; k++){
                    P mid = (cp[k] +cp[k+1]) /2.0;
                    bool in = false;
                    for(int l=0; l<n; l++){
                        if(in_poly(mid, poly[l]) >= 0){
                            in = true;
                            break;
                        }
                    }
                    if(!in){
                        cost += abs(cp[k+1] -cp[k]);
                    }
                }
                adj[i][j] = adj[j][i] = cost;
            }
        }

        for(int k=0; k<pn; k++){
            for(int i=0; i<pn; i++){
                for(int j=0; j<pn; j++){
                    adj[i][j] = min(adj[i][j], adj[i][k] +adj[k][j]);
                }
            }
        }
        cout << fixed << setprecision(8);
        cout << adj[sidx][gidx] << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 3704
final_rank: 1

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;++i)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-7)
#define equals(a,b) (fabs((a)-(b))<EPS)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0


using namespace std;

const bool debug = false; // DEBUG - DEBUG - DEBUG - DEBUG - DEBUG - DEBUG - DEBUG - DEBUG - DEBUG
 
inline double toRad(double theta){
  return theta * M_PI / 180.0;
}

// x >= y
bool GTE(double x, double y){ return equals(x,y) || x > y; }
 
// x > y
bool GT(double x, double y){ return !equals(x,y) && x > y; }
 
// x < y
bool LT(double x, double y){ return !equals(x,y) && x < y; }
 
// x <= y
bool LTE(double x, double y){ return equals(x,y) || x < y; }

// -- Library 2d -- BEGIN ----------------------------------------
class Point{
public:
  double x,y;
 
  Point(double x = 0,double y = 0): x(x),y(y){}
 
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }
 
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
 
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
 
};
 
struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator <  (const Segment& s) const { return ( p2 == s.p2 ) ? p1 < s.p1 : p2 < s.p2; }
  bool operator == (const Segment& s) const { return ( s.p1 == p1 && s.p2 == p2 ) || ( s.p1 == p2 && s.p2 == p1 ); }
 
};
 
typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;
 
ostream& operator << (ostream& os,const Point& a){ return os << "(" << a.x << "," << a.y << ")"; }
 
ostream& operator << (ostream& os,const Segment& a){ return os << "( " << a.p1 << " , " << a.p2 << " )"; }
 
double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }
 
double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }
 
double norm(Point a){ return a.x*a.x+a.y*a.y; }
 
double abs(Point a){ return sqrt(norm(a)); }
 
//rad ????§???????????????¢?????§?????????????????¨
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }
 
// a => prev, b => cur, c=> next
// prev ?????? cur ????????£??? next ????????????????§????????±???????
double getArg(Point a,Point b,Point c){
  double arg1 = atan2(b.y-a.y,b.x-a.x);
  double arg2 = atan2(c.y-b.y,c.x-b.x);
  double arg = fabs( arg1 - arg2 );
  while( arg > M_PI ) arg -= 2.0 * M_PI;
  return fabs(arg);
}

int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

bool intersectLL(Line l, Line m) {
  return abs(cross(l.p2-l.p1, m.p2-m.p1)) > EPS || // non-parallel
         abs(cross(l.p2-l.p1, m.p1-l.p1)) < EPS;   // same line
}
bool intersectLS(Line l, Line s) {
  return cross(l.p2-l.p1, s.p1-l.p1)*       // s[0] is left of l
         cross(l.p2-l.p1, s.p2-l.p1) < EPS; // s[1] is right of l
}
bool intersectLP(Line l,Point p) {
  return abs(cross(l.p2-p, l.p1-p)) < EPS;
}
bool intersectSS(Line s, Line t) {
  return ccw(s.p1,s.p2,t.p1)*ccw(s.p1,s.p2,t.p2) <= 0 &&
         ccw(t.p1,t.p2,s.p1)*ccw(t.p1,t.p2,s.p2) <= 0;
}
bool intersectSP(Line s, Point p) {
  return abs(s.p1-p)+abs(s.p2-p)-abs(s.p2-s.p1) < EPS; // triangle inequality
}
 
Point projection(Line l,Point p) {
  double t = dot(p-l.p1, l.p1-l.p2) / norm(l.p1-l.p2);
  return l.p1 + (l.p1-l.p2)*t;
}
Point reflection(Line l,Point p) {
  return p + (projection(l, p) - p) * 2;
}
double distanceLP(Line l, Point p) {
  return abs(p - projection(l, p));
}
double distanceLL(Line l, Line m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m.p1);
}
 
double distanceLS(Line l, Line s) {
  if (intersectLS(l, s)) return 0;
  return min(distanceLP(l, s.p1), distanceLP(l, s.p2));
}
double distanceSP(Line s, Point p) {
  Point r = projection(s, p);
  if (intersectSP(s, r)) return abs(r - p);
  return min(abs(s.p1 - p), abs(s.p2 - p));
}
 
double distanceSS(Line s, Line t) {
  if (intersectSS(s, t)) return 0;
  return min(min(distanceSP(s, t.p1), distanceSP(s, t.p2)),
             min(distanceSP(t, s.p1), distanceSP(t, s.p2)));
}
 
Point crosspoint(Line l,Line m){
  double A = cross(l.p2-l.p1,m.p2-m.p1);
  double B = cross(l.p2-l.p1,l.p2-m.p1);
  if(abs(A) < EPS && abs(B) < EPS){
    vector<Point> vec;
    vec.push_back(l.p1),vec.push_back(l.p2),vec.push_back(m.p1),vec.push_back(m.p2);
    sort(vec.begin(),vec.end());
    assert(vec[1] == vec[2]); //???????????°??????????????????
    return vec[1];
    //return m.p1;
  }
  if(abs(A) < EPS)assert(false);
  return m.p1 + (m.p2-m.p1)*(B/A);
}

struct Edge {
  int from,to;
  double cost;
  Edge(int from=0,int to=0,double cost=0):from(from),to(to),cost(cost){}
  bool operator < (const Edge& a)const { return !equals(cost,a.cost) && cost < a.cost; }
};
 
vector<vector<Edge> > segmentArrangement(vector<Segment> vs,vector<Point> &ps) {
/*
???????????????????????????
????????§???????????????????????????ps????????????
*/
  rep(i,(int)vs.size())
    REP(j,i+1,(int)vs.size())
    if(intersectSS(vs[i],vs[j]))
      ps.push_back(Point(crosspoint(vs[i],vs[j])));
 
  sort(ps.begin(),ps.end());  
  ps.erase(unique(ps.begin(),ps.end()),ps.end());
 
  vector<vector<Edge> > ret(ps.size());
 
  for(int i=0;i<(int)vs.size();i++){
    vector<pair<double,int> > list;
    rep(j,(int)ps.size()) if(intersectSP(vs[i],ps[j]))list.push_back(pair<double,int>(norm(vs[i].p1-ps[j]),j));
    sort(list.begin(),list.end());
    for(int j=0;j+1<(int)list.size();++j) {
      int from = list[j].second, to = list[j+1].second;
      double cost = abs(ps[from]-ps[to]);
      ret[from].push_back(Edge(from,to,cost));
      ret[to].push_back(Edge(to,from,cost));
    }
  }  
  return ret;
}
 
//cross product of pq and pr
double cross3p(Point p,Point q,Point r) { return (r.x-q.x) * (p.y -q.y) - (r.y - q.y) * (p.x - q.x); }
  
//returns true if point r is on the same line as the line pq
bool collinear(Point p,Point q,Point r) { return fabs(cross3p(p,q,r)) < EPS; }
  
//returns true if point t is on the left side of line pq
bool ccwtest(Point p,Point q,Point r){
  return cross3p(p,q,r) > 0; //can be modified to accept collinear points
}
 
bool onSegment(Point p,Point q,Point r){
  return collinear(p,q,r) && equals(sqrt(pow(p.x-r.x,2)+pow(p.y-r.y,2)) + sqrt(pow(r.x-q.x,2) + pow(r.y-q.y,2) ),sqrt(pow(p.x-q.x,2)+pow(p.y-q.y,2)) ) ;
}
  
 
bool isConvex(vector<Point> p) {
  int sz = (int)p.size();
  if(sz < 3)return false;//boundary case, we treat a point or a line as not convex
  bool isLeft = ccwtest(p[0],p[1],p[2]);
  for(int i=1; i<(int)p.size();i++)
    if(ccwtest(p[i],p[(i+1)%sz],p[(i+2)%sz]) != isLeft) return false;
  return true;
}
 
 
double angle(Point a,Point b,Point c) {
  double ux = b.x - a.x, uy = b.y - a.y;
  double vx = c.x - a.x, vy = c.y - a.y;
  return acos((ux*vx + uy*vy)/sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)));
}  
  
//????§???¢poly?????????????????????????????????p????????¨??????????????????????????????  
bool inPolygon(Polygon poly,Point p){
  if((int)poly.size() == 0)return false;
  rep(i,(int)poly.size()) if(onSegment(poly[i],poly[(i+1)%poly.size()],p))return true;
  double sum = 0;
  for(int i=0; i < (int)poly.size() ;i++) {
    if( equals(cross(poly[i]-p,poly[(i+1)%poly.size()]-p),0.0) ) continue; // ????????????????????¨angle???nan?????????sum???nan??????????????¬
    if( cross3p(p,poly[i],poly[(i+1)%poly.size()]) < 0 ) sum -= angle(p,poly[i],poly[(i+1)%poly.size()]);
    else                                                 sum += angle(p,poly[i],poly[(i+1)%poly.size()]);
  }
  // ?????????????????????????????????????????¨?????????????????§??\????????????????????? 
  const double eps = 1e-5;
  return (fabs(sum - 2*M_PI) < eps || fabs(sum + 2*M_PI) < eps);
}  


bool inPolygon(const Polygon &poly,Segment seg){
  vector<Point> vp;
  vp.push_back(seg.p1);
  vp.push_back(seg.p2);
  rep(i,(int)poly.size()) {
    Segment edge = Segment(poly[i],poly[(i+1)%(int)poly.size()]);
    if( equals(cross(seg.p1-seg.p2,edge.p1-edge.p2),0.0) ) {
      if( onSegment(seg.p1,seg.p2,edge.p1) ) vp.push_back(edge.p1);
      if( onSegment(seg.p1,seg.p2,edge.p2) ) vp.push_back(edge.p2);
    } else {
      if( intersectSS(seg,edge) ) vp.push_back(crosspoint(seg,edge));
    }
  }
  sort(vp.begin(),vp.end());
  vp.erase(unique(vp.begin(),vp.end()),vp.end());
  rep(i,(int)vp.size()-1) {
    Point middle_point = ( vp[i] + vp[i+1] ) / 2.0;
    if( !inPolygon(poly,middle_point) ) return false;
  }
  return true;  
}
 
Polygon andrewScan(Polygon s)
{
  Polygon u,l;
  if((int)s.size() < 3)return s;
 
  sort(s.begin(),s.end());
 
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[s.size()-1]);
  l.push_back(s[s.size()-2]);
 
  for(int i=2;i<(int)s.size();i++)
    {
      for(int n=(int)u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--)
	u.pop_back();
      u.push_back(s[i]);
    }
 
  for(int i=(int)s.size()-3; i>=0 ; i--)
    {
      for(int n=(int)l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--)
	l.pop_back();
      l.push_back(s[i]);
    }
 
  reverse(l.begin(),l.end());
 
  for(int i = (int)u.size()-2; i >= 1; i--) l.push_back(u[i]);
 
  return l;
}


// -- Library 2d -- END   ----------------------------------------

struct Data {
  int cur;
  double v;
  bool operator < (const Data &data) const {
    //return v > data.v;
    return LT(data.v,v); // data.v < v
  }
};

double dijkstra(vector<vector<Edge>> &G,int s,int t) {

  int V = G.size();
  vector<double> mini(V,1e8);

  priority_queue<Data> Q;
  Q.push((Data){s,0});
  mini[s] = 0;

  while( !Q.empty() ) {
    Data data = Q.top(); Q.pop();
    rep(i,(int)G[data.cur].size()) {
      Edge &e = G[data.cur][i];
      if( LT(data.v+e.cost,mini[e.to]) ) {
	mini[e.to] = data.v + e.cost;
	Q.push((Data){e.to,mini[e.to]});
      }
    }
  }
  assert( !equals(mini[t],1e8) );
  return mini[t];
}

inline bool is_parallel(Segment s,Segment t) { return equals(cross(s.p1-s.p2,t.p1-t.p2),0.0); }

const double rho = 1e5;
Polygon calc_shadow(Polygon &poly,double H,double theta,double phi) {
  assert( poly.size() >= 3 );
  assert( !( is_parallel(Segment(poly[0],poly[1]),Segment(poly[1],poly[2])) ) );
  
  theta = toRad(theta);
  phi   = toRad(phi);
  if( debug ) {
    cout << "theta = " << theta << " and phi = " << phi << endl;
  }
  Polygon shadow_poly;
  rep(i,(int)poly.size()) {
    double r = H / tan(phi);
    Vector v = Vector(r*cos(theta),r*sin(theta));
    shadow_poly.push_back(poly[i]-v);
  }
  rep(i,(int)poly.size()) shadow_poly.push_back(poly[i]);
  return andrewScan(shadow_poly);
}

void compute(vector<double> &H,vector<Polygon> &polies,vector<Segment> &segs,double theta,double phi,Point &s,Point &t) {  
  // ??±?????°??????????§????
  vector<Polygon> shadow_polies;
  rep(i,(int)polies.size()) {
    shadow_polies.push_back(calc_shadow(polies[i],H[i],theta,phi));
    if( debug ) {
      puts("");
      cout << i << "-th polygon (MINE)" << endl;
      rep(j,(int)shadow_polies[i].size()) {
	cout << shadow_polies[i][j] << endl;
      }
      puts("");
    }
  }
  
  if( debug ) {
    puts("");
    cout << "--- graph construction was finished! ---" << endl;
    puts("");
  }

  // ????????????
  vector<Point> ps;
  rep(i,(int)segs.size()) {
    ps.push_back(segs[i].p1);
    ps.push_back(segs[i].p2);
  }
  ps.push_back(s);
  ps.push_back(t);
  rep(i,(int)shadow_polies.size()) {
    int V = shadow_polies[i].size();
    rep(j,V) {
      Segment seg = Segment(shadow_polies[i][j],shadow_polies[i][(j+1)%V]);
      rep(k,(int)segs.size()) {
	if( intersectSS(seg,segs[k]) ) {
	  ps.push_back(crosspoint(seg,segs[k]));
	}
      }
    }
  }

  if( debug ) {
    puts("");
    cout << "--- enumeration was finished! ---" << endl;
    puts("");
  }

  // ??°???????§????
  vector<vector<Edge>> G = segmentArrangement(segs,ps);
  assert( G.size() == ps.size() );

  if( debug ) {
    puts("");
    cout << "--- arrangement was finished! ---" << endl;
    puts("");
  }

  // ???????????? (????????°????????±???????????????????????????0)
  rep(i,(int)G.size()) {
    rep(j,(int)G[i].size()) {
      Edge &e = G[i][j];
      Point mp = (ps[e.from]+ps[e.to])/2.0;
      bool in_shadow = false;
      rep(k,(int)shadow_polies.size()) {
	if( inPolygon(shadow_polies[k],mp) ) {
	  in_shadow = true;
	  break;
	}
      }
      if( in_shadow ) {
	e.cost = 0;
      }
    }
  }

  if( debug ) {
    puts("");
    cout << "--- weighting was finished! ---" << endl;
    puts("");
  }
  
  // dijkstra
  int sp=-1,ep=-1;
  rep(i,(int)ps.size()) {
    if( ps[i] == s ) sp = i;
    if( ps[i] == t ) ep = i;
  }
  assert( sp != -1 );
  assert( ep != -1 );
  printf("%.10f\n",dijkstra(G,sp,ep));
}


int main() {
  int N,M;
  while( cin >> N >> M, N|M ) {
    vector<double> H(N);
    vector<Polygon> polies(N);
    rep(i,N) {
      int V;
      cin >> V >> H[i];
      polies[i].resize(V);
      rep(j,V) cin >> polies[i][j].x >> polies[i][j].y;
    }
    vector<Segment> segs(M);
    rep(i,M) cin >> segs[i].p1.x >> segs[i].p1.y >> segs[i].p2.x >> segs[i].p2.y;
    double theta,phi;
    cin >> theta >> phi;
    Point s,t;
    cin >> s.x >> s.y;
    cin >> t.x >> t.y;

    compute(H,polies,segs,theta,phi,s,t);

  }
  return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 3636
final_rank: 4

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;++i)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-7)
#define equals(a,b) (fabs((a)-(b))<EPS)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0


using namespace std;

const bool debug = false; // DEBUG - DEBUG - DEBUG - DEBUG - DEBUG - DEBUG - DEBUG - DEBUG - DEBUG
 
inline double toRad(double theta){
  return theta * M_PI / 180.0;
}

// x >= y
bool GTE(double x, double y){ return equals(x,y) || x > y; }
 
// x > y
bool GT(double x, double y){ return !equals(x,y) && x > y; }
 
// x < y
bool LT(double x, double y){ return !equals(x,y) && x < y; }
 
// x <= y
bool LTE(double x, double y){ return equals(x,y) || x < y; }

// -- Library 2d -- BEGIN ----------------------------------------
class Point{
public:
  double x,y;
 
  Point(double x = 0,double y = 0): x(x),y(y){}
 
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }
 
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
 
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
 
};
 
struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator <  (const Segment& s) const { return ( p2 == s.p2 ) ? p1 < s.p1 : p2 < s.p2; }
  bool operator == (const Segment& s) const { return ( s.p1 == p1 && s.p2 == p2 ) || ( s.p1 == p2 && s.p2 == p1 ); }
 
};
 
typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;
 
ostream& operator << (ostream& os,const Point& a){ return os << "(" << a.x << "," << a.y << ")"; }
 
ostream& operator << (ostream& os,const Segment& a){ return os << "( " << a.p1 << " , " << a.p2 << " )"; }
 
double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }
 
double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }
 
double norm(Point a){ return a.x*a.x+a.y*a.y; }
 
double abs(Point a){ return sqrt(norm(a)); }
 
//rad ????§???????????????¢?????§?????????????????¨
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }
 
// a => prev, b => cur, c=> next
// prev ?????? cur ????????£??? next ????????????????§????????±???????
double getArg(Point a,Point b,Point c){
  double arg1 = atan2(b.y-a.y,b.x-a.x);
  double arg2 = atan2(c.y-b.y,c.x-b.x);
  double arg = fabs( arg1 - arg2 );
  while( arg > M_PI ) arg -= 2.0 * M_PI;
  return fabs(arg);
}

int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

bool intersectLL(Line l, Line m) {
  return abs(cross(l.p2-l.p1, m.p2-m.p1)) > EPS || // non-parallel
         abs(cross(l.p2-l.p1, m.p1-l.p1)) < EPS;   // same line
}
bool intersectLS(Line l, Line s) {
  return cross(l.p2-l.p1, s.p1-l.p1)*       // s[0] is left of l
         cross(l.p2-l.p1, s.p2-l.p1) < EPS; // s[1] is right of l
}
bool intersectLP(Line l,Point p) {
  return abs(cross(l.p2-p, l.p1-p)) < EPS;
}
bool intersectSS(Line s, Line t) {
  return ccw(s.p1,s.p2,t.p1)*ccw(s.p1,s.p2,t.p2) <= 0 &&
         ccw(t.p1,t.p2,s.p1)*ccw(t.p1,t.p2,s.p2) <= 0;
}
bool intersectSP(Line s, Point p) {
  return abs(s.p1-p)+abs(s.p2-p)-abs(s.p2-s.p1) < EPS; // triangle inequality
}
 
Point projection(Line l,Point p) {
  double t = dot(p-l.p1, l.p1-l.p2) / norm(l.p1-l.p2);
  return l.p1 + (l.p1-l.p2)*t;
}
Point reflection(Line l,Point p) {
  return p + (projection(l, p) - p) * 2;
}
double distanceLP(Line l, Point p) {
  return abs(p - projection(l, p));
}
double distanceLL(Line l, Line m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m.p1);
}
 
double distanceLS(Line l, Line s) {
  if (intersectLS(l, s)) return 0;
  return min(distanceLP(l, s.p1), distanceLP(l, s.p2));
}
double distanceSP(Line s, Point p) {
  Point r = projection(s, p);
  if (intersectSP(s, r)) return abs(r - p);
  return min(abs(s.p1 - p), abs(s.p2 - p));
}
 
double distanceSS(Line s, Line t) {
  if (intersectSS(s, t)) return 0;
  return min(min(distanceSP(s, t.p1), distanceSP(s, t.p2)),
             min(distanceSP(t, s.p1), distanceSP(t, s.p2)));
}
 
Point crosspoint(Line l,Line m){
  double A = cross(l.p2-l.p1,m.p2-m.p1);
  double B = cross(l.p2-l.p1,l.p2-m.p1);
  if(abs(A) < EPS && abs(B) < EPS){
    vector<Point> vec;
    vec.push_back(l.p1),vec.push_back(l.p2),vec.push_back(m.p1),vec.push_back(m.p2);
    sort(vec.begin(),vec.end());
    assert(vec[1] == vec[2]); //???????????°??????????????????
    return vec[1];
    //return m.p1;
  }
  if(abs(A) < EPS)assert(false);
  return m.p1 + (m.p2-m.p1)*(B/A);
}

struct Edge {
  int from,to;
  double cost;
  Edge(int from=0,int to=0,double cost=0):from(from),to(to),cost(cost){}
  bool operator < (const Edge& a)const { return !equals(cost,a.cost) && cost < a.cost; }
};
 
vector<vector<Edge> > segmentArrangement(vector<Segment> vs,vector<Point> &ps) {
/*
???????????????????????????
????????§???????????????????????????ps????????????
*/
  rep(i,(int)vs.size())
    REP(j,i+1,(int)vs.size())
    if(intersectSS(vs[i],vs[j]))
      ps.push_back(Point(crosspoint(vs[i],vs[j])));
 
  sort(ps.begin(),ps.end());  
  ps.erase(unique(ps.begin(),ps.end()),ps.end());
 
  vector<vector<Edge> > ret(ps.size());
 
  for(int i=0;i<(int)vs.size();i++){
    vector<pair<double,int> > list;
    rep(j,(int)ps.size()) if(intersectSP(vs[i],ps[j]))list.push_back(pair<double,int>(norm(vs[i].p1-ps[j]),j));
    sort(list.begin(),list.end());
    for(int j=0;j+1<(int)list.size();++j) {
      int from = list[j].second, to = list[j+1].second;
      double cost = abs(ps[from]-ps[to]);
      ret[from].push_back(Edge(from,to,cost));
      ret[to].push_back(Edge(to,from,cost));
    }
  }  
  return ret;
}
 
//cross product of pq and pr
double cross3p(Point p,Point q,Point r) { return (r.x-q.x) * (p.y -q.y) - (r.y - q.y) * (p.x - q.x); }
  
//returns true if point r is on the same line as the line pq
bool collinear(Point p,Point q,Point r) { return fabs(cross3p(p,q,r)) < EPS; }
  
//returns true if point t is on the left side of line pq
bool ccwtest(Point p,Point q,Point r){
  return cross3p(p,q,r) > 0; //can be modified to accept collinear points
}
 
bool onSegment(Point p,Point q,Point r){
  return collinear(p,q,r) && equals(sqrt(pow(p.x-r.x,2)+pow(p.y-r.y,2)) + sqrt(pow(r.x-q.x,2) + pow(r.y-q.y,2) ),sqrt(pow(p.x-q.x,2)+pow(p.y-q.y,2)) ) ;
}
  
 
bool isConvex(vector<Point> p) {
  int sz = (int)p.size();
  if(sz < 3)return false;//boundary case, we treat a point or a line as not convex
  bool isLeft = ccwtest(p[0],p[1],p[2]);
  for(int i=1; i<(int)p.size();i++)
    if(ccwtest(p[i],p[(i+1)%sz],p[(i+2)%sz]) != isLeft) return false;
  return true;
}
 
 
double angle(Point a,Point b,Point c) {
  double ux = b.x - a.x, uy = b.y - a.y;
  double vx = c.x - a.x, vy = c.y - a.y;
  return acos((ux*vx + uy*vy)/sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)));
}  
  
//????§???¢poly?????????????????????????????????p????????¨??????????????????????????????  
bool inPolygon(Polygon poly,Point p){
  if((int)poly.size() == 0)return false;
  rep(i,(int)poly.size()) if(onSegment(poly[i],poly[(i+1)%poly.size()],p))return true;
  double sum = 0;
  for(int i=0; i < (int)poly.size() ;i++) {
    if( equals(cross(poly[i]-p,poly[(i+1)%poly.size()]-p),0.0) ) continue; // ????????????????????¨angle???nan?????????sum???nan??????????????¬
    if( cross3p(p,poly[i],poly[(i+1)%poly.size()]) < 0 ) sum -= angle(p,poly[i],poly[(i+1)%poly.size()]);
    else                                                 sum += angle(p,poly[i],poly[(i+1)%poly.size()]);
  }
  // ?????????????????????????????????????????¨?????????????????§??\????????????????????? 
  const double eps = 1e-5;
  return (fabs(sum - 2*M_PI) < eps || fabs(sum + 2*M_PI) < eps);
}  


bool inPolygon(const Polygon &poly,Segment seg){
  vector<Point> vp;
  vp.push_back(seg.p1);
  vp.push_back(seg.p2);
  rep(i,(int)poly.size()) {
    Segment edge = Segment(poly[i],poly[(i+1)%(int)poly.size()]);
    if( equals(cross(seg.p1-seg.p2,edge.p1-edge.p2),0.0) ) {
      if( onSegment(seg.p1,seg.p2,edge.p1) ) vp.push_back(edge.p1);
      if( onSegment(seg.p1,seg.p2,edge.p2) ) vp.push_back(edge.p2);
    } else {
      if( intersectSS(seg,edge) ) vp.push_back(crosspoint(seg,edge));
    }
  }
  sort(vp.begin(),vp.end());
  vp.erase(unique(vp.begin(),vp.end()),vp.end());
  rep(i,(int)vp.size()-1) {
    Point middle_point = ( vp[i] + vp[i+1] ) / 2.0;
    if( !inPolygon(poly,middle_point) ) return false;
  }
  return true;  
}
 
Polygon andrewScan(Polygon s)
{
  Polygon u,l;
  if((int)s.size() < 3)return s;
 
  sort(s.begin(),s.end());
 
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[s.size()-1]);
  l.push_back(s[s.size()-2]);
 
  for(int i=2;i<(int)s.size();i++)
    {
      for(int n=(int)u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--)
	u.pop_back();
      u.push_back(s[i]);
    }
 
  for(int i=(int)s.size()-3; i>=0 ; i--)
    {
      for(int n=(int)l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--)
	l.pop_back();
      l.push_back(s[i]);
    }
 
  reverse(l.begin(),l.end());
 
  for(int i = (int)u.size()-2; i >= 1; i--) l.push_back(u[i]);
 
  return l;
}


// -- Library 2d -- END   ----------------------------------------

struct Data {
  int cur;
  double v;
  bool operator < (const Data &data) const {
    //return v > data.v;
    return LT(data.v,v); // data.v < v
  }
};

double dijkstra(vector<vector<Edge>> &G,int s,int t) {

  int V = G.size();
  vector<double> mini(V,1e8);

  priority_queue<Data> Q;
  Q.push((Data){s,0});
  mini[s] = 0;

  while( !Q.empty() ) {
    Data data = Q.top(); Q.pop();
    rep(i,(int)G[data.cur].size()) {
      Edge &e = G[data.cur][i];
      if( LT(data.v+e.cost,mini[e.to]) ) {
	mini[e.to] = data.v + e.cost;
	Q.push((Data){e.to,mini[e.to]});
      }
    }
  }
  assert( !equals(mini[t],1e8) );
  return mini[t];
}

inline bool is_parallel(Segment s,Segment t) { return equals(cross(s.p1-s.p2,t.p1-t.p2),0.0); }

const double rho = 1e5;
Polygon calc_shadow(Polygon &poly,double H,double theta,double phi) {
  assert( poly.size() >= 3 );
  assert( !( is_parallel(Segment(poly[0],poly[1]),Segment(poly[1],poly[2])) ) );
  
  theta = toRad(theta);
  phi   = toRad(phi);
  if( debug ) {
    cout << "theta = " << theta << " and phi = " << phi << endl;
  }
  Polygon shadow_poly;
  rep(i,(int)poly.size()) {
    double r = H / tan(phi);
    Vector v = Vector(r*cos(theta),r*sin(theta));
    shadow_poly.push_back(poly[i]-v);
  }
  rep(i,(int)poly.size()) shadow_poly.push_back(poly[i]);
  return andrewScan(shadow_poly);
}

void compute(vector<double> &H,vector<Polygon> &polies,vector<Segment> &segs,double theta,double phi,Point &s,Point &t) {  
  // ??±?????°??????????§????
  vector<Polygon> shadow_polies;
  rep(i,(int)polies.size()) {
    shadow_polies.push_back(calc_shadow(polies[i],H[i],theta,phi));
    if( debug ) {
      puts("");
      cout << i << "-th polygon (MINE)" << endl;
      rep(j,(int)shadow_polies[i].size()) {
	cout << shadow_polies[i][j] << endl;
      }
      puts("");
    }
  }
  
  if( debug ) {
    puts("");
    cout << "--- graph construction was finished! ---" << endl;
    puts("");
  }

  // ????????????
  vector<Point> ps;
  rep(i,(int)segs.size()) {
    ps.push_back(segs[i].p1);
    ps.push_back(segs[i].p2);
  }
  ps.push_back(s);
  ps.push_back(t);
  rep(i,(int)shadow_polies.size()) {
    int V = shadow_polies[i].size();
    rep(j,V) {
      Segment seg = Segment(shadow_polies[i][j],shadow_polies[i][(j+1)%V]);
      rep(k,(int)segs.size()) {
	if( intersectSS(seg,segs[k]) ) {
	  ps.push_back(crosspoint(seg,segs[k]));
	}
      }
    }
  }

  if( debug ) {
    puts("");
    cout << "--- enumeration was finished! ---" << endl;
    puts("");
  }

  // ??°???????§????
  vector<vector<Edge>> G = segmentArrangement(segs,ps);
  assert( G.size() == ps.size() );

  if( debug ) {
    puts("");
    cout << "--- arrangement was finished! ---" << endl;
    puts("");
  }

  // ???????????? (????????°????????±???????????????????????????0)
  rep(i,(int)G.size()) {
    rep(j,(int)G[i].size()) {
      Edge &e = G[i][j];
      Point mp = (ps[e.from]+ps[e.to])/2.0;
      bool in_shadow = false;
      rep(k,(int)shadow_polies.size()) {
	if( inPolygon(shadow_polies[k],mp) ) {
	  in_shadow = true;
	  break;
	}
      }
      if( in_shadow ) {
	e.cost = 0;
      }
    }
  }

  if( debug ) {
    puts("");
    cout << "--- weighting was finished! ---" << endl;
    puts("");
  }
  
  // dijkstra
  int sp=-1,ep=-1;
  rep(i,(int)ps.size()) {
    if( ps[i] == s ) sp = i;
    if( ps[i] == t ) ep = i;
  }
  assert( sp != -1 );
  assert( ep != -1 );
  printf("%.10f\n",dijkstra(G,sp,ep));
}


int main() {
  int N,M;
  while( cin >> N >> M, N|M ) {
    vector<double> H(N);
    vector<Polygon> polies(N);
    rep(i,N) {
      int V;
      cin >> V >> H[i];
      polies[i].resize(V);
      rep(j,V) cin >> polies[i][j].x >> polies[i][j].y;
    }
    vector<Segment> segs(M);
    rep(i,M) cin >> segs[i].p1.x >> segs[i].p1.y >> segs[i].p2.x >> segs[i].p2.y;
    double theta,phi;
    cin >> theta >> phi;
    Point s,t;
    cin >> s.x >> s.y;
    cin >> t.x >> t.y;

    rep(i,N) {
      int V = polies[i].size();
      rep(j,V) {
	Segment seg = Segment(polies[i][j],polies[i][(j+1)%V]);
	rep(k,M) {
	  assert( !intersectSS(seg,segs[k]) );
	}
      }
    }

    compute(H,polies,segs,theta,phi,s,t);
  }
  return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 3652
final_rank: 5

code_snippet: #include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cmath>
#include <cassert>
#include <queue>
#include <set>
#include <map>
#include <valarray>
#include <bitset>
#include <stack>
using namespace std;

#define REP(i,n) for(int i=0;i<(int)n;++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
#define chmax(a,b) (a<(b)?(a=b,1):0)
#define chmin(a,b) (a>(b)?(a=b,1):0)
#define valid(y,x,h,w) (0<=y&&y<h&&0<=x&&x<w)
#define double long double
const int INF = 1<<29;
const double EPS = 1e-8;
const double PI = acos(-1);
typedef pair<int,int> pii;
typedef long long ll;

typedef double Weight;
struct Edge {
  int src, dst;
  Weight weight;
  Edge(int src, int dst, Weight weight) :
    src(src), dst(dst), weight(weight) { }
};

bool operator < (const Edge &e, const Edge &f) {
  return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!
    e.src != f.src ? e.src < f.src : e.dst < f.dst;
}

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;


// テゥツ?禿ァツィツ凝」ツ?古」ツ??」ツつ嘉」ツ?ェテ」ツ??・ツ?エテ・ツ青?
vector<Weight> dijkstra(const Graph &g, int s) {
  vector<Weight> dist(g.size(), INF);
  dist[s] = 0;
  priority_queue<Edge> Q; // "e < f" <=> "e.weight > f.weight"
  for (Q.push(Edge(-2, s, 0)); !Q.empty(); ) {
    Edge e = Q.top(); Q.pop();
    if (dist[e.dst] < e.weight) continue;
    FOR(f,g[e.dst]) {
      if (dist[f->dst] > e.weight+f->weight) {
        dist[f->dst] = e.weight+f->weight;
        Q.push(Edge(f->src, f->dst, e.weight+f->weight));
      }
    }
  }
  return dist;
}


typedef complex<double> P;
namespace std {
  bool operator < (const P& a, const P& b) {
    if (abs(a-b)<EPS) return 0;
    return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
  }
}
double cross(const P& a, const P& b) {
  return imag(conj(a)*b);
}
double dot(const P& a, const P& b) {
  return real(conj(a)*b);
}
struct L : public vector<P> {
  L(const P &a, const P &b) {
    push_back(a); push_back(b);
  }
  L() {resize(2);}
};
ostream &operator<<(ostream &os, const L &a) {
  os << a[0] << " -> " << a[1];
  return os;
}

typedef vector<P> G;
#define curr(P, i) P[i]
#define next(P, i) P[(i+1)%P.size()]
struct C {
  P p; double r;
  C(const P &p, double r) : p(p), r(r) { }
};

int ccw(P a, P b, P c) {
  b -= a; c -= a;
  if (cross(b, c) > EPS)   return +1;       // counter clockwise
  if (cross(b, c) < -EPS)   return -1;       // clockwise
  if (dot(b, c) < -EPS)     return +2;       // c--a--b on line
  if (norm(b) < norm(c)) return -2;       // a--b--c on line
  return 0;
}

P rotate(const P &p, double ang) {
  return p * P(cos(ang), sin(ang));
}

P projection(const L &l, const P &p) {
  double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]);
  return l[0] + t*(l[0]-l[1]);
}
P reflection(const L &l, const P &p) {
  return p + P(2,0) * (projection(l, p) - p);
}

double distanceLP(const L &l, const P &p) {
  return abs(p - projection(l, p));
}

bool intersectSP(const L &s, const P &p) {
  return abs(s[0]-p)+abs(s[1]-p)-abs(s[1]-s[0]) < EPS; // triangle inequality
}
bool intersectLL(const L &l, const L &m) {
  return abs(cross(l[1]-l[0], m[1]-m[0])) > EPS || // non-parallel
         abs(cross(l[1]-l[0], m[0]-l[0])) < EPS;   // same line
}
bool intersectLS(const L &l, const L &s) {
  return cross(l[1]-l[0], s[0]-l[0])*       // s[0] is left of l
         cross(l[1]-l[0], s[1]-l[0]) < EPS; // s[1] is right of l
}
bool intersectLP(const L &l, const P &p) {
  return abs(cross(l[1]-p, l[0]-p)) < EPS;
}
bool intersectSS(const L &s, const L &t) {
  return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 &&
         ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;
}
bool intersectSS2(const L &s, const L &t) {
  if (intersectSP(s,t[0]) || intersectSP(s,t[1]) ||
      intersectSP(t,s[0]) || intersectSP(t,s[1])) return 0;
  return intersectSS(s,t);
}
bool intersectHS(const L &h, const L &s) {
  if (intersectLP(h,s[0]) || intersectLP(h,s[1]) ||
      intersectLP(s,h[0]) || intersectLP(s,h[1])) return 0;
  if (intersectSS(h,s)) return 1;
  if (!intersectLS(h,s)) return 0;
  return (ccw(s[0],s[1],h[0]) == 1) ^ (cross(s[1]-s[0], h[1]-h[0]) > 0);
}

P crosspoint(const L &l, const L &m) {
  double A = cross(l[1] - l[0], m[1] - m[0]);
  double B = cross(l[1] - l[0], l[1] - m[0]);
  if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line
  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m[0] + B / A * (m[1] - m[0]);
}

bool EQ(double a, double b) {
  return abs(a-b) < EPS;
}
bool EQP(const P &a, const P &b) {
  return norm(a-b) < EPS*EPS;
}

Graph segmentArrangement(const vector<L> &ss, vector<P> &ps, P start, P end) {
  for (int i = 0; i < ss.size(); ++i) { // O(n^2)
    ps.push_back( ss[i][0] );
    ps.push_back( ss[i][1] );
    if (intersectSP(ss[i], start)) ps.push_back(start);
    if (intersectSP(ss[i], end)) ps.push_back(end);
    for (int j = i+1; j < ss.size(); ++j)
      if (intersectSS(ss[i], ss[j]))
        ps.push_back( crosspoint(ss[i], ss[j]) );
  }
  sort(ALL(ps)); ps.erase(unique(ALL(ps)), ps.end());

  Graph g(ps.size());
  for (int i = 0; i < ss.size(); ++i) {
    vector< pair<double, int> > list;
    for (int j = 0; j < ps.size(); ++j)
      if (intersectSP(ss[i], ps[j]))
        list.push_back(make_pair(norm(ss[i][0]-ps[j]), j));
    sort(ALL(list));
    for (int j = 0; j+1 < list.size(); ++j) {
      int a = list[j].second, b = list[j+1].second;
      g[a].push_back( Edge(a, b, abs(ps[a]-ps[b])) );
      g[b].push_back( Edge(b, a, abs(ps[a]-ps[b])) );
    }
  }
  return g;
}


vector<P> graham(vector<P> v) {
  if (v.size()<=2) return v;
  int n = v.size(), k = 0;
  sort(ALL(v));
  vector<P> ret(2*n);
  for (int i = 0; i < n; ret[k++] = v[i++])
    while (k >= 2 && ccw(ret[k-2],ret[k-1],v[i]) < 0) k--;
  for (int i = n-2, t = k+1; i >= 0; ret[k++] = v[i--])
    while (k >= t && ccw(ret[k-2],ret[k-1],v[i]) < 0) k--;
  ret.resize(k-1);
  return ret;
}

typedef valarray<double> point;
struct line : public vector<point> {
  line() {}
  line(point a, point b) { push_back(a); push_back(b); }
};
point Point(double x, double y, double z) {
  point p(3);
  p[0]=x;p[1]=y;p[2]=z;
  return p;
}
double dot(const point& a, const point& b) {
  return (a * b).sum();
}
point cross(const point& a, const point& b) {
  return a.cshift(+1)*b.cshift(-1)
       - a.cshift(-1)*b.cshift(+1);
}
double norm(const point &a) {
  return dot(a,a);
}
double length(const point &a) {
  return sqrt(dot(a,a));
}
double angle(const point &a, const point &b) {
  return acos( dot(a,b)/length(a)/length(b) );
}
point input() {
  double a[3];
  REP(i,3) cin >>a[i];
  return point(a,3);
}
ostream &operator<<(ostream &os, const point &a) {
  char str[200];
  snprintf(str, 199, "(%.2Lf, %.2Lf, %.2Lf)", a[0], a[1], a[2]);
  os << str;
  return os;
}

point projection(const line &l, const point &p) {
  double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]);
  return l[0] + t * (l[0]-l[1]);
}
bool intersectSP(const line &s, const point &p) {
  return length(s[0]-p) + length(s[1]-p) - length(s[1]-s[0]) < EPS;
}
double distanceSP(const line &s, const point &p) {
  const point r = projection(s, p);
  if (intersectSP(s, r)) { return length(r-p); }
  return min(length(s[0]-p), length(s[1]-p));
}
// テ」ツδ凖」ツつッテ」ツδ暗」ツδォテ」ツ?セテ」ツつ湘」ツつ甘」ツ?ョテ・ツ崢榲ィツサツ「 * axis : テ・ツ崢榲ィツサツ「ティツサツクテ」ツ?ョテ・ツ債佚、ツスツ催」ツδ凖」ツつッテ」ツδ暗」ツδォ
point rotate(point axis, double ang, point a) {
  return a * cos(ang) + (1.0 - cos(ang)) * dot(a, axis) * axis + cross(axis, a) * sin(ang);
}
// テァツオツ古・ツコツヲテ」ツ?ィテァツキツッテ・ツコツヲテ」ツ?凝」ツつ嘉・ツコツァテヲツィツ凖」ツつ津ィツィツ暗ァツョツ療」ツ?づァツ青ε」ツ?ョテ、ツクツュテ・ツソツε」ツ?古・ツ篠淌ァツつケテ」ツ??
// lon : テッツシツ静・ツコツヲテ」ツ?凝」ツつ嘉ヲツ敖アテ」ツ?セテ」ツつ湘」ツつ甘」ツ??ッツシツ静」ツ?愿ッツシツ禿ッツシツ姪ッツシツ?
// lat : テ・ツ個療ヲツ・ツオテ」ツ?凝」ツつ嘉・ツ債療ヲツ・ツオテヲツ鳴ケテ・ツ青妥」ツ??ッツシツ静」ツ?愿ッツシツ妥ッツシツ佚ッツシツ?
// lon=0,lat=90 テ」ツ?古ッツスツ佚ィツサツクテ」ツ?〕on=90,lat=90 テ」ツ?古ッツスツ凖ィツサツクテ」ツ??・ツ個療ヲツ・ツオテ」ツ?古ッツスツ堙ィツサツク
point coord(double R, double lon, double lat) {
  point res(3);
  res[0] = R*cos(lon)*sin(lat);
  res[1] = R*sin(lon)*sin(lat);
  res[2] = R*cos(lat);
  return res;
}

// xyテ・ツケツウテゥツ敖「テ」ツ?クテ」ツ?ョテ・ツーツ?・ツスツア
P projection(const point &p, const point &ray) {
  double k = - p[2] / ray[2];
  assert(k>0);
  double x = p[0] + k * ray[0];
  double y = p[1] + k * ray[1];
  return P(x,y); 
}

bool convex_contain(const G &g, const P &p) { // テ・ツ債甘ヲツ卍づィツィツ暗・ツ崢榲」ツつ甘」ツつ津、ツサツョテ・ツョツ?
  REP(i,g.size())
    if (ccw(g[i], next(g, i), p) == -1) return 0;
  return 1;
}

G shadows[15];
int n,m;

double sunshine(const L &seg) {
  vector<double> v;
  double len = abs(seg[1]-seg[0]);  
  v.push_back(0);
  v.push_back(len);
  REP(i,n) {
    REP(j,shadows[i].size()) {
      L l(shadows[i][j], shadows[i][(j+1)%shadows[i].size()]);
      if (intersectSS(seg,l)) {
        v.push_back(abs(crosspoint(seg,l)-seg[0]));
      }
    }
  }
  sort(ALL(v));
  v.erase(unique(ALL(v)), v.end());
  double ans = 0;
  REP(i,v.size()-1) {
    double ss = (v[i]+v[i+1])*0.5 / len;
    P p = (1-ss)*seg[0] + ss*seg[1];
    // cout << p << endl;
    bool in = 0;    
    REP(j,n) {
      if (convex_contain(shadows[j],p)) {
        in = 1;
        break;
      }
    }
    if (in) {
    } else {
      ans += v[i+1]-v[i];
    }
  }
  return ans;
}

double h[15];
G buil[15];

int main() {
  while(cin>>n>>m,n||m) {
    REP(i,n) {
      int nv; cin >> nv;
      cin >> h[i];
      buil[i].clear();
      REP(j,nv) {
        P p;
        cin >> p.real() >> p.imag();
        buil[i].push_back(p);
      }
    }
    vector<L> segs;
    REP(i,m) {
      P a,b;
      cin >> a.real() >> a.imag();
      cin >> b.real() >> b.imag();
      segs.push_back(L(a,b));
    }
    double theta, phi;
    cin >> theta >> phi;
    theta = theta*PI/180;
    phi = phi*PI/180;
    point ray(-coord(1,theta,PI/2-phi));

    // cout << ray << endl;
    
    REP(i,n) {
      vector<P> vp;
      REP(j,buil[i].size()) {
        double x = buil[i][j].real();
        double y = buil[i][j].imag();
        vp.push_back(P(x,y));
        P p = projection(Point(x,y,h[i]), ray);
        // cout << Point(x,y,h[i]) << " " << ray <<  "   - > " << p << endl;
        vp.push_back(p);
      }
      shadows[i] = graham(vp);
      // REP(j,shadows[i].size()) {
      //   cout << shadows[i][j] << endl;
      // }
    }
    
    P start, end;
    cin >> start.real() >> start.imag() >> end.real() >> end.imag();
    // REP(i,n) {
    //   if (intersectSP(segs[i],start)) {
    //     segs.push_back(L(segs[i][0],start));
    //     segs.push_back(L(start,segs[i][1]));
    //   }
    //   if (intersectSP(segs[i],end)) {
    //     segs.push_back(L(segs[i][0],end));
    //     segs.push_back(L(end,segs[i][1]));        
    //   }
    // }
    vector<P> pv;
    Graph g = segmentArrangement(segs,pv,start,end);
    int sid = -1, eid = -1;
    REP(i,pv.size()) {
      if (abs(pv[i]-start) < 1e-6) sid = i;
      if (abs(pv[i]-end) < 1e-6) eid = i;
    }
    assert(sid != -1 && eid != -1);
    int N = g.size();
    REP(i,N) {
      FOR(it, g[i]) {
        int a = it->src;
        int b = it->dst;
        L seg(pv[a],pv[b]);
        it->weight = sunshine(seg);
        
        // cout << pv[a] << " -> " << pv[b] << "  : " << it->weight << endl;
      }
    }
    // cout << "OK" << endl;    
    double ans = dijkstra(g,sid)[eid];
    printf("%.10Lf\n", ans);
  }
}
accuracy: 1
time_ms: 670
memory_kb: 1356
final_rank: 2