#include <bits/stdc++.h>
using namespace std;
const int kMaxN = 55;
const double kEps = 1e-7;
typedef pair<double, double> Point;
typedef pair<Point, Point> Segment;
ifstream fin("triangulare.in");
ofstream fout("triangulare.out");
int N;
vector< Point > polygon, triangulation;
bool IsZero(const double& x) {
return fabs(x) < kEps;
}
double Determinant(const Point& a, const Point& b, const Point& c) {
return (b.first - a.first)*(c.second - a.second) - (b.second - a.second)*(c.first - a.first);
}
bool IsInsidePolygon(const Point& p) {
Point q(1000000, rand() % 1000000);
bool isInside = false;
for (int i = 0; i < N; ++i) {
int j = (i + 1) % N;
if (Determinant(p, polygon[i], polygon[j])*Determinant(q, polygon[i], polygon[j]) > 0
&& Determinant(polygon[i], p, q)*Determinant(polygon[j], p, q) < -kEps)
isInside ^= true;
}
return isInside;
}
bool IntersectIntervals(double left1, double right1, double left2, double right2) {
if (left1 > left2) {
swap(left1, left2);
swap(right1, right2);
}
return right1 - left2 > kEps;
}
bool IntersectSegments(const Segment& a, const Segment& b) {
if (IsZero(Determinant(a.first, a.second, b.first)) && IsZero(Determinant(a.first, a.second, b.second))) {
if (IntersectIntervals( min(a.first.first, a.second.first), max(a.first.first, a.second.first),
min(b.first.first, b.second.first), max(b.first.first, b.second.first) )
|| IntersectIntervals( min(a.first.second, a.second.second), max(a.first.second, a.second.second),
min(b.first.second, b.second.second), max(b.first.second, b.second.second) ))
return true;
else
return false;
}
return (Determinant(a.first, a.second, b.first)*Determinant(a.first, a.second, b.second) < -kEps
&& Determinant(b.first, b.second, a.first)*Determinant(b.first, b.second, a.second) < -kEps);
}
bool CheckCut(Segment cutSegment) {
for (int i = 0; i < N; ++i) {
if (IntersectSegments(cutSegment, Segment(polygon[i], polygon[(i + 1) % N])))
return false;
}
for (auto& it : triangulation) {
if (IntersectSegments(cutSegment, Segment(polygon[it.first], polygon[it.second])))
return false;
}
return IsInsidePolygon(Point( (cutSegment.first.first + cutSegment.second.first)/2,
(cutSegment.first.second+ cutSegment.second.second)/2 ));
}
int main() {
srand(time(NULL));
int testCount;
fin >> testCount;
while (testCount--) {
fin >> N;
polygon.resize(N);
for (auto& it : polygon)
fin >> it.first >> it.second;
triangulation.clear();
for (int i = 0; i < N; ++i) {
for (int j = (i + 2) % N; (j + 1) % N != i; j = (j + 1) % N) {
if (CheckCut(Segment(polygon[i], polygon[j])))
triangulation.push_back({ min(i, j), max(i, j) });
}
}
sort(triangulation.begin(), triangulation.end());
for (auto it : triangulation)
fout << it.first << ' ' << it.second << '\n';
}
return 0;
}
//Trust me, I'm the Doctor!