#include #include #include #include #include #include using namespace std; typedef complex cd; typedef pair line; #define DELTA 1e-8 #define INF 1e+8 #define ENOUGH_LONG 1e+6 #define NON_CROSS_POINT (cd(INF, INF)) bool isOnLine(line l, cd target) { cd p = l.first; cd v = l.second - l.first; cd temp = (target - p) / v; return abs(imag(temp)) < DELTA; } bool isOnLineSegment(line l, cd target) { cd p = l.first; cd v = l.second - l.first; cd temp = (target - p) / v; return abs(imag(temp)) < DELTA && 0.0 <= real(temp) && real(temp) <= 1.0; } bool isOverlap(line l1, line l2) { if(isOnLineSegment(l1, l2.first) && isOnLine(l1, l2.second)) return true; if(isOnLineSegment(l1, l2.second) && isOnLine(l1, l2.first)) return true; if(isOnLineSegment(l2, l1.first) && isOnLine(l2, l1.second)) return true; if(isOnLineSegment(l2, l1.second) && isOnLine(l2, l1.first)) return true; return false; } //p1+f1*v1 = p2+f2*v2 //p1-p2+f1*v1 = f2*v2 //(p1-p2)/v1+f1 = f2*v2/v1 cd crossLines(line l1, line l2) { cd p1 = l1.first; cd v1 = l1.second - l1.first; cd p2 = l2.first; cd v2 = l2.second - l2.first; if(abs(imag(v2/v1)) < DELTA) return NON_CROSS_POINT; double f1 = imag((p2-p1)/v2) / imag(v1/v2); double f2 = imag((p1-p2)/v1) / imag(v2/v1); if(f1 < 0.0 || 1.0 < f1 || f2 < 0.0 || 1.0 < f2) return NON_CROSS_POINT; return p1+f1*v1; } line merge(line l1, line l2) { cd p = l1.first; cd v = l1.second - l1.first; double maxFactor = 1.0; double minFactor = 0.0; double factor; factor = real((l2.first - p) / v); maxFactor = max(maxFactor, factor); minFactor = min(minFactor, factor); factor = real((l2.second - p) / v); maxFactor = max(maxFactor, factor); minFactor = min(minFactor, factor); return make_pair(p+minFactor*v, p+maxFactor*v); } void addLine(line &l, list &lst) { list::iterator it = lst.begin(); while(it != lst.end()) { if(isOverlap(*it, l)) { l = merge(*it, l); it = lst.erase(it); } else { it++; } } lst.push_back(l); } list generateNewCandidateShoreLines(vector &shoreLines, double r) { list output; cd e[] = { cd( r, 0), cd( 0, r), cd(-r, 0), cd( 0, -r), cd( r, 0), }; for(vector::iterator it = shoreLines.begin(); it != shoreLines.end(); it++) { for(int j = 0; j < 4; j++) { line l1 = make_pair(it->first + e[j], it->second + e[j]); line l2 = make_pair(it->first + e[j], it->first + e[j+1]); addLine(l1, output); addLine(l2, output); } } return output; } vector separateEachOther(list &lines, vector &shoreLines) { vector output; for(list::iterator it1 = lines.begin(); it1 != lines.end(); it1++) { cd p = it1->first; cd v = it1->second - it1->first; vector factors; factors.push_back(0.0); factors.push_back(1.0); for(list::iterator it2 = lines.begin(); it2 != lines.end(); it2++) { if(it1 == it2) continue; cd c = crossLines(*it1, *it2); if(c == NON_CROSS_POINT) continue; factors.push_back(real((c - p)/v)); } for(vector::iterator it2 = shoreLines.begin(); it2 != shoreLines.end(); it2++) { cd c = crossLines(*it1, *it2); if(c == NON_CROSS_POINT) continue; factors.push_back(real((c - p)/v)); } sort(factors.begin(), factors.end()); for(int i = 1; i < factors.size(); i++) { cd p1 = p + factors[i-1] * v; cd p2 = p + factors[i] * v; if(abs(p1-p2) < DELTA)continue; output.push_back(make_pair(p1, p2)); } } return output; } vector makeShoreLines(int n, const int *x, const int *y) { vector output; for(int i = 0; i < n; i++) { output.push_back(make_pair(cd(x[i], y[i]), cd(x[(i+1)%n], y[(i+1)%n]))); } return output; } bool innerPoint(cd p, vector &lines) { while(true) { double rad = 2.0*M_PI * (double)rand() / RAND_MAX; cd target = p + polar(ENOUGH_LONG, rad); line l = make_pair(p, target); int counter = 0; bool conflict = false; for(vector::iterator it = lines.begin(); it != lines.end(); it++) { if(isOnLineSegment(l, it->first) || isOnLineSegment(l, it->second)) { conflict = true; break; } if(crossLines(*it, l) != NON_CROSS_POINT) { counter++; } } if(conflict) continue; return counter % 2 == 1; } } double distanceManhattan(cd p1, cd p2) { cd d = p1 - p2; return abs(real(d)) + abs(imag(d)); } double distanceManhattan(line l, cd p) { double output = min(distanceManhattan(l.first, p), distanceManhattan(l.second, p)); cd c1 = crossLines(l, make_pair(p+ENOUGH_LONG*cd(1, 0), p+ENOUGH_LONG*cd(-1, 0))); if(c1 != NON_CROSS_POINT) { output = min(output, abs(c1 - p)); } cd c2 = crossLines(l, make_pair(p+ENOUGH_LONG*cd(0, 1), p+ENOUGH_LONG*cd(0, -1))); if(c2 != NON_CROSS_POINT) { output = min(output, abs(c2 - p)); } return output; } double distanceFromShoreLine(cd p, vector &shoreLines) { double output = INF; for(vector::iterator it = shoreLines.begin(); it != shoreLines.end(); it++) { output = min(output, distanceManhattan(*it, p)); } return output; } bool isOnNewShoreLine(cd p, vector &shoreLines, double r) { return innerPoint(p, shoreLines) && distanceFromShoreLine(p, shoreLines) > r - DELTA; } double calculateNewShoreLineLength(vector separatedLines, vector shoreLines, double r) { double sum = 0.0; for(vector::iterator it = separatedLines.begin(); it != separatedLines.end(); it++) { cd mid = 0.5*(it->first + it->second); if(isOnNewShoreLine(mid, shoreLines, r)) { sum += abs(it->first - it->second); } } return sum; } double solve(int n, double r, const int *x, const int *y) { vector shoreLines = makeShoreLines(n, x, y); list candidateShoreLines = generateNewCandidateShoreLines(shoreLines, r); vector separatedShoreLines = separateEachOther(candidateShoreLines, shoreLines); return calculateNewShoreLineLength(separatedShoreLines, shoreLines, r); } int main(void) { while(true) { int n; cin >> n; if(n == 0)break; double r; cin >> r; cd p[n]; int x[n]; int y[n]; for(int i = 0; i < n; i++) { cin >> x[i] >> y[i]; } printf("%.10f\r\n", solve(n, r, x, y)); } }