Language: C++

#include<cstdio>
#include<complex>
#include<vector>
#include<cmath>
#include<iostream>
#include<string>
#include<climits>
#include<algorithm>

using namespace std;

//FILE *fp=fopen("ShoreErosion_visu2.htm","w");
FILE *fp=stderr;
typedef long double Real;
#define mnan (nanl)

typedef complex<Real> Point;
typedef complex<Real> Vector;
typedef pair<Point,Point> Segment;
typedef pair<Point,Point> Line;
typedef vector<Point> Polygon;

const Real eps=1e-9;
const Real PI=acos(-1.0);

template<class T> bool eq(T a,T b){
	return abs(a-b)<eps;
}
template<class T> int sgn(T a){
	if(eq(a,(Real)0.0)) return 0;
	if(a>0) return 1;
	return -1;
}

Real arg(Point p){
	return atan2(p.imag(),p.real());
}

Real crP(Vector a,Vector b){
	return (conj(a)*b).imag();
}

Real doP(Vector a,Vector b){
	return (conj(a)*b).real();
}

Point iLL(Line l1,Line l2){
	if(sgn(crP(l1.second-l1.first,l2.second-l2.first))==0) return Point(mnan,mnan);
	Point a=l1.first,b=l1.second;
	Point c=l2.first,d=l2.second;
	Real num=crP(c-a,d-a);
	Real den=crP(b-a,d-c);
	return a+(b-a)*num/den;
}

bool onSeg(Point a,Point b,Point c){
	return eq(abs(a-b),abs(a-c)+abs(c-b));
}

bool isPara(Segment s1,Segment s2){
	return sgn(crP(s1.second-s1.first,s2.second-s2.first))==0;
}

bool cmp_lex(const Point &p1,const Point &p2){
	if(sgn(p1.real()-p2.real())!=0){
		if(p1.real()<p2.real()) return true;
		return false;
	}
	return p1.imag()<p2.imag();
}

bool mergeIfAble(Segment &s,Segment t){
	if(sgn(crP(t.first-s.first,s.second-s.first))!=0) return false;
	if(sgn(crP(t.second-s.first,s.second-s.first))!=0) return false;
/*	Point pts[]={t.first,t.second};
	for(int i=0;i<2;i++){
		if(onSeg(s.first,pts[i],s.second)){
			s.second=pts[i];
		}else if(onSeg(s.second,pts[i],s.first)){
			s.first=pts[i];
		}
	}*/
	if(cmp_lex(s.first,s.second)==false) swap(s.first,s.second);
	if(cmp_lex(t.first,t.second)==false) swap(t.first,t.second);
	Segment res=s;
	if(cmp_lex(res.first,t.first)==false) swap(res,t);
	if(cmp_lex(res.second,t.first)==false){
		if(cmp_lex(res.second,t.second)) res.second=t.second;
		s=res;
		return true;
	}
	return false;
}
void mergeSegments(vector<Segment> &segs){
	for(int i=0;i<segs.size();i++){
		for(int j=i+1;j<segs.size();j++){
			if(mergeIfAble(segs[i],segs[j])){
				segs[j--]=segs.back();
				segs.pop_back();
			}
		}
	}
}

struct Segment2:Segment{
	vector<Point> pts;
	Segment2(){}
	Segment2(Segment s):Segment(s){}
};

vector<Segment> segs;
vector<Segment2> segs2;

Polygon poly;
Real R;

const int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
Vector dir[4];

void put(Segment seg){
	Point p=seg.first,q=seg.second;
	Real dx=abs((p-q).real()),dy=abs((p-q).imag());
	int rem=dx<dy?0:1;
	for(int i=0;i<4;i++){
//		if(i%2!=rem) continue;
		Point p2=p+Point(::dx[i],::dy[i])*R;
		Point q2=q+Point(::dx[i],::dy[i])*R;
		int s=sgn(crP(q-p,q2-q));
//		if(s<0) continue;
		segs.push_back(Segment(p2,q2));
	}
}

void put(Point p){
	for(int i=0;i<4;i++){
		int j=(i+1)%4;
		Point a=p+dir[i]*R;
		Point b=p+dir[j]*R;
		segs.push_back(Segment(a,b));
	}
}

Real mDis(Point a,Point b){
	return abs((a-b).real())+abs((a-b).imag());
}

Real mDis(Segment seg,Point p){
	if(onSeg(seg.first,seg.second,p)) return 0;
	Real res=min(mDis(seg.first,p),mDis(seg.second,p));
	for(int i=0;i<2;i++){
		Point q=p+dir[i];
		if(sgn(crP(q-p,seg.second-seg.first))==0) continue;
		Point r=iLL(Segment(p,q),seg);
		if(onSeg(seg.first,seg.second,r)){
			res=min(res,mDis(p,r));
		}
	}
	return res;
}

