#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<set>
#include<complex>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define NEXT(i,n)  ( ((i+1)%n))
typedef complex<double> P;
const double EPS = 1e-10;
class DisjointSet{
public:
  vector<int> rank,p;
  DisjointSet(){}
  DisjointSet(int size){
    rank.resize(size,0);
    p.resize(size,0);
  }
  void makeset(int x){
    p[x]=x;
    rank[x]=0;
  }
  void merge(int x,int y){
    link(findset(x),findset(y));
  }
  void link(int x,int y){
    if ( rank[x] > rank[y]){
      p[y]=x;      
    }else {
      p[x]=y;
      if ( rank[x] == rank[y])rank[y]++;
    }
  }
  int findset(int x){
    if ( x != p[x])p[x] = findset(p[x]);
    return p[x];
  }
};

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

bool is_point_online(P a,P b,P c){
  return ( abs(a-c)+abs(b-c) < abs(a-b)+EPS);
}

bool isl(P a1,P a2,P b1,P b2){
  if ( is_point_online(a1,a2,b1))return true;
  if ( is_point_online(a1,a2,b2))return true;
  if ( is_point_online(b1,b2,a1))return true;
  if ( is_point_online(b1,b2,a2))return true;
  if (  ( cross(a2-a1,b1-a1) * cross(a2-a1,b2-a1)<EPS ) && 
	( cross(b2-b1,a1-b1)*cross(b2-b1,a2-b1)<EPS))return true;
  else return false;
}

bool is_in(P *in,P a){
  int cnt = 0;
  rep(i,4){
    P cur = in[i]-a,next=in[NEXT(i,4)]-a;
    if ( cur.imag()>next.imag())swap(cur,next);
    if (cur.imag()<0 && 0 <=next.imag() &&
	cross(next,cur)>=0)cnt++;
    if ( is_point_online(in[i],in[NEXT(i,4)],a))return true;
  }
  if ( cnt % 2 == 1)return true;
  else return false;
}

class block{
public:
  P in[4];
  bool sect(block  a){
    
    rep(i,4){
      rep(j,4){
	if ( isl(in[i],in[NEXT(i,4)],a.in[j],a.in[NEXT(j,4)])){
	  return true;
	} 
      }
    }

    rep(i,4){
      if ( is_in(in,a.in[i])||is_in(a.in,in[i]))return true;
    }
    
    return false;
  }
};


class sq{
public:
  vector<block> in;
};


DisjointSet dj(100);


int solve(int n,sq me){
  rep(i,100)dj.makeset(i);
  rep(i,n){
    //    REP(j,i+1,n){
    rep(j,n){
      if ( i!=j  && me.in[i].sect(me.in[j]) == true)dj.merge(i,j);
    }
  }
  
  set<int> S;
  rep(i,n)S.insert(dj.findset(i));
  return S.size();
}


main(){
  int n;
  while(cin>>n && n){
    rep(i,n){
      int m;
      cin>>m;
      sq now;
      rep(j,m){
	block ins;
	rep(k,4){
	  cin>>ins.in[k].real()>>ins.in[k].imag();
	}
	now.in.push_back(ins);
      }
      cout << solve(m,now) << endl;
    }
  }
  return false;
}