1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#pragma once


#include <tuple><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include "utility/functional.hpp"

#include "geometry/point.hpp"
#include "geometry/line.hpp"


namespace uni {


template<class Point>
struct segment : line<Point> {
    using point_type = Point;
    using value_type = typename point_type::value_type;

    constexpr segment() noexcept = default;
    constexpr segment(const point_type& p0, const point_type& p1) noexcept(NO_EXCEPT) : line<Point>(p1) { this->_normalize(); }

    constexpr segment(const line<point_type>& ln) noexcept(NO_EXCEPT) : segment(ln.p0(), ln.p1()) {}

    constexpr auto relation(const point_type& p) noexcept(NO_EXCEPT);<--- Derived function 'segment::relation'
};


template<bool ALLOW_END_POINT, class Point>
bool intersecting(const segment<Point>& s0, const segment<Point>& s1) noexcept(NO_EXCEPT) {
    const auto cp0 = cross(s0.p1(), s1.p0(), s0.p0());
    const auto cp1 = cross(s0.p1(), s1.p1(), s0.p0());
    const auto cp2 = cross(s1.p1(), s0.p0(), s1.p0());
    const auto cp3 = cross(s1.p1(), s0.p1(), s1.p0());

    if(compare(cp0) == 0 and compare(cp1) == 0 and compare(cp2) == 0 and compare(cp3) == 0) {
        return std::max(s0.p0(), s1.p0()) <= std::min(s0.p1(), s1.p1());
    }

    if constexpr(ALLOW_END_POINT) return compare(cp0 * cp1) <= 0 and compare(cp2 * cp3) <= 0;
    else return compare(cp0 * cp1) < 0 and compare(cp2 * cp3) < 0;
}

template<class Point>
bool intersecting(const segment<Point>& s0, const segment<Point>& s1) noexcept(NO_EXCEPT) {
    return intersecting<true>(s0, s1);
}


template<class Point>
inline constexpr std::optional<Point> intersection(const segment<Point>& s0, const segment<Point>& s1) noexcept(NO_EXCEPT) {
    if(!intersecting(s0, s1)) return {};
    return intersection(line<Point>(s0), line<Point>(s1));
}


template<class Point>
constexpr auto segment<Point>::relation(const Point& p) noexcept(NO_EXCEPT) {<--- Derived function 'segment < uni :: point < long double > >::relation'
    if(p == this->_p0 or p == this->_p1) return positional_relation::on;

    typename Point::value_type al, bl;
    if(internal::relation(p, *this, &al, &bl) == positional_relation::out) {
        return positional_relation::out;
    };

    const auto comp = compare(al, bl);

    if(comp < 0) return positional_relation::out;
    if(comp > 0) return positional_relation::in;

    assert(false);
}


template<class Point>
double distance(const segment<Point>& s0, const segment<Point> &s1) {
    if(intersecting(s0, s1)) return 0;
    return
        min(
            distance(s0, s1.p0()), distance(s0, s1.p1()),
            distance(s1, s0.p0()), distance(s1, s0.p1())
        );
}

template<class Point>
double squared_distance(const segment<Point>& s0, const segment<Point> &s1) {
    if(intersecting(s0, s1)) return 0;
    return
        min(
            squared_distance(s0, s1.p0()), squared_distance(s0, s1.p1()),
            squared_distance(s1, s0.p0()), squared_distance(s1, s0.p1())
        );
}


template<class Point>
auto distance(const segment<Point>& seg, const Point& p) noexcept(NO_EXCEPT) {
    if(compare(dot(seg.p1(), p, seg.p0())) < 0) return distance(p, seg.p0());
    if(compare(dot(seg.p0(), p, seg.p1())) < 0) return distance(p, seg.p1());
    return distance(line<Point>(seg), p);
}

template<class Point>
inline auto distance(const Point& p, const segment<Point>& seg) noexcept(NO_EXCEPT) { return distance(seg, p); }


template<class Point>
auto squared_distance(const segment<Point>& seg, const Point& p) noexcept(NO_EXCEPT) {
    if(compare(dot(seg.p1(), p, seg.p0())) < 0) return squared_distance(p, seg.p0());
    if(compare(dot(seg.p0(), p, seg.p1())) < 0) return squared_distance(p, seg.p1());
    return squared_distance(line<Point>(seg), p);
}

template<class Point>
inline auto squared_distance(const Point& p, const segment<Point>& seg) noexcept(NO_EXCEPT) { return squared_distance(seg, p); }


} // namespace uni