#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>

#define MAX_M (100)
#define EPS (1e-5)
#define SQ(X) ((X) * (X))

using namespace std;

typedef struct {
	double x, y;
} Point;

vector<Point> Rect[MAX_M];
vector<int> G[MAX_M];
bool used[MAX_M];
int flag;

double getSize(double a, double b, double c)
{
	double s;
	
	s = (a + b + c) / 2.0;
	
	flag |= s * (s - a) * (s - b) * (s - c) < 0;
	
	return (sqrt(s * (s - a) * (s - b) * (s - c)));
}

bool checkCross(vector<Point> p, vector<Point> q)
{
	double len[5];
	double areaA, areaB;
	
	for (int i = 0; i < 4; i++){
		len[i] = sqrt(SQ(p[i].x - p[(i + 1) % 4].x) + SQ(p[i].y - p[(i + 1) % 4].y));
	}
	len[4] = sqrt(SQ(p[0].x - p[2].x) + SQ(p[0].y - p[2].y));
	areaA = getSize(len[0], len[1], len[4]) + getSize(len[2], len[3], len[4]);
	
	for (int i = 0; i < 4; i++){
		areaB = 0;
		for (int j = 0; j < 4; j++){
			double two[2];
			two[0] = sqrt(SQ(p[j].x - q[i].x) + SQ(p[j].y - q[i].y));
			two[1] = sqrt(SQ(p[(j + 1) % 4].x - q[i].x) + SQ(p[(j + 1) % 4].y - q[i].y));
			areaB += getSize(len[j], two[0], two[1]);
		}
		if (fabs(areaA - areaB) <= EPS){
			return (true);
		}
	}
	
	return (false);
}

void dfs(int k)
{
	used[k] = true;
	for (int i = 0; i < G[k].size(); i++){
		if (!used[G[k][i]]){
			dfs(G[k][i]);
		}
	}
}

int main()
{
	int n, m;
	int ans;
	
	while (scanf("%d", &n) && n){
		
		for (int i = 0; i < n; i++){
			scanf("%d", &m);
			for (int j = 0; j < m; j++){
				Rect[j].clear();
				G[j].clear();
			}
			
			for (int j = 0; j < m; j++){
				for (int k = 0; k < 4; k++){
					Point in;
					scanf("%lf %lf", &in.x, &in.y);
					Rect[j].push_back(in);
				}
			}
			
			for (int j = 0; j < m; j++){
				for (int k = 0; k < m; k++){
					if (checkCross(Rect[j], Rect[k]) == true){
						G[j].push_back(k);
						G[k].push_back(j);
					}
				}
			}
			
			memset(used, false, sizeof(used));
			ans = 0;
			for (int j = 0; j < m; j++){
				if (used[j] == false){
					ans++;
					dfs(j);
				}
			}
			
			printf("%d\n", ans);
		}
	}
	
	return (flag);
}