On this page
article
Geometria 3D
Sobre
Link original: geometria3d.cpp
Código
typedef double ld;
const ld DINF = 1e18;
const ld eps = 1e-9;
#define sq(x) ((x)*(x))
bool eq(ld a, ld b) {
return abs(a - b) <= eps;
}
struct pt { // ponto
ld x, y, z;
pt(ld x_ = 0, ld y_ = 0, ld z_ = 0) : x(x_), y(y_), z(z_) {}
bool operator < (const pt p) const {
if (!eq(x, p.x)) return x < p.x;
if (!eq(y, p.y)) return y < p.y;
if (!eq(z, p.z)) return z < p.z;
return 0;
}
bool operator == (const pt p) const {
return eq(x, p.x) and eq(y, p.y) and eq(z, p.z);
}
pt operator + (const pt p) const { return pt(x+p.x, y+p.y, z+p.z); }
pt operator - (const pt p) const { return pt(x-p.x, y-p.y, z-p.z); }
pt operator * (const ld c) const { return pt(x*c , y*c , z*c ); }
pt operator / (const ld c) const { return pt(x/c , y/c , z/c ); }
ld operator * (const pt p) const { return x*p.x + y*p.y + z*p.z; }
pt operator ^ (const pt p) const { return pt(y*p.z - z*p.y, z*p.x - x*p.z, x*p.y - y*p.x); }
friend istream& operator >> (istream& in, pt& p) {
return in >> p.x >> p.y >> p.z;
}
};
struct line { // reta
pt p, q;
line() {}
line(pt p_, pt q_) : p(p_), q(q_) {}
friend istream& operator >> (istream& in, line& r) {
return in >> r.p >> r.q;
}
};
struct plane { // plano
array<pt, 3> p; // pontos que definem o plano
array<ld, 4> eq; // equacao do plano
plane() {}
plane(pt p_, pt q_, pt r_) : p({p_, q_, r_}) { build(); }
friend istream& operator >> (istream& in, plane& P) {
return in >> P.p[0] >> P.p[1] >> P.p[2];
P.build();
}
void build() {
pt dir = (p[1] - p[0]) ^ (p[2] - p[0]);
eq = {dir.x, dir.y, dir.z, dir*p[0]*(-1)};
}
};
// converte de coordenadas polares para cartesianas
// (angulos devem estar em radianos)
// phi eh o angulo com o eixo z (cima) theta eh o angulo de rotacao ao redor de z
pt convert(ld rho, ld th, ld phi) {
return pt(sin(phi) * cos(th), sin(phi) * sin(th), cos(phi)) * rho;
}
// projecao do ponto p na reta r
pt proj(pt p, line r) {
if (r.p == r.q) return r.p;
r.q = r.q - r.p; p = p - r.p;
pt proj = r.q * ((p*r.q) / (r.q*r.q));
return proj + r.p;
}
// projecao do ponto p no plano P
pt proj(pt p, plane P) {
p = p - P.p[0], P.p[1] = P.p[1] - P.p[0], P.p[2] = P.p[2] - P.p[0];
pt norm = P.p[1] ^ P.p[2];
pt proj = p - (norm * (norm * p) / (norm*norm));
return proj + P.p[0];
}
// distancia
ld dist(pt a, pt b) {
return sqrt(sq(a.x-b.x) + sq(a.y-b.y) + sq(a.z-b.z));
}
// distancia ponto reta
ld distline(pt p, line r) {
return dist(p, proj(p, r));
}
// distancia de ponto para segmento
ld distseg(pt p, line r) {
if ((r.q - r.p)*(p - r.p) < 0) return dist(r.p, p);
if ((r.p - r.q)*(p - r.q) < 0) return dist(r.q, p);
return distline(p, r);
}
// distancia de ponto a plano com sinal
ld sdist(pt p, plane P) {
return P.eq[0]*p.x + P.eq[1]*p.y + P.eq[2]*p.z + P.eq[3];
}
// distancia de ponto a plano
ld distplane(pt p, plane P) {
return abs(sdist(p, P));
}
// se ponto pertence a reta
bool isinseg(pt p, line r) {
return eq(distseg(p, r), 0);
}
// se ponto pertence ao triangulo definido por P.p
bool isinpol(pt p, vector<pt> v) {
assert(v.size() >= 3);
pt norm = (v[1]-v[0]) ^ (v[2]-v[1]);
bool inside = true;
int sign = -1;
for (int i = 0; i < v.size(); i++) {
line r(v[(i+1)%3], v[i]);
if (isinseg(p, r)) return true;
pt ar = v[(i+1)%3] - v[i];
if (sign == -1) sign = ((ar^(p-v[i]))*norm > 0);
else if (((ar^(p-v[i]))*norm > 0) != sign) inside = false;
}
return inside;
}
// distancia de ponto ate poligono
ld distpol(pt p, vector<pt> v) {
pt p2 = proj(p, plane(v[0], v[1], v[2]));
if (isinpol(p2, v)) return dist(p, p2);
ld ret = DINF;
for (int i = 0; i < v.size(); i++) {
int j = (i+1)%v.size();
ret = min(ret, distseg(p, line(v[i], v[j])));
}
return ret;
}
// intersecao de plano e segmento
// BOTH = o segmento esta no plano
// ONE = um dos pontos do segmento esta no plano
// PARAL = segmento paralelo ao plano
// CONCOR = segmento concorrente ao plano
enum RETCODE {BOTH, ONE, PARAL, CONCOR};
pair<RETCODE, pt> intersect(plane P, line r) {
ld d1 = sdist(r.p, P);
ld d2 = sdist(r.q, P);
if (eq(d1, 0) and eq(d2, 0))
return pair(BOTH, r.p);
if (eq(d1, 0))
return pair(ONE, r.p);
if (eq(d2, 0))
return pair(ONE, r.q);
if ((d1 > 0 and d2 > 0) or (d1 < 0 and d2 < 0)) {
if (eq(d1-d2, 0)) return pair(PARAL, pt());
return pair(CONCOR, pt());
}
ld frac = d1 / (d1 - d2);
pt res = r.p + ((r.q - r.p) * frac);
return pair(ONE, res);
}
// rotaciona p ao redor do eixo u por um angulo a
pt rotate(pt p, pt u, ld a) {
u = u / dist(u, pt());
return u * (u * p) + (u ^ p ^ u) * cos(a) + (u ^ p) * sin(a);
}