#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)
bool visited[100];
typedef complex<double> P;
const double EPS = 1e-10;

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[(i+1)%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[(i+1)%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[(i+1)%4],a.in[j],a.in[(j+1)%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;};

void dfs(int n,sq & me,int now){
  visited[now]=true;
  rep(i,n){
    if ( i != now && visited[i]==false && me.in[now].sect(me.in[i])==true)
      dfs(n,me,i);
  }
}

int solve(int n,sq me){
  rep(i,100)visited[i]=false;
  int cnt = 0;
  rep(i,n)if ( visited[i] == false)cnt++,dfs(n,me,i);
  return cnt;
}

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;
}