#include <cstdio>
#include <iostream>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>

using namespace std;

#define EPS (1e-10)
#define EQ(a,b) (abs((a) - (b)) < EPS)
#define EQV(a,b) (EQ((a).real(),(b).real()) && EQ((a).imag(),(b).imag()))

typedef complex<double> P;
typedef pair<P,P> Edge;
typedef long long ll;

const double PI=4*atan(1.0);
const int MAX_SIZE = 10000;

// àÏ
double dot(P a, P b) {
  return (a.real() * b.real() + a.imag() * b.imag());
}
// OÏ
double cross(P a, P b) {
  return (a.real() * b.imag() - a.imag() * b.real());
}
// é`ÌÉ_ª¶Ý·é©Ç¤©
bool isInRectangle(P p1,P p2,P p3,P p4,P s){
	P a=p1-s;
	P b=p2-s;
	P c=p3-s;
    P d=p4-s;
    return ((cross(a,b)>0||EQ(a,b))&&(cross(b,c)>0||EQ(a,b))&&(cross(c,d)>0||EQ(c,d))&&(cross(d,a)>0||EQ(d,a)))
    		||((cross(a,b)<0||EQ(a,b))&&(cross(b,c)<0||EQ(a,b))&&(cross(c,d)<0||EQ(c,d))&&(cross(d,a)<0||EQ(d,a)));
}

struct Rec{
	P p[4];
};

class UnionFindTree{
private:
  // indexÌÌem[h
  // indexðªÆ·éØÌN
  // ØÌÅål
  int treeSize;
public:
  vector<int> par;
  vector<int> rank;
  UnionFindTree(int initTreeSize = 1000){
	  // øÅ^¦çê½lðÅåi[Æ·éUnionFindTreeÌì¬
	  treeSize = initTreeSize;
	  init();
  }
  void init(){
	  for(int i = 0; i < treeSize; i++){
		  par.push_back(i);
		  rank.push_back(0);
	  }
  }
  // ^¦çê½ªi[³êÄ¢éØÌ[gðTõ
  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[y] == rank[x])rank[x]++;
	  }
  }
  bool same(int x,int y){
	  return find(x) == find(y);
  }
};

// aÆbÌé`ªÚµÄ¢é©Ç¤©
bool check(Rec &a,Rec &b){
	// aÌe¸_ªbÌÉ¶ÝµÄ¢é©`FbN
	for(int i=0;i<4;i++)if(isInRectangle(b.p[0],b.p[1],b.p[2],b.p[3],a.p[i]))return true;
	for(int i=0;i<4;i++)if(isInRectangle(a.p[0],a.p[1],a.p[2],a.p[3],b.p[i]))return true;
	return false;
}

Rec recs[1001];
int main(){
	int t;
	while(cin>>t&&t!=0){
		while(t--){
			int n;
			cin>>n;
			for(int i=0;i<n;i++){
				for(int j=0;j<4;j++){
					int x,y;
					cin>>x>>y;
					recs[i].p[j]=P(x,y);
				}
			}
			UnionFindTree uft(n);
			for(int i=0;i<n;i++){
				for(int j=0;j<n;j++){
					if(i==j)continue;
					if(check(recs[i],recs[j]))uft.unite(i,j);
				}
			}
			set<int> s;
			for(int i=0;i<n;i++)s.insert(uft.par[i]);
			cout<<s.size()<<endl;
		}
	}
	return 0;
}