/*
题意: 求平面的n个三角形的不同覆盖次数(1 - n)的面积 。
分析:扫描线可以搞定。
扫描线:把三角形的顶点和交点的x轴的值排序, 这样就能把三角形给离散化, 然后枚举前后两条线之间的情况来计算。
前后两条搞毛线之间的情况变得很简单:都是由没有线交属于某个三角形的三角形或者梯形组成, 然后就可以从上到下遍历这些图形边, 依次计算面积。
具体如图:
*/
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <queue>
#include <deque>
#include <complex>
#define MAX 200005
#define INF 1e8
#define FOR(i, n) for(int i = 0; i < n; i++)
#define FORB(i, n) for(int i = n - 1; i >= 0; i--)
#define MP(i, j) make_pair(i, j)
#define MEM(array, val) memset(array, val, sizeof(array))
#define pu first
#define pv second
#define eps 1e-10
#define INF 1e10
#define next(i, n) ( (i + 1) %n)
using namespace std;
inline double sqr(double x) {
return x * x;
}
inline int sgn(double x) {
return x > eps ? 1 : (x < -eps? -1 : 0);
}
struct Point {
double x, y;
Point() {}
Point(const double &xx, const double &yy):x(xx), y(yy) {}
friend Point operator + (const Point &b, const Point &a) {
return Point(b.x + a.x, b.y + a.y);
}
friend Point operator - (const Point &b, const Point &a) {
return Point(b.x - a.x, b.y - a.y);
}
Point operator * (const double &a)const{
return Point(x * a, y * a);
}
Point operator / (const double &a) const{
return Point(x / a, y / a);
}
friend double dot(const Point &a, const Point &b) {
return a.x *b.x + a.y * b.y;
}
friend double det(const Point &a, const Point &b) {
return a.x * b.y - a.y * b.x;
}
double len( )const {
return sqrt(dot(*this, *this));
}
bool operator < (const Point &a)const {
return sgn(x - a.x) < 0 || (sgn(x - a.x) == 0 && sgn(y - a.y) > 0);
}
bool operator == (const Point &a)const {
return sgn(x - a.x ) == 0 && sgn(y - a.y) == 0;
}
void in() {
scanf("%lf %lf", &x, &y);
}
void out()const {
printf("%.4f %.4f\n", x, y);
}
};
struct Line{
Point s, t;
Line(){}
Line(const Point &ss, const Point &tt):s(ss), t(tt){}
friend bool isParallel(const Line &l1, const Line &l2){
return sgn(det(l1.t - l1.s, l2.t - l2.s) ) == 0;
}
//点是否在线上(包含边界)
friend bool pointOnLine(const Point &p, const Line &l1){
bool res1 = sgn(det(l1.s - p, l1.t - p)) == 0;
if(!res1)return false;
return sgn( dot(l1.s - p, l1.t - p) ) <= 0;
}
//ab是否在l1的同一边, 不包含边界
friend bool sameSide(const Line &l1, const Point &a, const Point &b){
double res1 = det(b - l1.s, l1.t - l1.s);
double res2 = det(a - l1.s, l1.t - l1.s);
// cout<<sgn( res1 * res2)<<endl;
return sgn( res1 * res2) > 0;
}
//线段和线段的交点(包含边界), 重合则返回相交的端点
friend vector<Point> lineInsectLine(const Line &l1, const Line &l2){
vector<Point>res;
if(isParallel(l1, l2)){
if(pointOnLine(l1.s, l2))res.push_back(l1.s);
if(pointOnLine(l1.t, l2))res.push_back(l1.t);
if(pointOnLine(l2.s, l1))res.push_back(l2.s);
if(pointOnLine(l2.t, l1))res.push_back(l2.t);
}else{
bool res1 = !sameSide(l1, l2.s, l2.t);
bool res2 = !sameSide(l2, l1.s, l1.t);
if(!res1 || !res2)return res;
double s1 = det(l1.s - l2.s, l2.t - l2.s), s2 = det(l1.t - l2.s, l2.t - l2.s);
res.push_back(( l1.t * s1 - l1.s * s2) / (s1 - s2));
}
return res;
}
void out()const{
s.out();
t.out();
}
};
//ba 到 bc 的叉积符号
int cross(const Point &a,const Point &b, const Point &c) {
return sgn(det(a - b , c - b));
}
int n;//三角形个数
int nx, nl;//扫描线个数, 区间线个数
double x[111222];//扫描线
double ans[111];//每层的面积
struct Traingle {
Point a[3];
Traingle() {}
Traingle(const Point &aa, const Point &bb, const Point &cc) {
a[0] = aa; a[1] = bb; a[2] = cc;
}
//返回两个三角形的所有交点
friend vector<Point> insectTrian(const Traingle &a, const Traingle &b){
vector<Point>res, tt;
for(int i = 0; i < 3; i++){
Line l1(a.a[i], a.a[next(i, 3)]);
for(int j = 0; j < 3; j++){
Line l2(b.a[j], b.a[next(j,3)]);
tt = lineInsectLine(l1, l2);
for(int k = 0; k < tt.size();k++){
res.push_back(tt[k]);
}
}
}
//去重
sort(res.begin(), res.end());
int tn = unique(res.begin(), res.end()) - res.begin();
res.resize(tn);
return res;
}
//返回三角形和线的交点
friend vector<Point> insectLine(const Traingle &b, const Line &a){
vector<Point>res, tt;
for(int i = 0; i < 3; i++){
Line line(b.a[i], b.a[next(i, 3)]);
tt = lineInsectLine(line, a);
for(int i = 0; i < tt.size(); i++){
res.push_back(tt[i]);
}
}
//去重
sort(res.begin(), res.end());//左到右, 上到下
int tn= unique(res.begin(), res.end()) - res.begin();
res.resize(tn);
return res;
}
//判断面积是否为0, 看有木有共线边
bool isZroArea(){
return cross( a[0], a[1], a[2]) == 0;
}
} train[55];
//区间斜线类, 辅助计算区间面积
struct rangLine{
double yl, yr;//斜线在区间左右边的y值
int type; //1 表示某三角形在该区间的上边, -1下边
bool operator < (const rangLine &a)const{
return (yl + yr) > (a.yl + a.yr);
}
}rl[111222];
void addx(double val){
x[nx++] = val;
}
void init(){
cin>>n;
int p = 0;
for(int i = 0; i < n; i++) {
train[p].a[0].in();
train[p].a[1].in();
train[p++].a[2].in();
if(train[p -1 ].isZroArea() )p--;//面积为0滚蛋
}
n = p;
nx = 0;
nl = 0;
memset(ans, 0, sizeof(ans));
}
//获取所有扫描线, 并且去重
void getScanLine(){
vector<Point>ps;
for(int i = 0; i < n; i++){
addx(train[i].a[0].x);
addx(train[i].a[1].x);
addx(train[i].a[2].x);
for(int j =i + 1; j < n; j++){
ps = insectTrian(train[i], train[j]);
for(int k = 0; k < ps.size(); k++){
addx(ps[k].x);
}
}
}
sort(x, x + nx);
//去重
int p = 0;
for(int i = 0; i < nx; i++){
if(!i || sgn(fabs(x[i] - x[i -1]) != 0) ){
x[p++] = x[i];
}
}
nx = p;
}
const double maxh = 5000;
//获取某区间单个三角形的区间线
void getRangLine(const Traingle &tri, const double &l, const double &r){
// cout<<"at range "<<l<<" "<<r<<endl;
//判断三角形是否在区间内
double minx = INF, maxx = -INF;
for(int i = 0; i < 3; i++){
minx = min(tri.a[i].x, minx);
maxx = max(tri.a[i].x, maxx);
}
if( sgn(l - minx) < 0 || sgn(r - maxx) > 0)return ;//线必须夹着三角形
//求交点
vector<Point>psl, psr;
Line ll(Point(l, -maxh), Point(l, maxh));
Line lr(Point(r, -maxh), Point(r, maxh));
//获取两边直线交点
psl = insectLine(tri, ll);
psr = insectLine(tri, lr);
int i = 0, j = 0;
rl[nl].yl = psl[i].y;
rl[nl].yr = psr[j].y;
rl[nl].type = 1;
if(i < psl.size() - 1)i++;
if(j < psr.size() - 1)j++;
rl[nl + 1].yl = psl[i].y;
rl[nl + 1].yr = psr[j].y;
rl[nl + 1].type = -1;
nl += 2;
}
//单个区间的面积计算情况
void cacuRang(const double &l, const double &r){
nl = 0;
for(int j = 0; j < n; j++){
getRangLine(train[j], l, r);
}
sort(rl, rl + nl);
int cnt = 0;
for(int i = 0; i < nl; i++){
if(cnt){
ans[cnt] += fabs((rl[i - 1].yl - rl[i].yl + rl[i - 1].yr - rl[i].yr) * (r- l) );
}
cnt += rl[i].type;
}
}
void solve( ){
for(int i =1; i < nx; i++){
cacuRang(x[i -1], x[i]);
}
for(int i = 1; i <= n; i++){
printf("%.10f\n", ans[i]/2.0);
}
}
int main() {
int T;
cin>>T;
while(T--) {
init();
getScanLine();
solve();
}
return 0;
}
/*
2
2
0 0
0 2
2 0
0 1
0 -1
2 -1
1 2
1 0
3 0
*/