Blame shape.cpp

e31ea0
e31ea0
#include "shape.h"
e31ea0
e31ea0
e31ea0
CilinderShape::CilinderShape(Real radius, const Vector3 &pos, const Vector3 &dir) {
e31ea0
    Vector3 vx = dir.perp().norm();
e31ea0
    Vector3 vy = vx.cross(dir);
e31ea0
    matrix = Matrix4(
e31ea0
        vx.x*radius, vx.y*radius, vx.z*radius, 0,
e31ea0
        vy.x*radius, vy.y*radius, vy.z*radius, 0,
e31ea0
        dir.x      , dir.y      , dir.z      , 0,
e31ea0
        pos.x      , pos.y      , pos.z      , 1 ).inv();
e31ea0
}
e31ea0
e31ea0
Real CilinderShape::distance_to_triangle(const Triangle &triangle) const {
e31ea0
    Real dist = INFINITY;
e31ea0
    
e31ea0
    Vector3 v[3], d[3];
e31ea0
    Real A[3], B[3], C[3];
e31ea0
    for(int i = 0; i < 3; ++i) {
e31ea0
        v[i] = matrix.transform( triangle.vertices[i] );
e31ea0
        C[i] = v[i].x*v[i].x + v[i].y*v[i].y - 1;
e31ea0
        
e31ea0
        // collision with vertex
e31ea0
        if (C[i] <= precision)
e31ea0
            dist = std::min(dist, v[i].z);
e31ea0
    }
e31ea0
e31ea0
    for(int i = 0; i < 3; ++i) {
e31ea0
        d[i] = v[(i+1)%3] - v[i];
e31ea0
        A[i] = d[i].x*d[i].x + d[i].y*d[i].y;
e31ea0
        B[i] = 2*(d[i].x*v[i].x + d[i].y*v[i].y);
e31ea0
        
e31ea0
        // collision with edge
e31ea0
        Real roots[2];
e31ea0
        int count = solve(roots, C[i], B[i], A[i]);
e31ea0
        for(int j = 0; j < count; ++j)
e31ea0
            if (roots[j] >= -precision && roots[j] <= 1 + precision)
e31ea0
                dist = std::min(dist, d[i].z*roots[j] + v[i].z);
e31ea0
    }
e31ea0
    
e31ea0
    // collision with plane
e31ea0
    Vector3 perp = d[1].cross(d[2]);
e31ea0
    if (perp.z < 0) perp = Vector3(-perp.x, -perp.y, -perp.z);
e31ea0
    if (perp.z > precision) {
e31ea0
        // nearest plane touch point
e31ea0
        Vector3 p(0, 0, perp*v[0]/perp.z);
e31ea0
        Real xy = sqrt(perp.x*perp.x + perp.y*perp.y);
e31ea0
        if (xy > precision) {
e31ea0
            Real dxy = 1/xy;
e31ea0
            p.x = perp.x*dxy;
e31ea0
            p.y = perp.y*dxy;
e31ea0
            p.z -= xy/perp.z;
e31ea0
        }
e31ea0
        
e31ea0
        // is touch point inside tringle
e31ea0
        Real s =  sign( perp.cross(d[0])*(p - v[0]), 0.1*precision );
e31ea0
        if ( s
e31ea0
          && s == sign( perp.cross(d[1])*(p - v[1]), 0.1*precision )
e31ea0
          && s == sign( perp.cross(d[2])*(p - v[2]), 0.1*precision ) )
e31ea0
            dist = std::min(dist, p.z);
e31ea0
    }
e31ea0
    
e31ea0
    return dist;
e31ea0
}