HDU 573 tetrahedron 三维计算几何(叉积, 四面体内切球)

tetrahedron


Problem Description
Given four points ABCD, if ABCD is a tetrahedron, calculate the inscribed sphere of ABCD.
 

Input
Multiple test cases (test cases  100 ).

Each test cases contains a line of 12 integers  [1e6,1e6]  indicate the coordinates of four vertices of ABCD.

Input ends by EOF.
 

Output
Print the coordinate of the center of the sphere and the radius, rounded to 4 decimal places.

If there is no such sphere, output "O O O O".
 

Sample Input
  
  
0 0 0 2 0 0 0 0 2 0 2 0 0 0 0 2 0 0 3 0 0 4 0 0
 

Sample Output
  
  
0.4226 0.4226 0.4226 0.4226 O O O O
 


设四面体四个顶点坐标分别为  (xi,yi,zi) ,与之相对的面的面积为 si ,四面体体积为 V ,则有 
四面体内心(内切球球心)坐标 

x = s1x1+s2x2+s3x3+s4x4s1+s2+s3+s4y = s1y1+s2y2+s3y3+s4y4s1+s2+s3+s4z = s1z1+s2z2+s3z3+s4z4s1+s2+s3+s4

四面体内切球半径 
r = 3Vs1+s2+s3+s4

面积可以用三维叉积求,体积则用混合积 
若体积为0,则内切球不存在

#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;

const int MAXN = 500000 + 7;
const double eps = 1e-7;
const double PI = acos(-1.0);

int sgn(double x) {
    if(fabs(x) < eps) return 0;
    return x > 0 ? 1 : -1;
}

struct Point {
    double x, y, z;
    Point() {}
    Point(double x, double y, double z) : x(x), y(y), z(z) {}
};

typedef Point Vec;

Vec operator + (Vec v1, Vec v2) {return Vec(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);}
Vec operator - (Vec v1, Vec v2) {return Vec(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);}
Vec operator * (Vec v, double p) {return Vec(v.x * p, v.y * p, v.z * p);}
Vec operator / (Vec v, double p) {return Vec(v.x / p, v.y / p, v.z / p);}
bool operator == (Vec v1, Vec v2) {
    return sgn(v1.x - v2.x) == 0 && sgn(v1.y - v2.y) == 0;
}

double vDiot(Vec v1, Vec v2) {return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;}
double vLen(Vec v) {return sqrt(vDiot(v, v));}
Vec vCross(Vec v1, Vec v2) {return Vec(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);}
double getArea(Vec a, Vec b, Vec c) {
    return vLen(vCross(b - a, c - a)) / 2;
}
double getVolum(Vec v1, Vec v2, Vec v3, Vec v4) {
    return fabs(vDiot(v4 - v1, vCross(v2 - v1, v3 - v1)) / 6.0);
}

int main() {
    ios::sync_with_stdio(false);
    Point p[4];
    double X, Y, Z, V, R, sa, sb, sc, sd;
    while(cin >> p[0].x >> p[0].y >> p[0].z >> p[1].x >> p[1].y >> p[1].z >> p[2].x
              >> p[2].y >> p[2].z >> p[3].x >> p[3].y >> p[3].z) {
        sa = getArea(p[1], p[2], p[3]);
        sb = getArea(p[0], p[2], p[3]);
        sc = getArea(p[0], p[1], p[3]);
        sd = getArea(p[0], p[1], p[2]);
        X = (sa * p[0].x + sb * p[1].x + sc * p[2].x + sd * p[3].x) / (sa + sb + sc + sd);
        Y = (sa * p[0].y + sb * p[1].y + sc * p[2].y + sd * p[3].y) / (sa + sb + sc + sd);
        Z = (sa * p[0].z + sb * p[1].z + sc * p[2].z + sd * p[3].z) / (sa + sb + sc + sd);
        V = getVolum(p[0], p[1], p[2], p[3]);
        R = 3 * V / (sa + sb + sc + sd);
        if(V < eps) {
            cout << "O O O O" << endl;
        }
        else {
            cout << fixed << setprecision(4) << X << " " << Y << " " << Z << " " << R << endl;
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值