#include <set>
#include <cstdio>
#include <queue>
#include <iostream>
#include <complex>
#include <vector>
#include <climits>
#include <cfloat>

#define REP(i,n) for(int i=0; i<(int)(n); i++)

#define f first
#define s second
#define mp make_pair

using namespace std;

typedef complex<double> P;

class UnionFind{
private:
  vector<int> id;

  int getId(int i){
    if(i == id[i]) return i;
    return id[i] = getId(id[i]);
  }
public:
  UnionFind(int size = 0){ init(size); }
  ~UnionFind(){}
  void init(int size){
    id = vector<int>(size);
    for(int i = 0; i < size; i++)
      id[i] = i;
  }
  void unite(int i, int j){
    int next = min( getId(i), getId(j) );
    id[i] = id[j] = next;
  }
  int operator [](int i){ return getId(i); }
  int count(){
    set<int> s;
    for(int i = 0; i < (int)id.size(); i++)
      s.insert(getId(i));
    return s.size();
  }
};

//üª
struct S{
  P p1;
  P p2;
  S(P p,P q) : p1(p), p2(q) {}
};

/* p0, p1, p2ª
 * ½vñè:  1
 * vñè  : -1
 *
 * R_ª¼üãÉ éê
 * p0ªp2Æp1ÌÔÉ é: -1
 * p2ªp0Æp1ÌÔÉ é:  0
 * p1ªp0Æp2ÌÔÉ é:  1
 */
int ccw(P p0, P p1, P p2){
  P d1 = p1-p0;
  P d2 = p2-p0;
  double dx1 = d1.real(), dx2 = d2.real();
  double dy1 = d1.imag(), dy2 = d2.imag();

  if(dx1*dy2 > dy1*dx2) return  1;//½vñè
  if(dx1*dy2 < dy1*dx2) return -1;//vñè
  if((dx1*dx2 < 0) || (dy1*dy2 < 0)) return -1;
  if((dx1*dx1+dy1*dy1) < (dx2*dx2+dy2*dy2)) return 1;
  return 0;
}

bool intersect(const S &s1, const S &s2){
  return ((ccw(s1.p1, s1.p2, s2.p1)
	   *ccw(s1.p1, s1.p2, s2.p2)) <= 0)
    &&((ccw(s2.p1, s2.p2, s1.p1)
	*ccw(s2.p1, s2.p2, s1.p2)) <= 0);
}

bool inside(P t, const P *p, int N){
  int count = 0, j = 0;
  S lt(t, P(DBL_MAX,t.imag()));  

  P pj = p[N-1];
  for(int i=1; i<=N; i++){
    S lp(p[i-1],p[i-1]);
    if(ccw(lt.p1, lt.p2, p[i-1]) != 0){
      if(i == j+1){
	lp.p2 = pj;
	if(intersect(lp,lt)) count++;
      }else if(ccw(lt.p1, lt.p2, p[i-1])*ccw(lt.p1, lt.p2, pj) < 0)
	count++;
      j = i;
      if(j == N) pj = p[0];
      else pj = p[j-1];
    }else{
      count++;
    }
  }
  return (count & 1) == 1;
}

struct Polygon{
  vector<P> p;
  Polygon(){}
  Polygon(const vector<P> &ps) : p(ps){}
};

/* ¤ÊªðÂ */
bool intersect(const Polygon &r1, const Polygon &r2, bool impl = true){
  for(int i = 0; i < (int)r2.p.size(); i++){
    if(inside(r2.p[i], &r1.p[0], r1.p.size()))
      return true;
  }
  if(impl) return intersect(r2, r1, false);
  return false;
}

int main(){
  int t;
  while(scanf("%d", &t), t){
    while(t --> 0){
      int n; scanf("%d", &n);
      UnionFind uf(n);
      vector<Polygon> ps(n);
      
      REP(i,n){
	vector<P> pos(4);
	REP(j,4) scanf("%lf%lf", &pos[j].real(), &pos[j].imag());
	ps[i] = Polygon(pos);
	
	REP(j,i) if(intersect(ps[i], ps[j])){
	  uf.unite(i, j);
	  break;
	}
      }
      
      printf("%d\n", uf.count());
    }
  }
  return 0;
}