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
NV1 H1 X1,1 Y1,1 X1,2 Y1,2 . . . X1,NV1 Y1,NV1
...
NVN HN XN,1 YN,1 XN,2 YN,2 . . . XN,NVN YN,NVN
RX1,1 RY1,1 RX1,2 RY1,2
...
RXM,1 RYM,1 RXM,2 RYM,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). NVi is the number of the vertices of the base of the i-th building (3 ≤ NVi ≤ 10). Hi is the
height of the i-th building. Xi, j and Yi, j are the (x, y)-coordinates of the j-th vertex of the base of the i-th
building. RXk,. and RYk,. 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

Solution in C (judge verdict: Accepted)

// AOJ 2099 Walk under a Scorching Sun
// 2018.3.25 bal4u

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define EPS			1e-6
#define EQ(a,b)		(fabs((a)-(b))<EPS)

// [library]

/* 実数座標のハッシュテーブル */
#define HASHSIZ 5003
#define M1      12
#define M2      1024
typedef struct { int id; double x, y; } HASH;
HASH hash[HASHSIZ+5], *hashend = hash + HASHSIZ;

int lookup(double x, double y)
{
	int xx = (int)(x*M2), yy = (int)(y*M2);
	unsigned i = 1 + (xx << M1) + yy;
	HASH *p = hash + (i % HASHSIZ);
	while (p->id) {
		if (EQ(x, p->x) && EQ(y, p->y)) return p->id -1;
		if (++p == hashend) p = hash;
	}
	return -1;
}

int insert(double x, double y, int id)
{
	int xx = (int)(x*M2), yy = (int)(y*M2);
	unsigned i = 1 + (xx << M1) + yy;
	HASH *p = hash + (i % HASHSIZ);
	while (p->id) {
		if (EQ(x, p->x) && EQ(y, p->y)) return 0;
		if (++p == hashend) p = hash;
	}
	p->x = x, p->y = y, p->id = id +1;
	return 1;
}

/* 優先度付き（キー t に関する昇順）キュー */
#define QMAX 1000
typedef struct { double t; int s; } QUE;
QUE que[QMAX]; int qsize;

#define PARENT(i) ((i)>>1)
#define LEFT(i)   ((i)<<1)
#define RIGHT(i)  (((i)<<1)+1)

void min_heapify(int i)
{
	int l, r, min;
	QUE qt;

	l = LEFT(i), r = RIGHT(i);
	if (l < qsize && que[l].t < que[i].t) min = l; else min = i;
	if (r < qsize && que[r].t < que[min].t) min = r;
	if (min != i) {
		qt = que[i], que[i] = que[min], que[min] = qt;
		min_heapify(min);
	}
}

void deq()
{
	que[0] = que[--qsize];
	min_heapify(0);
}

void enq(int s, double t)
{
	int i, min;
	QUE qt;

	i = qsize++;
	que[i].s = s, que[i].t = t;
	while (i > 0 && que[min = PARENT(i)].t > que[i].t) {
		qt = que[i], que[i] = que[min], que[min] = qt;
		i = min;
	}
}

/* マイナスを含む整数値の入力（スピードの点では scanf()を圧勝 */
//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0, c = getchar_unlocked();
	if (c == '-') {	c = getchar_unlocked();
		do n = 10*n + (c & 0xf), c = getchar_unlocked(); while (c >= '0');
		return -n;
	}
	do n = 10*n + (c & 0xf), c = getchar_unlocked(); while (c >= '0');
	return n;
}

// [\library]

typedef struct { double x, y; } PP;
typedef struct { PP s, e; } SEG;

#define INF			1e6
#define PI          3.1415926535897932384626433832795

#define PeqP(a,b)	(EQ(a.x,b.x)&&EQ(a.y,b.y))
PP vset(double x, double y) { PP r; r.x = x, r.y = y; return r; }
PP vadd(PP p1, PP p2) { PP r; r.x = p1.x + p2.x, r.y = p1.y + p2.y; return r; }
PP vsub(PP p1, PP p2) { PP r; r.x = p1.x - p2.x, r.y = p1.y - p2.y; return r; }
PP vsmul(PP p, double k) { PP r; r.x = p.x * k, r.y = p.y * k; return r; }
double dot(PP a, PP b) { return a.x * b.x + a.y * b.y; }
double cross(PP a, PP b) { return a.x * b.y - a.y * b.x; }
double dist(PP p1, PP p2) {	return hypot(p1.x-p2.x, p1.y-p2.y); };
int ccw(PP p, PP q, PP r) {
	double dx, dy, dx_, dy_, t;
	dx  = q.x - p.x, dy  = q.y - p.y;
	dx_ = r.x - p.x, dy_ = r.y - p.y;
	t = dx * dy_ - dy * dx_;
	if (fabs(t) < EPS) return 0;
	if (t <= 0) return -1;
	return 1;
}
PP dir(SEG s) { return vsub(s.e, s.s); }

