/*! */ double Segment2D::dist( const Vector2D & p ) const { double len = this->length(); if ( len == 0.0 ) { return origin().dist( p ); } const Vector2D vec = terminal() - origin(); const double prod = vec.innerProduct( p - origin() ); // // A: p1 - p0 // A: p - p0 // // check if 0 <= |B|cos(theta) <= |A| // -> 0 <= |A||b|cos(theta) <= |A|^2 // -> 0 <= A.B <= |A|^2 // A.B = |A||B|cos(theta) // if ( 0.0 <= prod && prod <= len * len ) { // return perpendicular distance //return std::fabs( Triangle2D( *this, p ).doubleSignedArea() / len ); return std::fabs( Triangle2D::double_signed_area( origin(), terminal(), p ) / len ); } return std::sqrt( std::min( origin().dist2( p ), terminal().dist2( p ) ) ); }
/*! */ Vector2D Segment2D::projection( const Vector2D & p ) const { Vector2D dir = terminal() - origin(); double len = dir.r(); if ( len < EPSILON ) { return origin(); } dir /= len; // normalize double d = dir.innerProduct( p - origin() ); if ( -EPSILON < d && d < len + EPSILON ) { dir *= d; return Vector2D( origin() ) += dir; } return Vector2D::INVALIDATED; #if 0 Line2D my_line = this->line(); Vector2D sol = my_line.projection( p ); if ( ! sol.isValid() || ! this->contains( sol ) ) { return Vector2D::INVALIDATED; } return sol; #endif }
/*! */ Vector2D Segment2D::nearestPoint( const Vector2D & p ) const { const Vector2D vec = terminal() - origin(); const double len_square = vec.r2(); if ( len_square == 0.0 ) { return origin(); } double inner_product = vec.innerProduct( (p - origin()) ); // // A: p1 - p0 // B: p - p0 // // check if 0 <= |B|cos(theta) <= |A| // -> 0 <= |A||B|cos(theta) <= |A|^2 // -> 0 <= A.B <= |A|^2 // A.B = |A||B|cos(theta) // if ( inner_product <= 0.0 ) { return origin(); } else if ( inner_product >= len_square ) { return terminal(); } return origin() + vec * inner_product / len_square; }