|
|
|
|
|
#ifndef DLIB_LInE_H_ |
|
#define DLIB_LInE_H_ |
|
|
|
#include "line_abstract.h" |
|
#include "vector.h" |
|
#include <utility> |
|
#include "../numeric_constants.h" |
|
#include <array> |
|
|
|
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<double,3>(0,0,1)).normalize(); |
|
} |
|
|
|
template <typename T> |
|
line(const std::pair<vector<T,2>,vector<T,2>>& 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 <typename U> |
|
double signed_distance_to_line ( |
|
const line& l, |
|
const vector<U,2>& p |
|
) |
|
{ |
|
return dot(p-l.p1(), l.normal()); |
|
} |
|
|
|
template <typename T, typename U> |
|
double signed_distance_to_line ( |
|
const std::pair<vector<T,2>,vector<T,2> >& l, |
|
const vector<U,2>& p |
|
) |
|
{ |
|
return signed_distance_to_line(line(l),p); |
|
} |
|
|
|
template <typename T, typename U> |
|
double distance_to_line ( |
|
const std::pair<vector<T,2>,vector<T,2> >& l, |
|
const vector<U,2>& p |
|
) |
|
{ |
|
return std::abs(signed_distance_to_line(l,p)); |
|
} |
|
|
|
template <typename U> |
|
double distance_to_line ( |
|
const line& l, |
|
const vector<U,2>& p |
|
) |
|
{ |
|
return std::abs(signed_distance_to_line(l,p)); |
|
} |
|
|
|
|
|
|
|
inline line reverse(const line& l) |
|
{ |
|
return line(l.p2(), l.p1()); |
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
inline dpoint intersect( |
|
const std::pair<vector<T,2>,vector<T,2>>& a, |
|
const std::pair<vector<T,2>,vector<T,2>>& b |
|
) |
|
{ |
|
|
|
dlib::vector<double,3> a1 = a.first; |
|
dlib::vector<double,3> a2 = a.second; |
|
dlib::vector<double,3> b1 = b.first; |
|
dlib::vector<double,3> b2 = b.second; |
|
a1.z() = 1; |
|
a2.z() = 1; |
|
b1.z() = 1; |
|
b2.z() = 1; |
|
|
|
|
|
auto l1 = a1.cross(a2); |
|
auto l2 = b1.cross(b2); |
|
|
|
|
|
auto p = l1.cross(l2); |
|
|
|
if (p.z() != 0) |
|
return p/p.z(); |
|
else |
|
return dpoint(std::numeric_limits<double>::infinity(), std::numeric_limits<double>::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 <typename T> |
|
inline size_t count_points_on_side_of_line( |
|
line l, |
|
const dpoint& reference_point, |
|
const std::vector<vector<T,2>>& pts, |
|
const double& dist_thresh_min = 0, |
|
const double& dist_thresh_max = std::numeric_limits<double>::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 <typename T> |
|
inline double count_points_between_lines( |
|
line l1, |
|
line l2, |
|
const dpoint& reference_point, |
|
const std::vector<vector<T,2>>& 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<dpoint,4> find_convex_quadrilateral ( |
|
const std::array<line,4>& 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 |
|
|
|
|