int intersect(SEG s1, SEG s2)
{
	return ccw(s1.s, s1.e, s2.s) * ccw(s1.s, s1.e, s2.e) <= 0 &&
		   ccw(s2.s, s2.e, s1.s) * ccw(s2.s, s2.e, s1.e) <= 0;
}

PP crossPoint(int *ok, SEG s1, SEG s2)
{
	double n, d;
	PP one = {1,1};
	n = cross(vsub(s2.s, s1.s), dir(s2));
	d = cross(dir(s1), dir(s2));
	if (EQ(d,0)) { *ok = 0; return one; } 
	*ok = 1;
	return vadd(s1.s, vsmul(dir(s1), n/d));
}

int ycmp(PP *a, PP *b) {
	if (EQ(a->y, b->y)) {
		if (EQ(a->x, b->x)) return 0;
		if (a->x <= b->x) return -1;
		return 1;
	}
	if (a->y <= b->y) return -1;
	return 1;
}

int convex_hull(int n, PP *ps, PP *po)
{
	int i, k, j = 0;

	qsort(ps, n, sizeof(PP), ycmp);
	for (i = 0; i < n; i++) {
		while (j > 1 && cross(vsub(po[j-1], po[j-2]), vsub(ps[i], po[j-1])) <= EPS) j--;
		po[j++] = ps[i];
	}
	k = j;
	for (i = n - 2; i >= 0; i--) {
		while (j > k && cross(vsub(po[j-1], po[j-2]), vsub(ps[i], po[j-1])) <= EPS) j--;
		po[j++] = ps[i];
	}
	return j-1;
}

int uniq(PP *a, int n)
{
	int i, j;
	
	if (n == 0) return 0;
	for (i = 0, j = 1; j < n; j++) {
		while (j < n && PeqP(a[i], a[j])) j++;
		if (j < n) if (++i != j) a[i] = a[j];
	}
	return i+1;
}

#define MAX         200
#define PN			40

typedef struct { int h; double xmin, xmax, ymin, ymax; int n; PP p[PN]; } POLY;
POLY poly[16]; int N;

typedef struct { SEG s; int n; PP p[PN]; } T;
T road[16]; int M;

PP  tbl[MAX]; int sz;
int hi[MAX], to[MAX][8]; double cost[MAX][8];
double mk[MAX];

int xcmp(PP *a, PP *b) {
	if (EQ(a->x, b->x)) {
		if (EQ(a->y, b->y)) return 0;
		if (a->y <= b->y) return -1;
		return 1;
	}
	if (a->x <= b->x) return -1;
	return 1;
}

int xcmp2(int *a, int *b) { return xcmp(tbl + *a, tbl + *b); }

void pushback(int i, int j, double c)
{
	int k;
	if (i == j) return;
	for (k = 0; k < hi[i]; k++) if (to[i][k] == j) return;
	k = hi[i]++, to[i][k] = j, cost[i][k] = c;
}

double dijkstra(PP start, PP goal)
{
	int i, s, e, gno;
	double t, nt, ans;

	memset(mk, 0x45, sizeof(double)*sz);
	s = lookup(start.x, start.y), gno = lookup(goal.x, goal.y);
	qsize = 0, enq(s, 0), mk[s] = 0;

	ans = 0;
	while (qsize) {
		s = que[0].s, t = que[0].t, deq();

		if (s == gno) { ans = t; break; }
		if (mk[s] < t) continue;

		for (i = 0; i < hi[s]; i++) {
			e = to[s][i], nt = t + cost[s][i]; 
			if (mk[e] > nt) mk[e] = nt, enq(e, nt);
		}
	}
	return ans;
}

// 点が多角形に含まれているかの判定　1:含まれる, 0:含まれない
int contains(PP p)
{
	int i, j, n, f;
	PP a, b, t;
	double c;		// cross(a,b)

	for (j = 0; j < N; j++) {
		if (poly[j].xmin <= p.x && p.x <= poly[j].xmax &&
			poly[j].ymin <= p.y && p.y <= poly[j].ymax) {
			f = 0, n = poly[j].n;
			for (i = 0; i < n; i++) {
				a = vsub(poly[j].p[i], p), b = vsub(poly[j].p[i+1], p);
				if (EQ((c=cross(a, b)), 0) && dot(a, b) < EPS) return 0;
				if (!EQ(a.y, b.y) && a.y >= b.y) t = a, a = b, b = t, c = -c;
				if (a.y < EPS && EPS < b.y && c > EPS) f = !f;
			}
			if (f) return 1;
		}
	}
	return 0;
}

