#include<iostream>
#include<complex>
#include<vector>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<map>
#include<cassert>

using namespace std;

#define rep(i, n) for (int i = 0; i < int(n); ++i)

#define X real()
#define Y imag()

typedef long double D;
typedef complex<D> P;
typedef pair<P, P> L;
typedef vector<P> Pol;

const D INF = 1e40;
const D EPS = 1e-10;
const D PI = acos(-1);

int sig(D r) {return (r < -EPS) ? -1 : (r > EPS) ? 1 : 0;}
bool eq(D a, D b) {return abs(a - b) < EPS;}
bool near(P a, P b) {return abs(a - b) < EPS;}

// テ・ツ??ァツゥツ?
D dot(P a, P b) {return a.X * b.X + a.Y * b.Y;}
// テ・ツ、ツ姪ァツゥツ?
D det(P a, P b) {return a.X * b.Y - a.Y * b.X;}

// テァツキツ堙・ツ按?」ツ?ョテ」ツδ凖」ツつッテ」ツδ暗」ツδォ
P vec(L a) {return a.second - a.first;}

// テァツキツ堙・ツ按?bテ」ツ?ォテ・ツッツセテ」ツ?凖」ツつ凝ァツつケxテ」ツ?ョテ、ツスツ催ァツスツョ
enum CCW{FRONT = 1, RIGHT = 2, BACK = 4, LEFT = 8, ON = 16};
int ccw(L s, P p) {
  P a = vec(s);
  p -= s.first;
  D cr = det(a, p);
  if (eq(cr, 0)) {
    if (sig(dot(a, p)) < 0) return BACK;
    if (sig(norm(a) - norm(p)) < 0) return FRONT;
    return ON;
  }
  return (cr > 0) ? LEFT : RIGHT;
}

// ティツァツ津・ツコツヲ
D ang(P p) {D theta = arg(p); return sig(theta - PI) < 0 ? theta : -PI;}
// テヲツ慊嘉・ツ青妥ィツァツ津・ツコツヲ
D ang(P base, P a, P b) {return ang((b - base) / (a - base));}

// テ・ツーツ?・ツスツア
P proj(P a, P b) {return a * dot(a, b) / norm(a);}
P perp(L l, P p) {return l.first + proj(vec(l), p - l.first);}
P refl(L l, P p) {return perp(l, p) * (D)2 - p;}

// テ、ツコツ、テ・ツキツョテ・ツ按、テ・ツョツ?
bool iLL(L a, L b) {return !eq(det(vec(a), vec(b)), 0);}
bool eqL(L a, L b) {return !iLL(a, b) && eq(det(vec(a), b.first - a.first), 0);}
bool iLS(L a, L b) {return sig(det(vec(a), b.first - a.first)) * sig(det(vec(a), b.second - a.first)) <= 0;}
bool iLSs(L a, L b) {return sig(det(vec(a), b.first - a.first)) * sig(det(vec(a), b.second - a.first)) < 0;}
bool iSS(L a, L b) {
  int cwa = ccw(a, b.first) | ccw(a, b.second);
  int cwb = ccw(b, a.first) | ccw(b, a.second);
  return ((cwa | cwb) & ON) || ((cwa & cwb) == (LEFT | RIGHT));
}
bool iSSs(L a, L b) {return ((ccw(a, b.first) | ccw(a, b.second)) & (ccw(b, a.first) | ccw(b, a.second))) == (LEFT | RIGHT);}

// テ、ツコツ、テァツつケ
P pLL(L a, L b) {return a.first + vec(a) * (det(vec(b), b.first - a.first) / det(vec(b), vec(a)));}

