Problem:
秋のイルミネーション

四角形が大好きな人が多く住む四角町では、四角形の電光板を組み合わせたイルミネーションで町中を彩るお祭りが開催されます。この電光板は電気を流すと発光し、発光している板に接している板も発光します。したがって、電光板を何枚使っても、すべてがひとかたまりに接していれば電源がひとつで済むという優れものです。

お祭り実行委員会では、四角形を組み合わせたデザインを町民から募集し多数のイルミネーションを作成します。各イルミネーションは、デザインを構成する四角形の配置によって必要となる電源の個数が変わるため、必要な電源の個数を把握する作業に大きな手間がかかります。そこで、あなたは四角形の配置を調べ、必要な電源の個数を計算するプログラムを作成して実行委員会を手助けすることにしました。

イルミネーションの個数、各イルミネーションを構成する四角形の情報を入力とし、イルミネーションごとに必要な電源の個数を出力するプログラムを作成してください。重なっていたり接していたりする四角形を 1 つのまとまりと考え、1 つのまとまりに対して電源の個数は 1 つと数えてください。

Input

複数のデータセットの並びが入力として与えられます。入力の終わりはゼロひとつの行で示されます。各データセットは以下の形式で与えられます。

N
M1
xa1 ya1 xb1 yb1 xc1 yc1 xd1 yd1
xa2 ya2 xb2 yb2 xc2 yc2 xd2 yd2
:
xaM1 yaM1 xbM1 ybM1 xcM1 ycM1 xdM1 ydM1
M2
:
:
MN
:
:

1 行目にイルミネーションの個数 N (1 ≤ N ≤ 100) が与えられます。続いて、N 個のイルミネーションの情報が与えられます。第 i のイルミネーションの情報として、イルミネーションを構成する四角形の個数 Mi (1 ≤ Mi ≤ 100) が１行に与えられます。続く Mi 行に j 個目の四角形の頂点 xaj, yaj, xbj, ybj, xcj, ycj, xdj, ydj (-1000 以上 1000 以下の整数) が与えられます。

入力される四角形の頂点座標は、時計回りの順に従って入力されます。ただし、入力データの四角形はすべて凸な四角形とします。

データセットの数は 10 を超えません。

Output

入力データセットごとに、イルミネーションごとに必要な電源の個数を出力します。出力する電源の個数は各イルミネーションが入力された順番に従ってください。

Sample Input

3
1
0 0 0 1 1 1 1 0
2
0 0 0 1 1 1 1 0
100 100 100 200 200 200 200 100
2
0 0 0 100 100 100 100 0
10 10 10 20 20 20 20 10
2
1
30 40 40 50 40 20 20 10
1
30 40 40 50 40 20 20 10
0

Output for the Sample Input

1
2
1
1
1

Solution in C++ (judge verdict: Wrong Answer)

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
#include <functional>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
using namespace std;

typedef istringstream ISS;
typedef ostringstream OSS;
typedef vector<string> VS;
typedef int INT;
typedef vector<INT> VI;
typedef vector<VI> VVI;
typedef pair <INT, INT> II;
typedef vector <II> VII;

template<class T> ostream& operator << ( ostream& os, vector<T> v ) {
    for ( typename vector<T>::iterator it_i = v.begin(); it_i != v.end(); ++it_i ) {
        os << *it_i << ", ";
    }
    return os;
}


