#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <set>

#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define REP(i,j) FOR(i,0,j)
#define mp std::make_pair

typedef long long ll;
typedef unsigned long long ull;

const int INF = 1001001001;
const int MAX_N = 100;

// S N E W(南北東西)
const int dx[8] = {0, 0, 1, -1, 1, 1, -1, -1}, dy[8] = {1, -1, 0, 0, 1, -1, 1, -1};

class UnionFind{
public:
    UnionFind(int n){
        REP(i, n){
            par[i] = i;
            rank[i] = 0;
        }
    }
    int find(int x){
        if(x == par[x])return x;
        return par[x] = find(par[x]);
    }
    bool same(int x, int y){
        return find(x) == find(y);
    }
    void unite(int x, int y){
        x = find(x);
        y = find(y);
        if(x == y){return;}
        
        if(rank[x] > rank[y]){
            par[y] = x;
        }else{
            par[x] = y;
            if(rank[x] == rank[y]){rank[y]++;}
        }
    }
private:
    int rank[MAX_N], par[MAX_N];
};

struct P{
    P(){}
    P(ll _r, ll _i):r(_r), i(_i){}
    void real(const ll& v){r = v;}
    void imag(const ll& v){i = v;}
    ll r, i;
};

struct Rectangle{
    P ps[4];
};

ll real(const P& p){return p.r;}
ll imag(const P& p){return p.i;}
ll norm(const P& p){ll r = real(p), i = imag(p); return r * r + i * i;}

P operator+(const P& lhs, const P& rhs){
    return P(real(lhs)+real(rhs), imag(lhs)+imag(rhs));
}
P operator-(const P& lhs, const P& rhs){
    return P(real(lhs)-real(rhs), imag(lhs)-imag(rhs));
}
P operator-(const P& p){
    return P(-real(p), -imag(p));
}

ll cross(const P& lhs, const P& rhs){
    return real(lhs)*imag(rhs) - imag(lhs)*real(rhs);
}

ll dot(const P& lhs, const P& rhs){
    return real(lhs)*real(rhs) + imag(lhs)*imag(rhs);
}

bool areIntersectedLines(const P& p1, const P& p2, const P& q1, const P& q2){
    if(cross(p1-p2, q1-p2) == 0 && dot(p1-p2, q1-p2) > 0 &&
       0 <= norm(q1-p2) && norm(q1-p2) <= norm(p1-p2)){
        return true;
    }
    if(cross(p1-p2, q2-p2) == 0 && dot(p1-p2, q2-p2) > 0 &&
       0 <= norm(q2-p2) && norm(q2-p2) <= norm(p1-p2)){
        return true;
    }
    if(cross(q1-q2, p1-q2) == 0 && dot(q1-q2, p1-q2) > 0 &&
       0 <= norm(p1-q2) && norm(p1-q2) <= norm(q1-q2)){
        return true;
    }
    if(cross(q1-q2, p2-q2) == 0 && dot(q1-q2, p2-q2) > 0 &&
       0 <= norm(p2-q2) && norm(p2-q2) <= norm(q1-q2)){
        return true;
    }

    return (cross(p1-p2, q1-p2) * cross(p1-p2, q2-p2) < 0) &&
        (cross(q1-q2, p1-q2) * cross(q1-q2, p2-q2) < 0);
}

// lhs is in rhs?
bool isIn(const Rectangle& lhs, const Rectangle& rhs){
    REP(i, 4){
        int count_n = 0, count_p = 0;
        REP(j, 4){
            ll c = cross(rhs.ps[(j+1)%4]-rhs.ps[j], lhs.ps[i]-rhs.ps[j]);
            if(c == 0){
                count_n += 1; count_p += 1;
            }else if(c < 0){
                count_n += 1;
            }else{
                count_p += 1;
            }
        }

        if(count_n % 4 != 0 && count_p % 4 != 0){return false;}
    }
    return true;
}

bool areIntersected(const Rectangle& lhs, const Rectangle& rhs){
    REP(i, 4){
        REP(j, 4){
            if(areIntersectedLines(lhs.ps[i], lhs.ps[(i+1)%4], rhs.ps[j], rhs.ps[(j+1)%4])){
                return true;
            }
        }
    }
    return false;
}

int N;

int main(){
    while(std::cin >> N, N){
        REP(i, N){
            int m;
            std::cin >> m;

            std::vector<Rectangle> rs(m);
        
            REP(j, m){
                REP(_, 4){
                    ll re, im;
                    std::cin >> re >> im;
                    rs[j].ps[_].real(re); rs[j].ps[_].imag(im);
                }
            }

            UnionFind uf(m);

            REP(k, m){
                FOR(l, k+1, m){
                    // printf("%d, %d: %d, %d, %d\n", k, l, isIn(rs[k], rs[l]), isIn(rs[l], rs[k]), areIntersected(rs[k], rs[l]));
                    if(isIn(rs[k], rs[l]) || isIn(rs[l], rs[k]) || areIntersected(rs[k], rs[l])){
                        uf.unite(k, l);
                    }
                }
            }
        
            int res = 0;
            REP(j, m){
                if(j == uf.find(j)){res += 1;}
            }

            std::cout << res << std::endl;
        }
    }
}

Measured memory_bytes: 1212