// ティツキツ敕ゥツ崢「
D dLP(L l, P x) {return abs(det(vec(l), x - l.first)) / abs(vec(l));}
D dSP(L s, P x) {
  if (sig(dot(vec(s), x - s.first)) <= 0) return abs(x - s.first);
  if (sig(dot(-vec(s), x - s.second)) <= 0) return abs(x - s.second);
  return dLP(s, x);
}
D dLL(L a, L b) {return iLL(a, b) ? 0 : dLP(a, b.first);}
D dLS(L a, L b) {return iLS(a, b) ? 0 : min(dLP(a, b.first), dLP(a, b.second));}
D dSS(L a, L b) {return iSS(a, b) ? 0 : min(min(dSP(a, b.first), dSP(a, b.second)), min(dSP(b, a.first), dSP(b, a.second)));}

// テヲツッツ氾ィツシツεゥツ鳴「テヲツ閉ー
namespace std {
  bool operator<(P a, P b) {return eq(a.X, b.X) ? a.Y < b.Y : a.X < b.X;}
}
L sortBase;
bool lessArg(P a, P b) {
  D ang1 = ang(sortBase.first, sortBase.second, a);
  D ang2 = ang(sortBase.first, sortBase.second, b);
  return eq(ang1, ang2) ? norm(a) > norm(b) : ang1 < ang2;
}

// テ・ツ??
struct C{
  P c; D r;
  C() {}
  C(P c, D r) : c(c), r(r) {}
};

// 2テ・ツ??」ツ?ョテ、ツスツ催ァツスツョテゥツ鳴「テ、ツソツ?
enum RELATION{SAME = 1, CONTAIN = 2, OVER = 4, NO_CROSS = 8, ONE_CROSS = 16, ONE_CONTAIN_CROSS = 32, ONE_OVER_CROSS = 64, TWO_CROSS = 128};
int cRel(C c1, C c2) {
  D d = abs(c1.c - c2.c);
  if (near(c1.c, c2.c) && eq(c1.r, c2.r)) return SAME;
  if (sig(d - (c1.r - c2.r)) < 0) return OVER;
  if (sig(d - (c2.r - c1.r)) < 0) return CONTAIN;
  if (eq(d, c1.r - c2.r)) return ONE_OVER_CROSS;
  if (eq(d, c2.r - c1.r)) return ONE_CONTAIN_CROSS;
  if (eq(d, c1.r + c2.r)) return ONE_CROSS;
  if (sig(d - (c1.r + c2.r)) > 0) return NO_CROSS;
  return TWO_CROSS;
}

// テァツつケテ」ツ?古・ツ??」ツ?ォテ・ツ青ォテ」ツ?セテ」ツつ古」ツつ凝」ツ??
bool iCP(C c, P p) {return sig(abs(p - c.c) - c.r) <= 0;}
// テ、ツコツ、テ・ツキツョテ・ツ按、テ・ツョツ?
bool iCL(C c, L l) {return sig(c.r - dLP(l, c.c)) >= 0;}
// テ・ツ??」ツ?ィテ、ツコツ、テ・ツキツョテ」ツ?崚」ツ?堙・ツョツ古・ツ?ィテ」ツ?ォテ・ツ青ォテ」ツ?セテ」ツつ古」ツ?ヲテ」ツつづィツ可ッテ」ツ??・ツ?エテ・ツ青暗」ツ?ッ&&テ、ツサツ・テゥツ卍催」ツつ津・ツ可甘ゥツ卍、
bool iCS(C c, L s) {return iCL(c, s) && sig(c.r - max(abs(s.first - c.c), abs(s.second - c.c))) <= 0;}
bool iCC(C a, C b) {return sig(abs(a.c - b.c) - abs(a.r - b.r) >= 0) && sig(abs(a.c - b.c) - a.r - b.r) <= 0;}

// テ、ツコツ、テァツつケ
pair<P, P> pCC(C a, C b) {
  D x = (norm(a.c - b.c) + a.r * a.r - b.r * b.r) / (2 * abs(a.c - b.c));
  P e = (b.c - a.c) / abs(b.c - a.c);
  P y = e * P(0, sqrt(max(a.r * a.r - x * x, (D)0)));
  return make_pair(a.c + e * x - y, a.c + e * x + y);
}
pair<P, P> pCL(C c, L l) {
  P x = perp(l, c.c);
  P y = vec(l) / abs(vec(l)) * sqrt(max(c.r * c.r - norm(x - c.c), (D)0));
  return make_pair(x - y, x + y);
}