class CPoint;
typedef CPoint CVector2D;
class CSegment;
typedef vector <CSegment> CSegments;
double GetSquare( double );
bool Equal( double, double );
bool LessthanEqual( double, double );
double GetCrossProduct( double, double, double, double );
double GetCrossProduct( CPoint, CPoint );
double GetDotProduct( double, double, double, double );
double GetDotProduct( CPoint, CPoint );
double GetGradientFromTwoPoints( CPoint, CPoint );
int CheckCounterClockWise( CPoint, CPoint, CPoint );
bool Intersect( CPoint, CPoint, CPoint, CPoint );
bool Intersect( CSegment, CSegment );
CPoint GetCrossPoint( CSegment, CSegment );
double GetLength( CPoint, CPoint );
double GetDistance( CPoint, CPoint );
double GetDistance( CSegment, CPoint );
CPoint GetLowestY( CPoint, CPoint );
class CPoint {
public:
    double x, y;
    CPoint( double x, double y ): x(x), y(y) {}
    CPoint(): x(0), y(0) {};
    double getNorm() {
        return x * x + y * y;
    }
    double getAbs() {
        return sqrt( getNorm() );
    }
    CPoint operator + ( CPoint p ) {
        return CPoint( x + p.x, y + p.y );
    }
    CPoint operator - ( CPoint p ) {
        return CPoint( x - p.x, y - p.y );
    }
    CPoint operator * ( double k ) {
        return CPoint( x * k, y * k );
    }
    bool operator < ( const CPoint& p ) const {
        if ( x < p.x ) return true;
        return x == p.x ? y < p.y : false;
    }
};
CPoint operator * ( double k, CPoint p ) {
    return CPoint( p.x * k, p.y * k );
}
ostream& operator << ( ostream& os, CPoint p0 ) {
    os << "(" << p0.x << ", " << p0.y << ")";
    return os;
}
class CSegment {
public:
    CPoint a, b;
    CSegment( int x1, int y1, int x2, int y2 ): a(CPoint( x1, y1 )), b(CPoint( x2, y2 )) {}
    CSegment( CPoint a, CPoint b ): a(a), b(b) {}
    CSegment() {}
    double getGradient() {
        return GetGradientFromTwoPoints( a, b );
    }
    double getLength() {
        return GetLength( a, b );
    }
    double getMinX() {
        return min( a.x, b.x );
    }
    double getMinY() {
        return min( a.y, b.y );
    }
    double getMaxX() {
        return max( a.x, b.x );
    }
    double getMaxY() {
        return max( a.y, b.y );
    }
    bool operator < ( const CSegment& s ) const {
        return b.y > s.b.y;
    }
    
};
ostream& operator << ( ostream& os, CSegment s0 ) {
    os << "(" << s0.a << " - " << s0.b << ")";
    return os;
}
class CCircle {
public:
    CPoint p;
    int r;
    CCircle(): p( 0, 0 ), r(0) {}
    CCircle( int x, int y, int r ): p(x, y), r(r) {}
    CCircle( CPoint p, int r ): p(p), r(r) {}
};
ostream& operator << ( ostream& os, CCircle c0 ) {
    os << "{(" << c0.p.x << ", " << c0.p.y << "), r = " << c0.r << ")";
    return os;
}
class CTriangle {
public:
    CPoint a;
    CPoint b;
    CPoint c;
    CTriangle( int x1, int y1, int x2, int y2, int x3, int y3 ):
        a(CPoint(x1,y1)), b(CPoint(x2,y2)), c(CPoint(x3,y3)) {}
    CTriangle( CPoint a, CPoint b, CPoint c ):
        a(a), b(b), c(c) {}
    CTriangle() {};
    double getArea() {
        CSegment AB( a, b );
        CSegment BC( b, c );
        CSegment CA( c, a );
        double aa = AB.getLength();
        double bb = BC.getLength();
        double cc = CA.getLength();
        double s = ( aa + bb + cc ) / 2.0;
        return sqrt( s * ( s - aa ) * ( s - bb ) * ( s - cc ) );
    }
};
ostream& operator << ( ostream& os, CTriangle t0 ) {
    os << "{" << t0.a << ", " << t0.b << ", " << t0.c << "}";
    return os;
}
const double EPS = 1e-9;
double GetSquare( double x ) {
    return x * x;
}
bool Equal( double a, double b ) {
    return fabs( b - a ) < EPS;
}
bool LessthanEqual( double a, double b ) {
    return a < b ? true : ( fabs( b - a ) < EPS );
}
double GetCrossProduct( double x1, double y1, double x2, double y2 ) {
    return x1 * y2 - y1 * x2;
}
double GetCrossProduct( CPoint a, CPoint b ) {
    return GetCrossProduct( a.x, a.y, b.x, b.y );
}
double GetDotProduct( double x1, double y1, double x2, double y2 ) {
    return x1 * x2 + y1 * y2;
}
double GetDotProduct( CPoint a, CPoint b ) {
    return GetDotProduct( a.x, a.y, b.x, b.y );
}
bool Intersect( CPoint p1, CPoint p2, CPoint p3, CPoint p4 ) {
    bool f1 = LessthanEqual( CheckCounterClockWise( p1, p2, p3 ) * CheckCounterClockWise( p1, p2, p4 ), 0 );
    bool f2 = LessthanEqual( CheckCounterClockWise( p3, p4, p1 ) * CheckCounterClockWise( p3, p4, p2 ), 0 );
    return f1 && f2;
}
bool Intersect( CSegment s1, CSegment s2 ) {
    return Intersect( s1.a, s1.b, s2.a, s2.b );
}
bool Contain( CTriangle a, CPoint p ) {
    CVector2D AP = p - a.a;
    CVector2D BP = p - a.b;
    CVector2D CP = p - a.c;
    CVector2D AB = a.b - a.a;
    CVector2D BC = a.c - a.b;
    CVector2D CA = a.a - a.c;
    if ( GetCrossProduct( AP, AB ) <= 0.0
         && GetCrossProduct( BP, BC ) <= 0.0
         && GetCrossProduct( CP, CA ) <= 0.0 ) return true;
    if ( GetCrossProduct( AP, AB ) >= 0.0
         && GetCrossProduct( BP, BC ) >= 0.0
         && GetCrossProduct( CP, CA ) >= 0.0 ) return true;
    return false;
}
bool Contain( CCircle cir, CTriangle tri ) {
    double maxd = 0.0;
    maxd = max( maxd, GetDistance( tri.a, cir.p ) );
    maxd = max( maxd, GetDistance( tri.b, cir.p ) );
    maxd = max( maxd, GetDistance( tri.c, cir.p ) );
    return LessthanEqual( maxd, cir.r );
}
bool Contain( CTriangle tri, CCircle cir ) {
    double mind = GetDistance(CSegment(tri.a, tri.b), cir.p);
    mind = min( mind, GetDistance(CSegment(tri.b, tri.c), cir.p) );
    mind = min( mind, GetDistance(CSegment(tri.c, tri.a), cir.p) );
    return LessthanEqual( cir.r, mind );
}
double GetGradientFromTwoPoints( CPoint a, CPoint b ) {
    return ( b.y - a.y ) / ( b.x - a.x );
}
const int COUNTER_CLOCKWISE = 1;
const int CLOCKWISE = -1;
const int ONLINE_BACK = 2;
const int ONLINE_FRONT = -2;
const int ON_SEGMENT = 0;
int CheckCounterClockWise( CPoint p0, CPoint p1, CPoint p2 ) {
    CVector2D a = p1 - p0;
    CVector2D b = p2 - p0;
    if ( GetCrossProduct( a, b ) > EPS ) return COUNTER_CLOCKWISE;
    if ( GetCrossProduct( a, b ) < EPS ) return CLOCKWISE;
    if ( GetDotProduct( a, b ) < -EPS ) return ONLINE_BACK;
    if ( a.getNorm() < b.getNorm() ) return ONLINE_FRONT;
    return ON_SEGMENT;
}
CPoint GetCrossPoint( CSegment s1, CSegment s2 ) {
    CVector2D base = s2.b - s2.a;
    double d1 = abs( GetCrossProduct( base, s1.a - s2.a ) );
    double d2 = abs( GetCrossProduct( base, s1.b - s2.a ) );
    double t = d1 / ( d1 + d2 );
    return s1.a + ( s1.b - s1.a ) * t;
}
double GetLength( CPoint a, CPoint b ) {
    return sqrt( GetSquare( a.x - b.x ) + GetSquare( a.y - b.y ) );
}
double GetDistance( CPoint a, CPoint b ) {
    return GetLength( a, b );
}
CPoint GetLowestY( CPoint a, CPoint b ) {
    if ( a.y == b.y ) return a.x < b.x ? a : b;
    return a.y < b.y ? a : b;
}
double GetDistance( CSegment seg, CPoint p ) {
    if ( GetDotProduct( seg.b - seg.a, p - seg.a ) < EPS ) return (p - seg.a).getAbs();
    if ( GetDotProduct( seg.a - seg.b, p - seg.b ) < EPS ) return (p - seg.b).getAbs();
    return fabs( GetCrossProduct( seg.b - seg.a, p - seg.a ) ) / ( seg.b - seg.a ).getAbs();
}
bool CheckIntersect( CSegment seg, CCircle c ) {
    bool f1 = LessthanEqual( ( c.p - seg.a ).getAbs(), c.r );
    bool f2 = LessthanEqual( ( c.p - seg.b ).getAbs(), c.r );
    if ( f1 ^ f2 ) return true;
    return LessthanEqual( GetDistance( seg, c.p ), c.r ) && ( ! f1 && ! f2 );
}
bool CheckIntersect( CTriangle tri, CCircle cir ) {
    return CheckIntersect( CSegment( tri.a, tri.b ), cir )
        || CheckIntersect( CSegment( tri.b, tri.c ), cir )
        || CheckIntersect( CSegment( tri.c, tri.a ), cir );
}
double GetArea( CSegment s0, CSegment s1, CSegment s2 ) {
    if ( ! Intersect( s0, s1 ) || ! Intersect( s1, s2 ) || ! Intersect( s2, s0 ) ) {
        return -1.0;
    }
    return CTriangle( GetCrossPoint( s0, s1 ), GetCrossPoint( s1, s2 ), GetCrossPoint( s2, s0 ) ).getArea();
}


