#include<iostream>
#include<complex>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<map>

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;}

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 arg(P base, P a, P b) {return arg((b - base) / (a - base));}
bool iLL(L a, L b) {return !eq(det(vec(a), vec(b)), 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));
}

P pLL(L a, L b) {return a.first + vec(a) * (det(vec(b), b.first - a.first) / det(vec(b), vec(a)));}

namespace std {
  bool operator<(P a, P b) {return eq(a.X, b.X) ? a.Y < b.Y : a.X < b.X;}
}

struct C{
  P c; D r;
  C() {}
  C(P c, D r) : c(c), r(r) {}
};

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;
}

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);
}

int sAP(P a, P b, P c) {return sig(det(a, c)) - sig(det(b, c)) - sig(det(a, b));}

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;
}

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, 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));
  }
  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(arg(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 = arg(vs[i].second - c);
    va[i].second = arg(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(arg(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;
  }
  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(arg(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]);
    }
  }
  printf("%.12Lf\n", res);
  return 0;
}

Measured memory_bytes: 4148