#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cassert>

#define rep(i,n) for(int i=0;i<n;i++)
#define rp(i,c) rep(i,(c).size())
#define fr(i,c) for(__typeof((c).begin()) i=(c).begin();i!=(c).end();i++)
#define mp make_pair
#define pb push_back
#define all(c) (c).begin(),(c).end()
#define dbg(x) cerr<<#x<<" = "<<(x)<<endl

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
const int inf=1<<28;
const double INF=1e10,EPS=1e-9;

typedef complex<double> P;
double cross(const P& a, const P& b) {
  return imag(conj(a)*b);
}
double dot(const P& a, const P& b) {
  return real(conj(a)*b);
}
struct L : public vector<P> {
  L(const P &a, const P &b) {
    push_back(a); push_back(b);
  }
};
int ccw(P a, P b, P c) {
  b -= a; c -= a;
  if (cross(b, c) > 0)   return +1;       // counter clockwise
  if (cross(b, c) < 0)   return -1;       // clockwise
  if (dot(b, c) < 0)     return +2;       // c--a--b on line
  if (norm(b) < norm(c)) return -2;       // a--b--c on line
  return 0;
}
typedef vector<P> G;
enum { OUT, ON, IN };
int convex_contains(const G &po, const P &p) {
  const int n = po.size();
  P g = (po[0] + po[n/3] + po[2*n/3]) / 3.0; // inner-P
  int a = 0, b = n;
  while (a+1 < b) { // invariant: c is in fan g-P[a]-P[b]
    int c = (a + b) / 2;
    if (cross(po[a]-g, po[c]-g) > 0) { // angle < 180 deg
      if (cross(po[a]-g, p-g) > 0 && cross(po[c]-g, p-g) < 0) b = c;
      else                                                  a = c;
    } else {
      if (cross(po[a]-g, p-g) < 0 && cross(po[c]-g, p-g) > 0) a = c;
      else                                                  b = c;
    }
  }
  b %= n;
  if (cross(po[a] - p, po[b] - p) < 0) return 0;
  if (cross(po[a] - p, po[b] - p) > 0) return 2;
  return 1;
}
bool intersectSS(const L &s, const L &t) {
  return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 &&
         ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;
}
bool crs(const G &a,const G &b)
{
	rep(i,4)
	{
		if(convex_contains(a,b[i]))return 1;
		if(convex_contains(b,a[i]))return 1;
	}
	rep(i,4)rep(j,4)
	{
		L l1(a[i],a[(i+1)%4]),l2(b[j],b[(j+1)%4]);
		if(intersectSS(l1,l2))return 1;
	}
	return 0;
}
int n,p[100];
int root(int x)
{
	if(p[x]==x)return x;
	return p[x]=root(p[x]);
}
int main()
{
	while(scanf("%d",&n),n)
	{
		rep(i,n)
		{
			int m; scanf("%d",&m);
			rep(j,m)p[j]=j;
			vector<G> g;
			rep(j,m)
			{
				G gg;
				rep(k,4)
				{
					int x,y; scanf("%d%d",&x,&y);
					gg.pb(P(x,y));
				}
				reverse(all(gg));
				g.pb(gg);
			}
			int ans=m;
			rep(j,m)rep(k,j)if(crs(g[j],g[k]))
			{
				int a=root(j),b=root(k);
				if(a!=b)p[b]=a,ans--;
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}