bool isin(Polygon poly,Point pt){/*ONは判定していない*/
	bool in=false;
	for(int i=0;i<poly.size();i++){
		Point a=poly[i],b=poly[(i+1)%poly.size()];
		a-=pt,b-=pt;
		if(sgn(a.imag()-b.imag())>0) swap(a,b);
		if(sgn(a.imag())<=0&&0<sgn(b.imag())){
			if(sgn(crP(a,b))<0) in=!in;
		}
	}
	return in;
}

Point center;
bool cmp(const Point &p1,const Point &p2){
	if(sgn(doP(p1-center,p2-center))<0) fprintf(stderr,"direction not correct\n");
	return sgn(abs(p1-center)-abs(p2-center))<0;
}

void showP(Point p){
	printf("(%f,%f) ",p.real(),p.imag());
}

Real solve(){
	for(int i=0;i<4;i++) dir[i]=Vector(dx[i],dy[i]);
	for(int i=0;i<poly.size();i++){
		put(poly[i]);
	}
	for(int i=0;i<poly.size();i++){
		Point p=poly[i];
		Point q=poly[(i+1)%poly.size()];
		put(Segment(p,q));
	}
/*	for(int i=0;i<poly.size();i++){
		Point p=poly[i];
		for(int j=0;j<4;j++){
			Point q=p+dir[j]*R;
			segs.push_back(Segment(p,q));
		}
	}*/
	mergeSegments(segs);
	for(int i=0;i<segs.size();i++){
		segs2.push_back(Segment2(segs[i]));
	}
/*	for(int i=0;i<segs2.size();i++) for(int j=i+1;j<segs2.size();j++){
		Point a=segs2[i].first,b=segs2[i].second;
		Point c=segs2[j].first,d=segs2[j].second;
	//	if(sgn(crP(b-a,d-c))==0&&sgn(crP(c-a,b-a))==0){
	//		showP(a);showP(b);showP(c);showP(d);
	//		printf("\n");
	//	}
	}*/
	for(int i=0;i<segs2.size();i++) for(int j=i+1;j<segs2.size();j++){
		Segment2 &s1=segs2[i],&s2=segs2[j];
		Point p=iLL(s1,s2);
		if(isnan(p.real())) continue;
		if((!onSeg(s1.first,s1.second,p))||(!onSeg(s2.first,s2.second,p))) continue;
		s1.pts.push_back(p);
		s2.pts.push_back(p);
	}
	for(int i=0;i<segs2.size();i++){
		for(int j=0;j<poly.size();j++){
			Segment edge=Segment(poly[j],poly[(j+1)%poly.size()]);
			Point p=iLL(segs2[i],edge);
			if(isnan(p.real())) continue;
			if((!onSeg(segs2[i].first,segs2[i].second,p))||(!onSeg(edge.first,edge.second,p))){
				continue;
			}
			segs2[i].pts.push_back(p);
		}
	}
	for(int i=0;i<segs2.size();i++){
	//	segs2[i].pts.push_back(segs2[i].first);
	//	segs2[i].pts.push_back(segs2[i].second);
		for(int j=0;j<poly.size();j++){
			for(int k=0;k<4;k++){
				Point p=poly[j]+dir[k]*R;
				if(onSeg(segs2[i].first,segs2[i].second,p)){
					segs2[i].pts.push_back(p);
				}
			}
			Point p=poly[j];
			if(onSeg(segs2[i].first,segs2[i].second,p)){
				segs2[i].pts.push_back(poly[j]);
			}
		}
		center=segs2[i].first;
		sort(segs2[i].pts.begin(),segs2[i].pts.end(),cmp);
		if(!eq(segs2[i].pts.back(),segs2[i].second)) fprintf(stderr,"c\n");
	}
	Real res=0;
	for(int i=0;i<segs2.size();i++){
		for(int j=0;j+1<segs2[i].pts.size();j++){
			Point a=segs2[i].pts[j],b=segs2[i].pts[j+1];
			Point mid=(a+b)/(Real)2.0;
			bool in=isin(poly,mid);
			if(!in) continue;
			bool suc=true;
			for(int k=0;k<poly.size();k++){
				Segment s=Segment(poly[k],poly[(k+1)%poly.size()]);
				Real dis=mDis(s,mid);
				if(sgn(dis-R)<0) suc=false;
			}
			if(!suc) continue;
			bool flg[2]={true,true};
			for(int k=0;k<poly.size();k++){
				Real dis1=mDis(a,poly[k]),dis2=mDis(b,poly[k]);
				if(sgn(dis1-R)<0||sgn(dis2-R)<0) fprintf(stderr,"a\n");
				if(eq(dis1,R)&&eq(dis2,R)){
					Point p=poly[k];
					int s=sgn(crP(b-a,p-a));
					int id=s==-1?0:1;
					flg[id]=false;
				}
			}
			for(int k=0;k<poly.size();k++){
				Segment edge=Segment(poly[k],poly[(k+1)%poly.size()]);
				Real dis1=mDis(edge,a);
				Real dis2=mDis(edge,b);
				if(sgn(dis1-R)<0||sgn(dis2-R)<0) fprintf(stderr,"b\n");
				if(isPara(edge,Segment(a,b))==false) continue;
				if(eq(dis1,R)&&eq(dis2,R)){
					Point p=edge.first;
					int s=sgn(crP(b-a,p-a));
					int id=s==-1?0:1;
					flg[id]=false;
				}
			}
			if(flg[0]==false&&flg[1]==false) continue;
			res+=abs(b-a);
//			fprintf(fp,"ctx.moveTo(%f,%f);\n",a.real()*10+600,a.imag()*10+600);
//			fprintf(fp,"ctx.lineTo(%f,%f);\n",b.real()*10+600,b.imag()*10+600);
//			fprintf(fp,"ctx.stroke();\n");
		}
	}
	return res;
}