// ティツァツ津」ツ?ョテ・ツ??・ツ、ツ姪・ツ按、テ・ツョツ?ティツァツ誕bテ」ツ?ョテ・ツ??ゥツδィテ」ツ?ォテ」ツ?づ」ツつ古」ツ?ーテヲツュツ」テ」ツ??ィツセツコテ、ツクツ甘」ツ?ッ0テ」ツ??・ツ、ツ姪ゥツδィテ」ツ?ッティツイツ?
int sAP(P a, P b, P c) {return sig(det(a, c)) - sig(det(b, c)) - sig(det(a, b));}

// テ・ツ、ツ堙ィツァツ津・ツスツ「テ」ツ?ョテゥツ敖「テァツゥツ?
D aPol(Pol vp) {
  D ret = 0;
  rep (i, vp.size()) ret += det(vp[i], vp[(i + 1) % vp.size()]);
  return abs(ret / 2);
}

// テ、ツクツ嘉ィツァツ津・ツスツ「テ」ツ?ョテゥツ敖「テァツゥツ?
D aTri(D a, D b, D c){
  D s = (a + b + c) / 2;
  return sqrt(max(s * (s - a) * (s - b) * (s - c), (D)0));
}

// テ・ツ、ツ堙ィツァツ津・ツスツ「テ」ツ?ョテ・ツ??・ツ、ツ姪・ツ按、テ・ツョツ?テ・ツ??ゥツδィ:1テ」ツ??・ツ堕ィテ、ツクツ?0テ」ツ??・ツ、ツ姪ゥツδィ:-1
int sGP(Pol pol, P p) {
  int side = -1;
  rep (i, pol.size()) {
    P p0 = pol[i] - p, p1 = pol[(i + 1) % pol.size()] - p;
    if (sig(det(p0, p1)) == 0 && sig(dot(p0, p1)) <= 0) return 0;
    if (p0.Y > p1.Y) swap(p0, p1);
    if (sig(p0.Y) <= 0 && 0 < sig(p1.Y) && sig(det(p0, p1)) > 0) side *= -1;
  }
  return side;
}

// テ・ツ?クテ・ツ個?
Pol convexHull(Pol p) {
  int m = 0;
  vector<P> q(p.size() * 2);
  sort(p.begin(), p.end());
  for (int i = 0; i < int(p.size()); q[m++] = p[i++]) for (; m > 1 && sig(det(q[m - 1] - q[m - 2], p[i] - q[m - 2])) <= 0; --m);
  for (int i = p.size() - 2, r = m; i >= 0; q[m++] = p[i--]) for (; m > r && sig(det(q[m - 1] - q[m - 2], p[i] - q[m - 2])) <= 0; --m);
  q.resize(m - 1);
  return q;
}

// テ・ツ?クテ・ツ個?」ツつォテ」ツδε」ツδ?
Pol convexCut(Pol p, L l) {
  vector<P> q;
  rep (i, p.size()) {
    if (ccw(l, p[i]) & (LEFT | BACK | ON | FRONT)) q.push_back(p[i]);
    if (iLSs(l, L(p[i], p[(i + 1) % p.size()]))) q.push_back(pLL(l, L(p[i], p[(i + 1) % p.size()])));
  }
  return q;
}

// テァツキツ堙・ツ按?」ツつ津」ツδ榲」ツδシテ」ツつクテ」ツ?凖」ツつ?
vector<L> merge(vector<L> s) {
  rep (i, s.size()) if (s[i].second < s[i].first) swap(s[i].first, s[i].second);
  sort(s.begin(), s.end());
  rep (i, s.size()) rep (j, i) if (iSS(s[i], s[j]) && !iLL(s[i], s[j])) {
    s[j].second = max(s[i].second, s[j].second);
    s.erase(s.begin() + i--);
    break;
  }
  return s;
}

