import java.awt.geom.*; import java.io.*; import java.util.*; public class walk { private static final double EPS = 1.0e-12; private static final Scanner cin = new Scanner(System.in); public static void main(String[] args) { DataSet ds; while((ds = DataSet.scan(cin)) != null) { System.out.println(String.format("%.8f", ds.solve())); } } private static class MyPoint extends Point2D.Double { public MyPoint() { } public MyPoint(double x, double y) { super(x, y); } public static MyPoint center(MyPoint p1, MyPoint p2) { return new MyPoint((p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0); } public String toString() { return String.format("(%s,%s)", x, y); } } private static class MyLine extends Line2D.Double { public MyLine() { } public MyLine(MyPoint p1, MyPoint p2) { super(p1, p2); } public MyLine(double x1, double y1, double x2, double y2) { super(x1, y1, x2, y2); } public MyPoint intersectsAt(MyLine l) { if(!intersectsLine(l)) { return null; } MyLine m = this; double la = l.y2 - l.y1; double lb = l.x2 - l.x1; double lc = l.x1 * l.y2 - l.x2 * l.y1; double ma = m.y2 - m.y1; double mb = m.x2 - m.x1; double mc = m.x1 * m.y2 - m.x2 * m.y1; MyPoint p = new MyPoint(); p.x = (lc * mb - lb * mc) / (la * mb - lb * ma); p.y = (lc * ma - la * mc) / (la * mb - lb * ma); return p; } public String toString() { return String.format("(%s,%s)-(%s,%s)", x1, y1, x2, y2); } } private static class MyPolygon { public final MyPoint[] v; // vertices (counterclockwise) public final MyLine [] l; // edges public final int n; public MyPolygon(MyPoint[] v) { this.v = v; this.l = new MyLine[v.length]; this.n = v.length; for(int i = 0; i < n; i++) { l[i] = new MyLine(v[i], v[(i + 1) % n]); } } public boolean contains(MyPoint p) { for(int i = 0; i < n; i++) { if(l[i].relativeCCW(p) >= 0) { return false; } } return true; } } private static class Building extends MyPolygon { public final double h; public Building(MyPoint[] v, double h) { super(v); this.h = h; } public MyPolygon makeShade(double tha, double phi) { double sx = Math.cos(tha); double sy = Math.sin(tha); double sl = h / Math.tan(phi); boolean[] ccw = new boolean[n]; ArrayList pts = new ArrayList(); for(int i = 0; i < n; i++) { ccw[i] = (l[i].relativeCCW(v[i].x + sx, v[i].y + sy) < 0); } for(int i = 0; i < n; i++) { double dx = ccw[i] ? (sx * sl) : 0.0; double dy = ccw[i] ? (sy * sl) : 0.0; pts.add(new MyPoint(v[i].x - dx, v[i].y - dy)); int j = (i + 1) % n; if(ccw[i] != ccw[j]) { pts.add(new MyPoint(v[j].x - dx, v[j].y - dy)); } } MyPoint[] tmp = new MyPoint[pts.size()]; pts.toArray(tmp); return new MyPolygon(tmp); } } private static class DataSet { private double tha; private double phi; private MyPoint src; private MyPoint dst; private Building [] bldgs; private MyLine [] roads; private MyPolygon[] shades; private MyPoint [] points; private double [][] adj; private DataSet() { } public static DataSet scan(Scanner in) { int n = in.nextInt(); int m = in.nextInt(); if(n == 0 && m == 0) { return null; } DataSet ds = new DataSet(); ds.bldgs = new Building[n]; ds.roads = new MyLine [m]; for(int i = 0; i < n; i++) { int nv = in.nextInt(); double ht = in.nextInt(); MyPoint[] v = new MyPoint[nv]; for(int j = 0; j < nv; j++) { v[j] = new MyPoint(in.nextInt(), in.nextInt()); } ds.bldgs[i] = new Building(v, ht); } for(int i = 0; i < m; i++) { ds.roads[i] = new MyLine (in.nextInt(), in.nextInt(), in.nextInt(), in.nextInt()); } ds.tha = in.nextInt() * Math.PI / 180.0; ds.phi = in.nextInt() * Math.PI / 180.0; ds.src = new MyPoint(in.nextInt(), in.nextInt()); ds.dst = new MyPoint(in.nextInt(), in.nextInt()); return ds; } private void makeShades() { int n = bldgs.length; shades = new MyPolygon[n]; for(int i = 0; i < n; i++) { shades[i] = bldgs[i].makeShade(tha, phi); } } private void makePoints() { int n = bldgs.length; int m = roads.length; ArrayList list = new ArrayList(); list.add(src); list.add(dst); for(int i = 0; i < m; i++) { for(int j = i + 1; j < m; j++) { MyPoint p = roads[i].intersectsAt(roads[j]); if(p != null) { list.add(p); } } } for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { for(int k = 0; k < shades[j].n; k++) { MyPoint p = roads[i].intersectsAt(shades[j].l[k]); if(p != null) { list.add(p); } } } } points = new MyPoint[list.size()]; list.toArray(points); } private void makeMatrix() { int n = points.length; int m = roads .length; Comparator comp = new Comparator() { // compare by x then y public int compare(Integer oi, Integer oj) { int i = oi; int j = oj; if(points[i].x - points[j].x > EPS) { return +1; } if(points[j].x - points[i].x > EPS) { return -1; } if(points[i].y - points[j].y > EPS) { return +1; } if(points[j].y - points[i].y > EPS) { return -1; } return 0; } }; adj = new double[n][n]; for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { adj[i][j] = (i == j) ? 0.0 : Double.POSITIVE_INFINITY; } } ArrayList list = new ArrayList(); for(int i = 0; i < m; i++) { list.clear(); for(int j = 0; j < n; j++) { if(roads[i].ptSegDistSq(points[j]) < EPS) { list.add(j); } } Collections.sort(list, comp); for(int j = 1; j < list.size(); j++) { int u = list.get(j - 1); int v = list.get(j - 0); MyPoint pu = points[u]; MyPoint pv = points[v]; MyPoint pm = MyPoint.center(pu, pv); boolean inShade = false; for(int k = 0; k < shades.length; k++) { if(shades[k].contains(pm)) { inShade = true; break; } } if(inShade) { adj[u][v] = adj[v][u] = 0.0; } else { adj[u][v] = adj[v][u] = pu.distance(pv); } } } } private double dijkstra(int s, int t) { int n = points.length; double [] dis = new double [n]; boolean[] vis = new boolean[n]; Arrays.fill(dis, Double.POSITIVE_INFINITY); Arrays.fill(vis, false); dis[s] = 0.0; while(true) { int j = -1; for(int i = 0; i < n; i++) { if(!vis[i] && (j == -1 || dis[i] < dis[j])) { j = i; } } if(j == t || j == -1) { break; } vis[j] = true; for(int i = 0; i < n; i++) { dis[i] = Math.min(dis[i], dis[j] + adj[j][i]); } } return dis[t]; } public double solve() { makeShades(); makePoints(); makeMatrix(); return dijkstra(0, 1); } } }