#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
struct point {
int x, y, index;
bool joined, isfault;
point() {}
point(int a, int b) {
x = a, y = b;
}
bool operator < (point other) {
return y < other.y || (y == other.y && x < other.x);
}
bool onSegment(point a, point b) {
if (ccw(a, b) != 0) {
return false;
}
int minx = min(a.x, b.x);
int maxx = max(a.x, b.x);
int miny = min(a.y, b.y);
int maxy = max(a.y, b.y);
return minx <= x && x <= maxx && miny <= y && y <= maxy;
}
int updown() {
if (y < 0 || (y == 0 && x > 0)) {
return 0;
}
return 1;
}
int ccw(point a, point b) {
ll c = (ll)x * (a.y - b.y) + (ll)a.x * (b.y - y) + (ll)b.x * (y - a.y);
if (c == 0) {
return 0;
}
if (c > 0) {
return 1;
}
return - 1;
}
ld dist(point other) {
return hypot(x - other.x, y - other.y);
}
};
point O = point(0, 0);
bool cmp(point a, point b) {
if (a.updown() != b.updown()) {
return a.updown() < b.updown();
}
return (ll)a.y * b.x < (ll)a.x * b.y;
}
vector <point> Build_ConvexHull(vector <point> &p) {
vector <point> ans;
sort(p.begin(), p.end());
bool checking = true;
for (int i = 0; i < p.size(); ++i) {
if (p[0].ccw(p[1], p[i]) != 0) {
checking = false;
break;
}
}
if (checking == true) {
ans = p;
p.clear();
return ans;
}
for (int i = 0; i < p.size(); ++i) {
p[i].index = i;
p[i].joined = false;
}
vector <point> pts = p;
int n = p.size(), sz = 0;
p.resize(n + 1);
for (int i = 1; i < n; ++i) {
if (i == n - 1 || pts[0].ccw(pts[i], pts[n - 1]) >= 0) {
while (sz > 0 && p[sz - 1].ccw(p[sz], pts[i]) < 0) {
sz--;
}
p[++sz] = pts[i];
}
}
if (sz != n - 1) {
for (int i = n - 2, j = sz; i >= 0; --i) {
if (i == 0 || pts[n - 1].ccw(pts[i], pts[0]) >= 0) {
while (sz > j && p[sz - 1].ccw(p[sz], pts[i]) < 0) {
sz--;
}
p[++sz] = pts[i];
}
}
p.resize(sz);
}
else {
p.resize(sz + 1);
}
for (int i = 0; i < p.size(); ++i) {
pts[p[i].index].joined = true;
}
ans = p;
p.clear();
for (auto i : pts) {
if (i.joined == false) {
p.push_back(i);
}
}
return ans;
}
int main() {
ios_base :: sync_with_stdio(false); cin.tie(0); cout.tie(0);
if (fopen("test.inp", "r")) {
freopen("test.inp", "r", stdin);
freopen("test.out", "w", stdout);
}
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector <point> p(n);
for (int i = 0; i < n; ++i) {
cin >> p[i].x >> p[i].y;
}
vector <point> points = p;
p.push_back(O);
ld ans = 0;
vector <vector <point>> pp(2);
pp[0] = Build_ConvexHull(p);
p.push_back(O);
pp[1] = Build_ConvexHull(p);
if (pp[0].size() + pp[1].size() == n + 2) {
bool checking = true;
for (int i = 0; i < 2; ++i) {
if (pp[i].size() < 3) {
checking = false;
break;
}
bool contain = false;
for (int j = 0; j < pp[i].size(); ++j) {
if (pp[i][j].x == 0 && pp[i][j].y == 0) {
contain = true;
}
int pre = (j - 1 + pp[i].size()) % pp[i].size();
int nxt = (j + 1) % pp[i].size();
if (pp[i][pre].ccw(pp[i][j], pp[i][nxt]) == 0) {
checking = false;
break;
}
}
if (contain == false) {
checking = false;
}
if (checking == false) {
break;
}
}
if (checking == true) {
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < pp[i].size(); ++j) {
int nxt = (j + 1) % pp[i].size();
ans += pp[i][j].dist(pp[i][nxt]);
}
}
}
}
p = points;
sort(p.begin(), p.end(), cmp);
int pos = - 1;
bool checking = true;
for (int i = 0; i < n; ++i) {
int nxt = (i + 1) % n;
if (p[i].onSegment(O, p[nxt]) || p[nxt].onSegment(O, p[i])) {
checking = false;
break;
}
}
if (checking == true) {
for (int i = 0; i < n; ++i) {
int pre = (i - 1 + n) % n;
int nxt = (i + 1) % n;
if (p[pre].ccw(p[i], p[nxt]) < 0 || p[i].onSegment(p[pre], p[nxt])) {
p[i].isfault = true;
}
else {
p[i].isfault = false;
}
p[i].index = i;
}
vector <deque <point>> pts(2);
vector <ld> len(2, 0);
vector <int> fault(2);
vector <bool> status(2, true);
pts[0].push_back(p[0]);
for (int i = 1; i < n; ++i) {
if (p[0].ccw(O, p[i]) < 0) {
len[0] += pts[0].back().dist(p[i]);
if (pts[0].size() >= 2 && pts[0].back().isfault == true) {
status[0] = false;
fault[0] = pts[0].back().index;
}
pts[0].push_back(p[i]);
}
else {
if (pts[1].size()) {
len[1] += pts[1].back().dist(p[i]);
}
if (pts[1].size() >= 2 && pts[1].back().isfault == true) {
status[1] = false;
fault[1] = pts[1].back().index;
}
pts[1].push_back(p[i]);
}
}
if ((status[0] && pts[0].size() >= 2 && O.ccw(pts[0].front(), pts[0].back()) > 0) && (status[1] && pts[1].size() >= 2 && O.ccw(pts[1].front(), pts[1].back()) > 0)) {
ans = max(ans, len[0] + O.dist(pts[0].front()) + O.dist(pts[0].back()) + len[1] + O.dist(pts[1].front()) + O.dist(pts[1].back()));
}
for (int i = 1; i < n; ++i) {
point curr = pts[0].front();
if (pts[1].size()) {
len[1] += pts[1].back().dist(curr);
}
if (pts[1].size() >= 2 && pts[1].back().isfault == true) {
status[1] = false;
fault[1] = pts[1].back().index;
}
pts[1].push_back(curr);
pts[0].pop_front();
if (pts[0].size()) {
len[0] -= pts[0].front().dist(curr);
if (status[0] == false) {
if (pts[0].front().isfault == true && pts[0].front().index == fault[0]) {
status[0] = true;
}
}
}
else {
pts[0].push_back(p[i]);
point curr = pts[1].front();
pts[1].pop_front();
if (pts[1].size()) {
len[1] -= pts[1].front().dist(curr);
if (status[1] == false) {
if (pts[1].front().isfault == true && pts[1].front().index == fault[1]) {
status[1] = true;
}
}
}
}
while (pts[1].size() > 0 && p[i].ccw(O, pts[1].front()) < 0) {
curr = pts[1].front();
len[0] += pts[0].back().dist(curr);
if (pts[0].size() >= 2 && pts[0].back().isfault == true) {
status[0] = false;
fault[0] = pts[0].back().index;
}
pts[0].push_back(curr);
pts[1].pop_front();
if (pts[1].size()) {
len[1] -= pts[1].front().dist(curr);
if (status[1] == false) {
if (pts[1].front().isfault == true && pts[1].front().index == fault[1]) {
status[1] = true;
}
}
}
}
if ((status[0] && pts[0].size() >= 2 && O.ccw(pts[0].front(), pts[0].back()) > 0) && (status[1] && pts[1].size() >= 2 && O.ccw(pts[1].front(), pts[1].back()) > 0)) {
ans = max(ans, len[0] + O.dist(pts[0].front()) + O.dist(pts[0].back()) + len[1] + O.dist(pts[1].front()) + O.dist(pts[1].back()));
}
}
}
cout << fixed << setprecision(10) << ans << "\n";
}
}