#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
#include <cfloat>
#include <ctime>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <numeric>

using namespace std;

#ifdef _MSC_VER
#define __typeof__ decltype

template <class T>
int __builtin_popcount(T n) { return n ? 1 + __builtin_popcount(n & (n - 1)) : 0; }
#endif

#define foreach(it, c) for (__typeof__((c).begin()) it=(c).begin(); it != (c).end(); ++it)
#define all(c) (c).begin(), (c).end()
#define rall(c) (c).rbegin(), (c).rend()
#define popcount __builtin_popcount

const double EPS = 1e-8;
typedef long long ll;
typedef pair<int, int> pint;

typedef complex<double> Point;

int sign(double n)
{
	if (abs(n) < EPS)
		return 0;
	else if (n > 0)
		return 1;
	else
		return -1;
}
double dot(const Point& a, const Point& b)
{
	return a.real()*b.real() + a.imag()*b.imag();
}
double cross(const Point& a, const Point& b)
{
	return a.real()*b.imag() - a.imag()*b.real();
}
double distance_line_point(const Point& point, const Point& a, const Point& b)
{
	return abs(cross(a-b, point-b) / (a-b));
}
double distance_linesegment_point(const Point& point, const Point& a, const Point& b)
{
	if (dot(b-a, point-a) < 0)
		return abs(a-point);
	else if (dot(a-b, point-b) < 0)
		return abs(b-point);
	else
		return distance_line_point(point, a, b);
}
bool is_in_triangle(const Point& point, const Point* triangle)
{
	double t[3];
	for (int i = 0; i < 3; ++i)
		t[i] = cross(triangle[(i+1)%3] - triangle[i], point - triangle[i]);
	return t[0] >= 0 && t[1] >= 0 && t[2] >= 0
		|| t[0] <= 0 && t[1] <= 0 && t[2] <= 0;
}
bool is_in_triangle(const Point& point, const Point& a, const Point& b, const Point& c)
{
	Point t[3] = { a, b, c };
	return is_in_triangle(point, t);
}
bool is_circle_in_triangle(const Point& center, double radius, const Point* triangle)
{
	if (!is_in_triangle(center, triangle))
		return false;
	for (int i = 0; i < 3; ++i)
		if (distance_line_point(center, triangle[i], triangle[(i+1)%3]) < radius - EPS)
			return false;
	return true;
}
bool is_triangle_in_circle(const Point* triangle, const Point& center, double radius)
{
	for (int i = 0; i < 3; ++i)
		if (abs(triangle[i]-center) > radius + EPS)
			return false;
	return true;
}
bool intersect_linesegments(const Point& a1, const Point& a2, const Point& b1, const Point& b2)
{
	return cross(a2-a1, b1-a1)*cross(a2-a1, b2-a2) < EPS
		&& cross(b2-b1, a1-b1)*cross(b2-b1, a2-b1) < EPS;
}
bool intersect_triangle_circle(const Point* triangle, const Point& center, double radius)
{
	for (int i = 0; i < 3; ++i)
		if (distance_linesegment_point(center, triangle[i], triangle[(i+1)%3]) < radius + EPS)
			return true;
	return false;
}
Point intersectin_point(const Point& a1, const Point& a2, const Point& b1, const Point& b2)
{
	double d1 = distance_linesegment_point(a1, b1, b2);
	double d2 = distance_linesegment_point(a2, b1, b2);
	double prop = d1 / (d1 + d2);
	return a1 + (a2 - a1) * prop;
}
double area_polygon(const Point* points, int n)
{
	double s = 0;
	for (int i = 0; i < n; ++i)
		s += cross(points[i], points[(i+1) % n]);
	return abs(s / 2);
}
double area_triangle(const Point* points)
{
	return area_polygon(points, 3);
}
double area_triangle(const Point& a, const Point& b, const Point& c)
{
	Point t[] = { a, b, c };
	return area_triangle(t);
}

bool include_poly(Point* in_poly, int n, Point* out_poly, int m)
{
	int dir = 0;
	for (int i = 0; i < n; ++i)
	{
		Point a = in_poly[i];
		Point b = in_poly[(i+1)%n];
		for (int j = 0; j < m; ++j)
		{
			int d = sign(cross(b - a, out_poly[j] - a));
			if (d * dir < 0)
				return false;
			dir = d;
		}
	}
	return true;
}

bool intersect_poly(Point* poly1, int n, Point* poly2, int m)
{
	for (int i = 0; i < n; ++i)
		for (int j = 0; j < m; ++j)
			if (intersect_linesegments(poly1[i], poly1[(i+1)%n], poly2[j], poly2[(j+1)%n]))
				return true;
	return include_poly(poly1, n, poly2, m);
}
vector<int> edge[100];
bool visit[100];
void dfs(int v)
{
	visit[v] = true;
	foreach (it, edge[v])
	{
		if (!visit[*it])
			dfs(*it);
	}
}
int count(int n, Point p[100][4])
{
	for (int i = 0; i < n; ++i)
		edge[i].clear();
	fill(visit, visit+n, false);

	for (int i = 0; i < n; ++i)
	{
		for (int j = i+1; j < n; ++j)
		{
			if (intersect_poly(p[i], 4, p[j], 4))
			{
				edge[i].push_back(j);
				edge[j].push_back(i);
			}
		}
	}

	int res = 0;
	for (int i = 0; i < n; ++i)
	{
		if (!visit[i])
		{
			dfs(i);
			++res;
		}
	}
	return res;
}
int main()
{
	int N;
	while (scanf("%d", &N), N)
	{
		while (N--)
		{
			int M;
			Point p[100][4];
			scanf("%d", &M);
			for (int i = 0; i < M; ++i)
			{
				for (int j = 0; j < 4; ++j)
				{
					int a, b;
					scanf("%d%d", &a, &b);
					p[i][j] = Point(a, b);
				}
			}
			printf("%d\n", count(M, p));
		}
	}

	return 0;
}