#include <iostream>
#include <complex>
#include <vector>
#include <set>
using namespace std;

#define EPS (1e-10)

typedef complex<double> P;

int par[100];
int rank[100];

double cross(P a,P b){
	return (a.real() * b.imag() - a.imag() * b.real());
}

int is_intersected_ls(P a1,P a2,P b1,P b2){
	return ( cross(a2-a1, b1-a1) * cross(a2-a1, b2-a1) < EPS ) &&
	       ( cross(b2-b1, a1-b1) * cross(b2-b1, a2-b1) < EPS );
}

bool pol_contains_p(vector<P> v,P p){
	int n = v.size();
	int cr = 0, cl = 0;

	for(int i=0;i<n;i++){
		P a = v[i];
		P b = v[(i+1)%n];
		if(EPS > cross(b-a,p-a)) cr++;
		if(0 < cross(b-a,p-a) + EPS) cl++;
	}

	return cr == n || cl == n;
}

bool pol_intersects_pol(vector<P> a,vector<P> b){
	int n = a.size(), m = b.size();

	for(int i=0;i<n-1;i++){
		for(int j=0;j<m-1;j++){
			if(is_intersected_ls(a[i],a[i+1],b[j],b[j+1])) return true;
		}
	}

	for(int i=0;i<n;i++){
		if(pol_contains_p(b,a[i])) return true;
	}
	for(int i=0;i<m;i++){
		if(pol_contains_p(a,b[i])) return true;
	}

	return false;
}

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

int find(int x){
	if(par[x] == x){
		return x;
	}
	else{
		return par[x] = find(par[x]);
	}
}

void unite(int x,int y){
	x = find(x);
	y = find(y);
	if(x == y) return;

	if(rank[x] < rank[y]){
		par[x] = y;
	}
	else{
		par[y] = x;
		if(rank[x] == rank[y]) rank[x]++;
	}
}

bool same(int x,int y){
	return find(x) == find(y);
}

int main(void){
	int n;

	while(cin>>n, n){
		while(n--){
			vector< vector<P> > v;
			int m;
			cin>>m;

			init(m);

			for(int i=0;i<m;i++){
				vector<P> tv;
				for(int j=0;j<4;j++){
					P p;
					cin>>p.real()>>p.imag();
					tv.push_back(p);
				}

				for(int j=0;j<i;j++){
					if(!same(i,j) && pol_intersects_pol(v[j],tv)){
						unite(i,j);
					}
				}
				v.push_back(tv);
			}

			set<int> s;
			for(int i=0;i<m;i++){
				s.insert(find(i));
			}

			cout<<s.size()<<endl;
		}
	}

	return 0;
}