// テァツキツ堙・ツ按?」ツつ「テ」ツδャテ」ツδウテ」ツつクテ」ツδ。テ」ツδウテ」ツδ?テゥツ堋」テ」ツ?ョテァツつケテ」ツ?クテ」ツ?ョティツセツコテ」ツ?ョテ」ツ?ソテ」ツつ津ヲツ個?」ツ?、
pair<vector<P>, vector<vector<int> > > sArr(vector<L> s) {
  s = merge(s);
  vector<P> vp;
  rep (i, s.size()) {
    vp.push_back(s[i].first);
    vp.push_back(s[i].second);
  }
  rep (i, s.size()) rep (j, i) if (iSS(s[i], s[j])) vp.push_back(pLL(s[i], s[j]));
  sort(vp.begin(), vp.end());
  vp.erase(unique(vp.begin(), vp.end(), near), vp.end());
  vector<vector<int> > g(vp.size());
  rep (i, s.size()) {
    vector<pair<D, int> > v;
    rep (j, vp.size()) if (ccw(s[i], vp[j]) == ON) v.push_back(make_pair(norm(vp[j] - s[i].first), j));
    sort(v.begin(), v.end());
    rep (j, v.size() - 1) {
      g[v[j + 1].second].push_back(v[j].second);
      g[v[j].second].push_back(v[j + 1].second);
    }
  }
  return make_pair(vp, g);
}

// テ、ツコツ古・ツ??」ツ?ョテ・ツ?アテゥツ?堙ヲツ篠・テァツキツ?
vector<L> tCC(C c1, C c2) {
  vector<L> res;
  pair<P, P> pcross1, pcross2;
  D d2 = norm(c2.c - c1.c);

  int rel = cRel(c1, c2);
  if (rel & (SAME | CONTAIN | OVER)) return res;
  
  if (rel & (ONE_CONTAIN_CROSS | ONE_OVER_CROSS | ONE_CROSS)) return res;

  //external
  pcross1 = pCC(C(c2.c, sqrt(d2 - (c2.r - c1.r) * (c2.r - c1.r) + c2.r * c2.r)), c1);
  pcross2 = pCC(C(c1.c, sqrt(d2 - (c2.r - c1.r) * (c2.r - c1.r) + c1.r * c1.r)), c2);
  res.push_back(L(pcross1.second, pcross2.first));
  res.push_back(L(pcross1.first, pcross2.second));
  if (rel & TWO_CROSS) return res;

  //internal
  P In((c2.r * c1.c + c1.r * c2.c) / (c1.r + c2.r));
  pcross1 = pCC(C(In, sqrt(norm(c1.c - In) - c1.r * c1.r)), c1);
  pcross2 = pCC(C(In, sqrt(norm(c2.c - In) - c2.r * c2.r)), c2);
  res.push_back(L(pcross1.first, pcross2.first));
  res.push_back(L(pcross1.second, pcross2.second));
  return res;
}