class UnionFind {
public:
    int n;
    VI D;
    UnionFind( int n ): n(n) {
        D = VI(n);
        for ( int i = 0; i < n; ++ i ) D[i] = -1;
    }
    UnionFind(): n(0) {}
    void merge( int x, int y ) {
        x = get(x);
        y = get(y);
        if ( x != y ) D[y] = x;
    }
    bool same( int x, int y ) {
        return get( x ) == get( y );
    }
    int get( int x ) {
        return D[x] == -1 ? x : get( D[x] );
    }
};

CPoint P[101][4];

bool check( CPoint a[4], CPoint b[4] ) {
    for ( int lp = 0; lp < 2; ++ lp ) {
        bool flag1 = true; 
        CTriangle t1( a[0], a[1], a[2] );
        CTriangle t2( a[2], a[3], a[0] );
        for ( int i = 0; i < 4; ++ i ) {
            if ( ! Contain( t1, b[i] ) ) flag1 = false;
        }
        if ( flag1 ) return true;
        swap( a, b );
    }
    for ( int i = 0; i < 4; ++ i ) {
        for ( int j = 0; j < 4; ++ j ) {
            if ( Equal( a[i].x, b[j].x ) && Equal( a[i].y, b[j].y ) ) return true;
        }
    }
    for ( int i1 = 0; i1 < 4; ++ i1 ) {
        for ( int i2 = i1+1; i2 < 4; ++ i2 ) {
            for ( int j1 = 0; j1 < 4; ++ j1 ) {
                for ( int j2 = 0; j2 < 4; ++ j2 ) {
                    CSegment s1( a[i1], a[i2] );
                    CSegment s2( b[j1], b[j2] );
                    if ( Intersect( s1, s2 ) ) return true;
                }
            }
        }
    }
    return false;
}

int solve( int n ) {
    UnionFind uf(n);
    for ( int i = 0; i < n; ++ i ) {
        for ( int j = 0; j < n; ++ j ) {
            if ( i == j ) continue;
            bool flag = check( P[i], P[j] );
            if ( flag ) uf.merge( i, j );
        }
    }
    int res = 0;
    for ( int i = 0; i < n; ++ i ) if ( uf.D[i] == -1 ) res ++;
    return res;
}

int main() {
    int n;
    while ( cin >> n && n ) {
        for ( int lp = 0; lp < n; ++ lp ) {
            int m;
            cin >> m;
            for ( int i = 0; i < m; ++ i ) {
                int x, y;
                for ( int j = 0; j < 4; ++ j ) {
                    cin >> x >> y;
                    P[i][j] = CPoint( x, y );
                }
            }
            cout << solve(m) << endl;
        }
    }
    return 0;
}