template<class T> Tuple<Vector<T,2>,Vector<T,3>> Triangle<Vector<T,2>>:: closest_point(const Vector<T,2>& location) const { TV closest; Vector<T,3> weights = barycentric_coordinates(location); // project closest point to the triangle if it's not already inside it if(weights.x<0){ T a23=interpolation_fraction(simplex(X[1],X[2]),location); // Check edge X[1]--X[2] if(a23<0){ if(weights.z<0){ // Closest point is on edge X[0]--X[1] T a12=clamp<T>(interpolation_fraction(simplex(X[0],X[1]),location),0,1);weights=Vector<T,3>(1-a12,a12,0);closest=weights.x*X[0]+weights.y*X[1];} else{weights=Vector<T,3>(0,1,0);closest=X[1];}} // Closest point is X[1] else if(a23>1){ if(weights.y<0){ // Closest point is on edge X[0]--X[2] T a13=clamp<T>(interpolation_fraction(simplex(X[0],X[2]),location),0,1);weights=Vector<T,3>(1-a13,0,a13);closest=weights.x*X[0]+weights.z*X[2];} else{weights=Vector<T,3>(0,0,1);closest=X[2];}} // Closest point is X[2] else{weights=Vector<T,3>(0,1-a23,a23);closest=weights.y*X[1]+weights.z*X[2];}} // Closest point is on edge X[1]--X[2] else if(weights.y<0){ T a13=interpolation_fraction(simplex(X[0],X[2]),location); // Check edge X[0]--X[2] if(a13<0){ if(weights.z<0){ // Closest point is on edge X[0]--X[1] T a12=clamp<T>(interpolation_fraction(simplex(X[0],X[1]),location),0,1);weights=Vector<T,3>(1-a12,a12,0);closest=weights.x*X[0]+weights.y*X[1];} else{weights=Vector<T,3>(1,0,0);closest=X[0];}} // Closest point is X[0] else if(a13>1){weights=Vector<T,3>(0,0,1);closest=X[2];} // Closest point is X[2] else{weights=Vector<T,3>(1-a13,0,a13);closest=weights.x*X[0]+weights.z*X[2];}} // Closest point is on edge X[0]--X[2] else if(weights.z<0){ // Closest point is on edge X[0]--X[1] T a12=clamp<T>(interpolation_fraction(simplex(X[0],X[1]),location),0,1);weights=Vector<T,3>(1-a12,a12,0);closest=weights.x*X[0]+weights.y*X[1];} else closest=weights.x*X[0]+weights.y*X[1]+weights.z*X[2]; // Point is interior to the triangle return tuple(closest,weights); }
bool Triangle::intersect(const Ray& r, LocalGeometry& lgeo) { Mat4 TInv = this->transform.inverse(); Vec3 dir = as_vec3(TInv*as_vec4(r.direction)); Vec4 origin = TInv*r.origin; if (cross(dir, normal).is_zero()) return false; double t = dot(as_vec3(origin-A), normal)/dot(dir, normal); if (t < 0.0) return false; else { Vec4 point = origin + (as_vec4(dir) * t); Vec3 bar_coords = barycentric_coordinates(A, B, C, point); double alpha = bar_coords.el(0); double beta = bar_coords.el(1); double gamma = bar_coords.el(2); if (alpha < 0.0 || beta < 0.0 || gamma < 0.0) return false; else { lgeo.normal = submatrix(transform).inverse().transpose() * normal; lgeo.point = transform * point; lgeo.geo = this; return true; } } }
void compute_closest_points(const Vec3d& P, Vec3d& pa, Vec3d& pb){ switch(size_){ //If the simplex has 4 points, it means that the last point added, //most likely lies on the previous simplex, a triangle. We instead //use the last simplex to compute the closest points. case 4:{ const uchar* pos = p_pos[(bits_ ^ (1 << last_sb_))]; const Vec3d& aA = a_[pos[0]]; const Vec3d& aB = a_[pos[1]]; const Vec3d& aC = a_[pos[2]]; const Vec3d& bA = b_[pos[0]]; const Vec3d& bB = b_[pos[1]]; const Vec3d& bC = b_[pos[2]]; const Vec3d& A = p_[pos[0]]; const Vec3d& B = p_[pos[1]]; const Vec3d& C = p_[pos[2]]; auto bary = barycentric_coordinates(P, A, B, C); pa = aA * bary[0] + aB * bary[1] + aC * bary[2]; pb = bA * bary[0] + bB * bary[1] + bC * bary[2]; break; } case 3:{ const uchar* pos = p_pos[(bits_ ^ (1 << last_sb_))]; const Vec3d& aA = a_[last_sb_]; const Vec3d& aB = a_[pos[0]]; const Vec3d& aC = a_[pos[1]]; const Vec3d& bA = b_[last_sb_]; const Vec3d& bB = b_[pos[0]]; const Vec3d& bC = b_[pos[1]]; const Vec3d& A = p_[last_sb_]; const Vec3d& B = p_[pos[0]]; const Vec3d& C = p_[pos[1]]; auto bary = barycentric_coordinates(P, A, B, C); pa = aA * bary[0] + aB * bary[1] + aC * bary[2]; pb = bA * bary[0] + bB * bary[1] + bC * bary[2]; break; } case 2:{ const uchar* pos = p_pos[(bits_ ^ (1 << last_sb_))]; const Vec3d& aA = a_[last_sb_]; const Vec3d& aB = a_[pos[0]]; const Vec3d& bA = b_[last_sb_]; const Vec3d& bB = b_[pos[0]]; double u, v; { const Vec3d& A = p_[last_sb_]; const Vec3d& B = p_[pos[0]]; auto AB = B - A; v = dot(AB, P - A) / AB.length2(); u = 1.0 - v; } pa = aA * u + aB * v; pb = bA * u + bB * v; break; } case 1:{ pa = a_[last_sb_]; pb = b_[last_sb_]; break; } default: break; } }