// テヲツ慊?ァツオツづゥツ伉イティツ。ツ崚・ツ閉湘ゥツ。ツ古ァツ板ィテァツァツ佚・ツッツ?・ツ?オテ・ツ卍ィ
// テ・ツ青古、ツクツ?」ツ?ョテ・ツ??」ツ?ッテ」ツ?セテ」ツ?ィテ」ツつ?」ツ?ヲテ」ツ?甘」ツ?湘」ツ?禿」ツ?ィ
pair<vector<P>, vector<vector<pair<int, int> > > > scArr(vector<L> s, vector<C> c, vector<pair<D, D> > a) {
  s = merge(s);
  vector<P> vp;
  rep (i, s.size()) {
    vp.push_back(s[i].first);
    vp.push_back(s[i].second);
  }
  //rep (i, s.size()) rep (j, i) if (iSS(s[i], s[j])) vp.push_back(pLL(s[i], s[j]));
  rep (i, c.size()) {
    vp.push_back(c[i].c + c[i].r);
    vp.push_back(c[i].c - c[i].r);
    vp.push_back(c[i].c + P(0, c[i].r));
    vp.push_back(c[i].c - P(0, c[i].r));
  }
  rep (i, c.size()) {
    vp.push_back(c[i].c + polar(c[i].r, a[i].first));
    vp.push_back(c[i].c + polar(c[i].r, a[i].second));
  }
  /*
  rep (i, c.size()) rep (j, i) if (iCC(c[i], c[j])) {
    pair<P, P> cc = pCC(c[i], c[j]);
    vp.push_back(cc.first);
    vp.push_back(cc.second);
  }
  rep (i, c.size()) rep (j, s.size()) if (iCS(c[i], s[j])) {
    pair<P, P> cs = pCL(c[i], s[j]);
    if (ccw(s[j], cs.first) == ON) vp.push_back(cs.first);
    if (ccw(s[j], cs.second) == ON) vp.push_back(cs.second);
  }
  */
  sort(vp.begin(), vp.end());
  vp.erase(unique(vp.begin(), vp.end(), near), vp.end());
  vector<vector<pair<int, int> > > g(vp.size());
  rep (i, s.size()) {
    vector<pair<D, int> > v;
    rep (j, vp.size()) if (ccw(s[i], vp[j]) == ON) v.push_back(make_pair(norm(vp[j] - s[i].first), j));
    sort(v.begin(), v.end());
    rep (j, v.size() - 1) {
      g[v[j + 1].second].push_back(make_pair(v[j].second, -1));
      g[v[j].second].push_back(make_pair(v[j + 1].second, -1));
    }
  }
  rep (i, c.size()) {
    vector<pair<D, int> > v;
    rep (j, vp.size()) if (eq(c[i].r, abs(c[i].c - vp[j])) && sAP(polar((D)1, a[i].first), polar((D)1, a[i].second), vp[j] - c[i].c) >= 0) v.push_back(make_pair(ang(vp[j] - c[i].c), j));
    sort(v.begin(), v.end());
    rep (j, v.size()) if (!near(vp[v[j].second], c[i].c + polar(c[i].r, a[i].second))) {
      // テヲツ卍づィツィツ暗・ツ崢榲」ツつ?
      g[v[(j + 1) % v.size()].second].push_back(make_pair(v[j].second, i));
      // テ・ツ渉催ヲツ卍づィツィツ暗・ツ崢榲」ツつ?
      g[v[j].second].push_back(make_pair(v[(j + 1) % v.size()].second, i));
    }
  }
  return make_pair(vp, g);
}

typedef pair<D, pair<int, P> > Status;