void arrange(PP start, PP goal)
{
	int i, j, k, f, u[40];
	double c;
	PP p, p1, p2;
	SEG s;

	tbl[0] = start, tbl[1] = goal;
	sz = 2; f = 0;
	for (i = 0; i < M; i++)	{
		tbl[sz++] = road[i].s.s, tbl[sz++] = road[i].s.e;
		road[i].p[road[i].n++] = road[i].s.s, road[i].p[road[i].n++] = road[i].s.e;

		if (!(f & 1)) {
			if (PeqP(start, road[i].s.s) || PeqP(start, road[i].s.e)) f |= 1;
			else if (!ccw(start, road[i].s.s, road[i].s.e)) {
				road[i].p[road[i].n++] = start, f |= 1;
			}
		}
		if (!(f & 2)) {
			if (PeqP(goal, road[i].s.s) || PeqP(goal, road[i].s.e)) f |= 2;
			else if (!ccw(goal, road[i].s.s, road[i].s.e)) {
				road[i].p[road[i].n++] = goal, f |= 2;
			}
		}
	}

	// cross points between roads
	for (i = 0; i < M; i++) {
		for (j = i+1; j < M; j++) {
			if (!intersect(road[i].s, road[j].s)) continue;
			p = crossPoint(&f, road[i].s, road[j].s);
			if (f) {
				tbl[sz++] = p;
				road[i].p[road[i].n++] = p;
				road[j].p[road[j].n++] = p;
			}
		}
	}

	// cross points between the shadows of polygon and roads
	for (i = 0; i < M; i++) {
		for (j = 0; j < N; j++) {
			for (k = 0; k < poly[j].n; k++) {
				s.s = poly[j].p[k], s.e = poly[j].p[k+1];
				if (!intersect(road[i].s, s)) continue;
				p = crossPoint(&f, road[i].s, s);
				if (f) tbl[sz++] = p, road[i].p[road[i].n++] = p;
			}
		}
	}

	qsort(tbl, sz, sizeof(PP), xcmp);
	sz = uniq(tbl, sz);
	for (i = 0; i < sz; i++) insert(tbl[i].x, tbl[i].y, i);

	memset(hi, 0, sz << 2);
	for (i = 0; i < M; i++) {
		k = 0; for (j = 0; j < road[i].n; j++) {
			u[k++] = lookup(road[i].p[j].x, road[i].p[j].y);
		}

		qsort(u, k, sizeof(int), xcmp2);
		for (j = 1; j < k; j++)	{
			p1 = tbl[u[j-1]], p2 = tbl[u[j]];
			p = vsmul(vadd(p1, p2), 0.5);
			if (contains(p)) c = 0; else c = dist(p1, p2);
			pushback(u[j-1], u[j], c), pushback(u[j], u[j-1], c);
		}
	}
}

int main()
{
	int i, j, k;
	double theta, phi, shadow;
	double xmin, xmax, ymin, ymax;
	PP start, goal;
	PP tmp[50], *pt;

	while (N = in()) {
		memset(hash, 0, sizeof(hash));
		M = in();

		for (i = 0; i < N; i++) {
			poly[i].n = k = in(), poly[i].h = in();
			pt = poly[i].p; for (j = 0; j < k; j++)	pt->x = in(), pt->y = in(), pt++;
		}
		for (i = 0; i < M; i++) {
			road[i].s.s.x = in(), road[i].s.s.y = in();
			road[i].s.e.x = in(), road[i].s.e.y = in();
			road[i].n = 0;
		}
		theta = (1+in()/180.0)*PI;			// theta + 180
		phi = in()/180.0*PI;
		start.x = in(), start.y = in();
		goal.x = in(), goal.y = in();

		// calc the shape of the shadow of polygons
		for (i = 0; i < N; i++) {
			shadow = poly[i].h / tan(phi);
			k = poly[i].n;
			pt = poly[i].p; for (j = 0; j < k; j++) {
				pt[k+j] = vadd(pt[j], vsmul(vset(cos(theta), sin(theta)), shadow));
			}
			poly[i].n = k = convex_hull(k<<1, poly[i].p, tmp);
			memcpy(poly[i].p, tmp, sizeof(PP)*k);
			poly[i].p[k] = poly[i].p[0];
			xmin = ymin = INF, xmax = ymax = -INF;
			pt = poly[i].p; for (j = 0; j < k; j++) {
				if (pt->x < xmin) xmin = pt->x;	if (pt->x > xmax) xmax = pt->x;
				if (pt->y < ymin) ymin = pt->y; if (pt->y > ymax) ymax = pt->y;
				pt++;
			}
			poly[i].xmin = xmin, poly[i].xmax = xmax;
			poly[i].ymin = ymin, poly[i].ymax = ymax;
		}

		arrange(start, goal);
		printf("%.8lf\n", dijkstra(start, goal));
	}
	return 0;
}