bool sphere_and_point_collision(const Point &segment_start, const Point &segment_end, double sphere_radius, const Point &point) { check_segment( segment_start, segment_end ); return greater_or_equal( sphere_radius, distance_between_point_and_segment( point, segment_start, segment_end ) ); }
bool is_point_inside_triangle(const Point &point, const Triangle &triangle) { // TODO: check whether the point is in the same plane as triangle. // By now this function returns true if the _projection_ of the point is inside triangle const Vector u = triangle[1] - triangle[0]; const Vector v = triangle[2] - triangle[0]; const Vector r = point - triangle[0]; // find components of r along u and v const double determinant = (u*u)*(v*v) - (u*v)*(u*v); check( determinant != 0, DegeneratedTriangleError() ); const double ru = ( (r*u)*(v*v) - (u*v)*(r*v) ) / determinant; const double rv = ( (u*u)*(r*v) - (r*u)*(u*v) ) / determinant; return greater_or_equal( ru, 0 ) && greater_or_equal( rv, 0 ) && less_or_equal( ru + rv, 1 ); }
/** * \brief Greater than or equal to operator. */ friend bool operator>= (Parent const& lhs, Parent const& rhs) { return greater_or_equal(lhs, rhs); }
bool sphere_and_segment_collision(const Point &sphere_segment_start, const Point &sphere_segment_end, double sphere_radius, const Point &segment_start, const Point &segment_end, /*out*/ Point &collision_point) { check_segment( segment_start, segment_end ); check_segment( sphere_segment_start, sphere_segment_end ); const Vector L_sphere = (sphere_segment_end - sphere_segment_start).normalized(); const Vector L_segment = (segment_end - segment_start).normalized(); Point nearest_on_sphere_way, nearest_on_segment; nearest_points_on_lines( sphere_segment_start, L_sphere, segment_start, L_segment, nearest_on_sphere_way, nearest_on_segment); const double dist = distance( nearest_on_sphere_way, nearest_on_segment ); if( L_sphere.is_collinear_to( L_segment ) ) { // when the sphere is flying in parallel to the line, it's assumed to be no collision return false; } if( greater_or_equal( sphere_radius, dist ) ) { // if distance between lines is less than radius const double perpendicular_length = sqrt( sphere_radius*sphere_radius - dist*dist ); Point result = perpendicular_base( L_sphere, L_segment, nearest_on_segment, perpendicular_length ); // now check that this collision point is inside the segment if( !is_point_between( result, segment_start, segment_end ) ) { return false; } Vector normal; // normal, aimed from L_segment to L_sphere if( L_sphere.is_orthogonal_to(L_segment) ) { normal = - L_sphere.normalized(); } else { const Vector L_segment_other = (result - nearest_on_segment).normalized(); assert( L_segment_other == L_segment || L_segment_other == -L_segment ); // calculating normal, aimed from L_segment to L_sphere as double cross-product. L_segment_other is used instead of L_segment in order to avoid sign mess normal = cross_product( cross_product( L_sphere, L_segment_other ), L_segment_other ).normalized(); } assert( !normal.is_zero() ); Point sphere_center = result + perpendicular_length*normal + (nearest_on_sphere_way - nearest_on_segment); // sphere center is here at the moment of collision // now check that sphere center at the moment of collision is inside the segment if( !is_point_between( sphere_center, sphere_segment_start, sphere_segment_end ) ) { return false; } // all checks passed => there is a collision collision_point = result; return true; } else { // otherwise, sphere flies too far, no collision return false; } }
/** * \brief Greater than or equal to operator. */ FRAMEWORK_ALWAYS_INLINE friend bool operator>= (Parent const& lhs, Parent const& rhs) { return greater_or_equal(lhs, rhs); }