#include<bits/stdc++.h>
using namespace std;
typedef complex < double > P;
typedef vector< P > G;
vector< G > g;
const double EPS = 1e-8;
const double INF = 1e12;
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: 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;
  if(cross(b,c) < 0) return -1;
  if(dot(b,c) < 0) return 2; // c--a--b
  if(norm(b) < norm(c)) return -2; // a--b--c
  return 0; // a--c--b
}
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;
}
#define curr(P,i) P[i]
#define next(P,i) P[(i+1)%P.size()]
bool conteins(const G& Q, const P& p){
  bool in = false;
  for(int i = 0 ; i < Q.size() ; i++ ){
    P a = curr(Q,i) - p, b = next(Q,i) - p;
    if(imag(a) > imag(b)) swap(a,b);
    if(imag(a) <= 0 && 0 < imag(b) && cross(a,b) < 0) in = !in;
    if(cross(a,b) == 0 && dot(a,b) <= 0) return true;
  }
  return in;
}
bool intersect( int x, int y){ //???????????? g[x] == g[y]
  // g[x] or g[y] ?????????
  for(int i = 0 ; i < 4 ; i++ ){
    if(conteins(g[y],g[x][i]) || conteins(g[x],g[y][i])) return true;
  }
  // g[x] ??¨ g[y]???????????????
  for(int i = 0 ; i < 4 ; i++ ){
    for(int j = 0 ; j < 4 ; j++ ){
      if(intersectSS(L(curr(g[x],i),next(g[x],i)),L(curr(g[y],j),next(g[y],j)))) return true;
    }
  }
  return false;
}

struct UnionFind {
  vector< int > data;
  UnionFind(){}
  void Build(int sz){ data.assign(sz, -1); }
  int Find(int x){ return(data[x] < 0 ? x : data[x] = Find(data[x])); }
  int Same(int a, int b){ return(Find(a) == Find(b)); }
  int Unite(int a, int b){ if(!Same(a, b)) data[a] += data[b], data[b] = a; }
};

int main()
{
  int N;
  UnionFind uf;

  while(cin >> N, N) {
    while(N--) {
      int M;
      cin >> M;
      uf.Build(M);
      g.resize(M);
      for(int i = 0; i < M; i++) {
        g[i].resize(4);
        for(int j = 0; j < 4; j++) {
          cin >> g[i][j].real() >> g[i][j].imag();
        }
      }
      for(int i = 0; i < M; i++) {
        for(int j = i + 1; j < M; j++) {
          if(intersect(i, j)) uf.Unite(i, j);
        }
      }
  
      int ret = 0;
      for(int i = 0; i < M; i++) {
        ret += i == uf.Find(i);
      }
      cout << ret << endl;
    }
  }
}