void init(){
	segs.clear();
	segs2.clear();
	poly.clear();
}

void input(){
	int N;
	scanf("%d%lf",&N,&R);
	if(N==0) exit(0);
	for(int i=0;i<N;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		Point p=Point(x,y);
		poly.push_back(p);
	}
}

int main(){
	for(int i=0;i<4;i++) dir[i]=Vector(dx[i],dy[i]);
	while(true){
		init();
		input();
/*			fprintf(fp,"<html>\n<head>\n<script type=\"text/javascript\">\n");
			fprintf(fp,"function draw(){\n");
			fprintf(fp,"var c=document.getElementById(\"canvas\");\n");
			fprintf(fp,"var ctx=c.getContext(\"2d\");\n");
			fprintf(fp,"ctx.beginPath();\n");*/
			Real ans=solve();
	/*		for(int i=0;i<poly.size();i++){
				fprintf(fp,"ctx.moveTo(%f,%f);\n",poly[i].real()*10+600,poly[i].imag()*10+600);
				fprintf(fp,"ctx.lineTo(%f,%f);\n",poly[(i+1)%poly.size()].real()*10+600,
					poly[(i+1)%poly.size()].imag()*10+600);
				fprintf(fp,"ctx.stroke();\n");
			}*/
			fprintf(fp,"}\n");
			fprintf(fp,"</script></head>\n");
			fprintf(fp,"<body onload=\"draw()\">\n");
			fprintf(fp,"<canvas id=\"canvas\" width=\"2000\" height=\"2000\"></canvas>\n");
			fprintf(fp,"</body></html>\n");
		//	fclose(fp);

	//	Real ans=solve();
		printf("%.10Lf\n",ans);
	}
	return 0;
}

Compiler output:
a.cc: In function 'Point iLL(Line, Line)':
a.cc:48:86: error: no matching function for call to 'std::complex<long double>::complex(long double (&)(const char*) noexcept, long double (&)(const char*) noexcept)'
   48 |         if(sgn(crP(l1.second-l1.first,l2.second-l2.first))==0) return Point(mnan,mnan);
      |                                                                                      ^
In file included from a.cc:2:
/usr/include/c++/14/complex:1695:26: note: candidate: 'constexpr std::complex<long double>::complex(const std::complex<double>&)'
 1695 |       _GLIBCXX_CONSTEXPR complex(const complex<double>& __z)
      |                          ^~~~~~~
/usr/include/c++/14/complex:1695:26: note:   candidate expects 1 argument, 2 provided
/usr/include/c++/14/complex:1692:26: note: candidate: 'constexpr std::complex<long double>::complex(const std::complex<float>&)'
 1692 |       _GLIBCXX_CONSTEXPR complex(const complex<float>& __z)
      |                          ^~~~~~~
/usr/include/c++/14/complex:1692:26: note:   candidate expects 1 argument, 2 provided
/usr/include/c++/14/complex:1683:28: note: candidate: 'constexpr std::complex<long double>::complex(const std::complex<long double>&)'
 1683 |       _GLIBCXX14_CONSTEXPR complex(const complex&) = default;
      |                            ^~~~~~~
/usr/include/c++/14/complex:1683:28: note:   candidate expects 1 argument, 2 provided
/usr/include/c++/14/complex:1671:26: note: candidate: 'constexpr std::complex<long double>::complex(long double, long double)'
 1671 |       _GLIBCXX_CONSTEXPR complex(long double __r = 0.0L,
      |                          ^~~~~~~
/usr/include/c++/14/complex:1671:46: note:   no known conversion for argument 1 from 'long double(const char*) noexcept' to 'long double'
 1671 |       _GLIBCXX_CONSTEXPR complex(long double __r = 0.0L,
      |                                  ~~~~~~~~~~~~^~~~~~~~~~
/usr/include/c++/14/complex:1669:26: note: candidate: 'constexpr std::complex<long double>::complex(_ComplexT)'
 1669 |       _GLIBCXX_CONSTEXPR complex(_ComplexT __z) : _M_value(__z) { }
      |                          ^~~~~~~
/usr/include/c++/14/complex:1669:26: note:   candidate expects 1 argument, 2 provided