// Copyright (C) 2018 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_LInE_H_ #define DLIB_LInE_H_ #include "line_abstract.h" #include "vector.h" #include #include "../numeric_constants.h" #include namespace dlib { // ---------------------------------------------------------------------------------------- class line { public: line() = default; line(const dpoint& a, const dpoint& b) : end1(a), end2(b) { normal_vector = (end1-end2).cross(dlib::vector(0,0,1)).normalize(); } template line(const std::pair,vector>& l) : line(l.first, l.second) {} const dpoint& p1() const { return end1; } const dpoint& p2() const { return end2; } const dpoint& normal() const { return normal_vector; } private: dpoint end1; dpoint end2; dpoint normal_vector; }; // ---------------------------------------------------------------------------------------- template double signed_distance_to_line ( const line& l, const vector& p ) { return dot(p-l.p1(), l.normal()); } template double signed_distance_to_line ( const std::pair,vector >& l, const vector& p ) { return signed_distance_to_line(line(l),p); } template double distance_to_line ( const std::pair,vector >& l, const vector& p ) { return std::abs(signed_distance_to_line(l,p)); } template double distance_to_line ( const line& l, const vector& p ) { return std::abs(signed_distance_to_line(l,p)); } // ---------------------------------------------------------------------------------------- inline line reverse(const line& l) { return line(l.p2(), l.p1()); } // ---------------------------------------------------------------------------------------- template inline dpoint intersect( const std::pair,vector>& a, const std::pair,vector>& b ) { // convert to homogeneous coordinates dlib::vector a1 = a.first; dlib::vector a2 = a.second; dlib::vector b1 = b.first; dlib::vector b2 = b.second; a1.z() = 1; a2.z() = 1; b1.z() = 1; b2.z() = 1; // find lines between pairs of points. auto l1 = a1.cross(a2); auto l2 = b1.cross(b2); // find intersection of the lines. auto p = l1.cross(l2); if (p.z() != 0) return p/p.z(); else return dpoint(std::numeric_limits::infinity(), std::numeric_limits::infinity()); } // ---------------------------------------------------------------------------------------- inline dpoint intersect( const line& a, const line& b ) { return intersect(std::make_pair(a.p1(),a.p2()), std::make_pair(b.p1(), b.p2())); } // ---------------------------------------------------------------------------------------- template inline size_t count_points_on_side_of_line( line l, const dpoint& reference_point, const std::vector>& pts, const double& dist_thresh_min = 0, const double& dist_thresh_max = std::numeric_limits::infinity() ) { if (signed_distance_to_line(l,reference_point) < 0) l = reverse(l); size_t cnt = 0; for (auto& p : pts) { double dist = signed_distance_to_line(l,p); if (dist_thresh_min <= dist && dist <= dist_thresh_max) ++cnt; } return cnt; } // ---------------------------------------------------------------------------------------- template inline double count_points_between_lines( line l1, line l2, const dpoint& reference_point, const std::vector>& pts ) { if (signed_distance_to_line(l1,reference_point) < 0) l1 = reverse(l1); if (signed_distance_to_line(l2,reference_point) < 0) l2 = reverse(l2); size_t cnt = 0; for (auto& p : pts) { if (signed_distance_to_line(l1,p) > 0 && signed_distance_to_line(l2,p) > 0) ++cnt; } return cnt; } // ---------------------------------------------------------------------------------------- inline double angle_between_lines ( const line& a, const line& b ) { auto tmp = put_in_range(0.0, 1.0, std::abs(dot(a.normal(),b.normal()))); return std::acos(tmp)*180/pi; } // ---------------------------------------------------------------------------------------- struct no_convex_quadrilateral : dlib::error { no_convex_quadrilateral() : dlib::error("Lines given to find_convex_quadrilateral() don't form any convex quadrilateral.") {} }; inline std::array find_convex_quadrilateral ( const std::array& lines ) { const dpoint v01 = intersect(lines[0],lines[1]); const dpoint v02 = intersect(lines[0],lines[2]); const dpoint v03 = intersect(lines[0],lines[3]); const dpoint v12 = intersect(lines[1],lines[2]); const dpoint v13 = intersect(lines[1],lines[3]); const dpoint v23 = intersect(lines[2],lines[3]); const auto& v10 = v01; const auto& v20 = v02; const auto& v30 = v03; const auto& v21 = v12; const auto& v31 = v13; const auto& v32 = v23; if (is_convex_quadrilateral({{v01, v12, v23, v30}})) return {{v01, v12, v23, v30}}; if (is_convex_quadrilateral({{v01, v13, v32, v20}})) return {{v01, v13, v32, v20}}; if (is_convex_quadrilateral({{v02, v23, v31, v10}})) return {{v02, v23, v31, v10}}; if (is_convex_quadrilateral({{v02, v21, v13, v30}})) return {{v02, v21, v13, v30}}; if (is_convex_quadrilateral({{v03, v32, v21, v10}})) return {{v03, v32, v21, v10}}; if (is_convex_quadrilateral({{v03, v31, v12, v20}})) return {{v03, v31, v12, v20}}; throw no_convex_quadrilateral(); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_LInE_H_