#include <bits/stdc++.h>
using namespace std;

#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)

const int MAX_N = 110;

int par[MAX_N];
int ranks[MAX_N];
int ufSize;

void init(int n){
    ufSize = n;
    for(int i=0; i<n; i++){
        par[i] = i;
        ranks[i] = 0;
    }
}

int find(int x){
    if(par[x] == x) return x;
    else 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 ;
    ufSize--;

    if(ranks[x] < ranks[y]) par[x] = y;
    else par[y] = x;

    if(ranks[x] == ranks[y]){
        ranks[x]++;
    }
}

struct Point{
    double x, y;
    Point(double x = 0, double y = 0): x(x), y(y) {}
    Point operator + (Point p){
        return Point(x + p.x, y + p.y);
    }
    Point operator - (Point p){
        return Point(x - p.x, y - p.y);
    }
    Point operator * (double a){
        return Point(a * x, a * y);
    }
    Point operator / (double a){
        return Point(x / a, y / a);
    }

    double norm(){
        return x * x + y * y;
    }
    double abs(){
        return sqrt(norm());
    }

    bool operator < (const Point &p) const {
        return (x != p.x ? x < p.x : y < p.y);
    }

};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Segment{
    Point p1, p2;
    Segment(Point p1, Point p2): p1(p1), p2(p2) {}
};

typedef Segment Line;

double dot(Vector a, Vector b){
    return a.x * b.x + a.y * b.y;
}

double cross(Vector a, Vector b){
    return a.x * b.y - a.y * b.x;
}

double norm(Vector a){
    return a.x * a.x + a.y * a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

int ccw(Point p0, Point p1, Point p2){
    Vector a = p1 - p0;
    Vector b = p2 - p0;
    if(cross(a, b) > EPS) return 1;
    if(cross(a, b) < -EPS) return -1;
    if(dot(a, b) < -EPS) return 2;
    if(a.norm() < b.norm()) return -2;
    return 0;
}

bool intersect(Point p1, Point p2, Point p3, Point p4){
    return (ccw(p1, p2, p3) * ccw(p1, p2, p4) <= 0 && ccw(p3, p4, p1) * ccw(p3, p4, p2) <= 0);
}

bool intersect(Segment s1, Segment s2){
    return intersect(s1.p1, s1.p2, s2.p1, s2.p2);
}

double getDistanceLP(Line l, Point p){
    return abs(cross(l.p2 - l.p1, p - l.p1) / abs(l.p2 - l.p1));
}

double getDistanceSP(Segment s, Point p){
    if(dot(s.p2 - s.p1, p - s.p1) < -EPS) return abs(p - s.p1);
    if(dot(s.p1 - s.p2, p - s.p2) < -EPS) return abs(p - s.p2);
    return getDistanceLP(s, p);
}

double getDistance(Segment s1, Segment s2){
    if(intersect(s1, s2)) return 0;
    return min({getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2), getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2)});
}

int contains(Polygon g, Point p){
    int n = g.size();
    bool x = false;
    for(int i=0; i<n; i++){
        Point a = g[i] - p;
        Point b = g[(i+1)%n] - p;
        if(abs(cross(a, b)) < EPS && dot(a, b) < EPS) return 1;
        if(a.y > b.y) swap(a, b);
        if(a.y < EPS && EPS < b.y && cross(a, b) > EPS) x = !x;
    }

    return (x ? 2 : 0);
}

int main(){
    while(1){
        int n; cin>>n;
        if(n == 0) return 0;
        while(n--){
            int m; cin>>m;
            vector<double> x1(m), x2(m), x3(m), x4(m), y1(m), y2(m), y3(m), y4(m);
            for(int i=0; i<m; i++){
                cin>>x1[i]>>y1[i]>>x2[i]>>y2[i]>>x3[i]>>y3[i]>>x4[i]>>y4[i];
            }

            init(m);
            for(int i=0; i<m; i++){
                for(int j=0; j<m; j++){
                    if(i == j) continue;

                    Segment s1 = {Point(x1[i], y1[i]), Point(x2[i], y2[i])};
                    Segment s2 = {Point(x2[i], y2[i]), Point(x3[i], y3[i])};
                    Segment s3 = {Point(x3[i], y3[i]), Point(x4[i], y4[i])};
                    Segment s4 = {Point(x4[i], y4[i]), Point(x1[i], y1[i])};

                    vector<Segment> S1;
                    S1.emplace_back(s1);
                    S1.emplace_back(s2);
                    S1.emplace_back(s3);
                    S1.emplace_back(s4);

                    Segment s5 = {Point(x1[j], y1[j]), Point(x2[j], y2[j])};
                    Segment s6 = {Point(x2[j], y2[j]), Point(x3[j], y3[j])};
                    Segment s7 = {Point(x3[j], y3[j]), Point(x4[j], y4[j])};
                    Segment s8 = {Point(x4[j], y4[j]), Point(x1[j], y1[j])};
                
                    vector<Segment> S2;
                    S2.emplace_back(s5);
                    S2.emplace_back(s6);
                    S2.emplace_back(s7);
                    S2.emplace_back(s8);

                    for(int k=0; k<4; k++){
                        for(int l=0; l<4; l++){
                            if(equals(getDistance(S1[k], S2[l]), 0)){
                                if(!same(i, j)){
                                    unite(i, j);
                                }
                            }
                        }
                    }

                    if(!same(i, j)){
                        Polygon po1;
                        po1.emplace_back(Point(x1[i], y1[i]));
                        po1.emplace_back(Point(x2[i], y2[i]));
                        po1.emplace_back(Point(x3[i], y3[i]));
                        po1.emplace_back(Point(x4[i], y4[i]));
                        int contain = 1;
                        contain *= contains(po1, Point(x1[j], y1[j]));
                        contain *= contains(po1, Point(x2[j], y2[j]));
                        contain *= contains(po1, Point(x3[j], y3[j]));
                        contain *= contains(po1, Point(x4[j], y4[j]));
                        
                        if(contain != 0){
                            unite(i, j);
                        }

                        Polygon po2;
                        po2.emplace_back(Point(x1[j], y1[j]));
                        po2.emplace_back(Point(x2[j], y2[j]));
                        po2.emplace_back(Point(x3[j], y3[j]));
                        po2.emplace_back(Point(x4[j], y4[j]));
                        contain = 1;
                        contain *= contains(po2, Point(x1[i], y1[i]));
                        contain *= contains(po2, Point(x2[i], y2[i]));
                        contain *= contains(po2, Point(x3[i], y3[i]));
                        contain *= contains(po2, Point(x4[i], y4[i]));
                        

                        if(contain != 0){
                            if(!same(i, j)){
                                unite(i, j);
                            }
                        }
                    }
                }
            }

            cout << ufSize << endl;
        }
    }
}


Measured memory_bytes: 3200