int main() {
  int n;
  cin >> n;
  vector<L> vs(n);
  rep (i, n) cin >> vs[i].first.X >> vs[i].first.Y >> vs[i].second.X >> vs[i].second.Y;
  vector<C> vc(n);
  vector<pair<D, D> > va(n);
  rep (i, n) {
    P c;
    L l1 = L(vec(vs[i]) * P(0, 1) + vs[i].second, vs[i].second);
    L l2 = L(vec(vs[(i + 1) % n]) * P(0, 1) + vs[(i + 1) % n].first, vs[(i + 1) % n].first);
    if (iLL(l1, l2)) c = pLL(l1, l2);
    else c = (vs[i].second + vs[(i + 1) % n].first) / (D)2;
    vc[i] = C(c, abs(c - vs[i].second));
    va[i].first = ang(vs[i].second - c);
    va[i].second = ang(vs[(i + 1) % n].first - c);
    if (ccw(vs[i], vs[(i + 1) % n].first) == RIGHT) swap(va[i].first, va[i].second);
  }
  rep (i, n) rep (j, i) {
    vector<L> vt = tCC(vc[i], vc[j]);
    rep (k, vt.size()) {
      if (sAP(polar((D)1, va[i].first), polar((D)1, va[i].second), vt[k].first - vc[i].c) < 0) continue;
      if (sAP(polar((D)1, va[j].first), polar((D)1, va[j].second), vt[k].second - vc[j].c) < 0) continue;
      vs.push_back(vt[k]);
    }
  }
  pair<vector<P>, vector<vector<pair<int, int> > > > arr = scArr(vs, vc, va);
  vector<P> vp = arr.first;
  vector<vector<pair<int, int> > > edge = arr.second;
  priority_queue<Status, vector<Status>, greater<Status> > que;
  int startI = -1;
  rep (i, vp.size()) if (near(vs[0].first, vp[i])) {
    rep (j, edge[i].size()) {
      if (edge[i][j].second == -1) {
	if (ccw(vs[0], vp[edge[i][j].first]) == ON) {
	  Status status;
	  status.first = abs(vp[edge[i][j].first] - vs[0].first);
	  status.second.first = edge[i][j].first;
	  status.second.second = vs[0].first;
	  que.push(status);
	}
      } else {
	L l(vc[edge[i][j].second].c, vs[0].first);
	if (!iLS(l, L(vs[0].second, vp[edge[i][j].first]))) {
	  Status status;
	  status.first = abs(ang(vc[edge[i][j].second].c, vs[0].first, vp[edge[i][j].first]));
	  status.second.first = edge[i][j].first;
	  if (ccw(vs[0], vp[edge[i][j].first]) == RIGHT) {
	    status.second.second = vp[edge[i][j].first] + (vp[edge[i][j].first] - vc[edge[i][j].second].c) * P(0, 1);
	  } else {
	    status.second.second = vp[edge[i][j].first] + (vp[edge[i][j].first] - vc[edge[i][j].second].c) * P(0, -1);
	  }
	  que.push(status);
	}
      }
    }
    startI = i;
  }
  assert(startI != -1);
  vector<map<int, D> > dis(vp.size());
  while (!que.empty()) {
    Status ppp = que.top();
    int now = ppp.second.first;
    P dir = ppp.second.second;
    que.pop();
    rep (i, edge[now].size()) {
      pair<int, int> pp = edge[now][i];
      if (pp.second == -1) {
	if (ccw(L(dir, vp[now]), vp[pp.first]) != FRONT) continue;
	Status status = ppp;
	status.first += abs(vp[pp.first] - vp[now]);
	status.second.first = pp.first;
	if (dis[pp.first].count(now) > 0 && dis[pp.first][now] < status.first) continue;
	dis[pp.first][now] = status.first;
	que.push(status);
      } else {
	L l = L(vc[pp.second].c, vp[now]);
	if (!iLSs(l, L(vp[pp.first], dir))) continue;
	if (!eq(dot(vp[now] - dir, vp[now] - vc[pp.second].c), 0)) continue;
	D a = abs(ang(vc[pp.second].c, vp[pp.first], vp[now]));
	Status status;
	status.first = ppp.first + a * vc[pp.second].r;
	status.second.first = pp.first;
	if (ccw(L(dir, vp[now]), vp[pp.first]) == RIGHT) {
	  status.second.second = vp[pp.first] + (vp[pp.first] - vc[pp.second].c) * P(0, 1);
	} else {
	  status.second.second = vp[pp.first] + (vp[pp.first] - vc[pp.second].c) * P(0, -1);
	}
	if (dis[pp.first].count(now) > 0 && dis[pp.first][now] < status.first) continue;
	dis[pp.first][now] = status.first;
	que.push(status);
      }
    }
  }
  D res = INF;
  rep (i, vp.size()) rep (j, edge[i].size()) if (edge[i][j].first == startI && dis[startI].count(i) > 0) {
    if (edge[i][j].second == -1) {
      if (ccw(vs[0], vp[i]) == BACK) res = min(res, dis[startI][i]);
    } else {
      if (!iLSs(L(vc[edge[i][j].second].c, vp[startI]), L(vs[0].second, vp[i]))) continue;
      if (!eq(dot(vec(vs[0]), vp[startI] - vc[edge[i][j].second].c), 0)) continue;
      res = min(res, dis[startI][i]);
    }
  }
  assert(res < INF);
  printf("%.12Lf\n", res);
  return 0;
}

Measured memory_bytes: 4160