Fishnet 2.0.1
Framework for Graph-Based Analysis of GIS Vector Data
Loading...
Searching...
No Matches
Segment.hpp
Go to the documentation of this file.
1#pragma once
2#include <array>
3#include <algorithm>
4#include "Vec2D.hpp"
5#include "Line.hpp"
6
7namespace fishnet::geometry{
13template<fishnet::math::Number T = fishnet::math::DEFAULT_NUMERIC>
14class Segment{
15private:
16 Vec2D<T> _p;
17 Vec2D<T> _q;
18public:
19
20 using numeric_type = T;
21 constexpr static GeometryType type = GeometryType::SEGMENT;
22
23 constexpr Segment(Vec2D<T> p, Vec2D<T> q):_p(p),_q (q){}
24
25 template<fishnet::math::Number U, typename = std::enable_if_t<!std::is_same_v<U,T> && std::is_same_v<T,fishnet::math::DEFAULT_NUMERIC>>>
26 constexpr Segment(Vec2D<T> p, Vec2D<U> q):Segment(p,Vec2D<T> (q.x ,q.y)){}
27
28 template<fishnet::math::Number U, typename = std::enable_if_t<!std::is_same_v<U,T> && std::is_same_v<T,fishnet::math::DEFAULT_NUMERIC>>>
29 constexpr Segment(Vec2D<U> p, Vec2D<T> q):Segment(Vec2D<T>(p.x ,p.y) ,q){}
30
31 constexpr const Vec2D<T> & p() const noexcept {
32 return _p;
33 }
34
35 constexpr const Vec2D<T> & q() const noexcept {
36 return _q;
37 }
38
39 constexpr Segment<T> flip() const noexcept {
40 return Segment(this->_q,this->_p);
41 }
42
43 constexpr Vec2D<T> direction() const noexcept {
44 return _q-_p;
45 }
46
47 constexpr const Vec2D<T> & upperEndpoint() const noexcept {
48 if (fishnet::math::areEqual(_p.y,_q.y))
49 return _p.x > _q.x ? _p:_q;
50 return _p.y > _q.y ? _p:_q;
51 }
52
53 constexpr const Vec2D<T> & lowerEndpoint() const noexcept {
54 if(fishnet::math::areEqual(_p.y,_q.y))
55 return _p.x < _q.x ? _p:_q;
56 return _p.y < _q.y ? _p:_q;
57 }
58
59 constexpr const Vec2D<T> & leftEndpoint() const noexcept {
60 if(fishnet::math::areEqual(_p.x,_q.x))
61 return _p.y < _q.y ? _p : _q;
62 return _p.x < _q.x ? _p : _q;
63 }
64
65 constexpr const Vec2D<T> & rightEndpoint() const noexcept {
66 if(fishnet::math::areEqual(_p.x,_q.x))
67 return _p.y > _q.y ? _p : _q;
68 return _p.x > _q.x ? _p : _q;
69 }
70
71 constexpr bool isEndpoint(IPoint auto const & point) const noexcept {
72 return _p == point or _q == point;
73 }
74
75 constexpr fishnet::math::DEFAULT_FLOATING_POINT length() const noexcept {
76 return direction().length();
77 }
78
79 constexpr bool isValid() const noexcept{
80 return length() > 0;
81 }
82
83 constexpr Line<T> toLine() const noexcept {
84 return Line<T>(_p,_q);
85 }
86
87 constexpr bool isParallel(LinearGeometry auto const& other)const noexcept{
88 return areParallel(*this,other);
89 }
90
91 constexpr bool intersects(LinearGeometry auto const& other)const noexcept{
92 return intersect(*this,other);
93 }
94
104 constexpr bool overlaps(ISegment auto const & other) const noexcept{
105 return isParallel(other) and (contains(other.p()) or contains(other.q()));
106 }
107
108 constexpr bool contains(ISegment auto const & other) const noexcept {
109 return isParallel(other) and contains(other.p()) and contains(other.q());
110 }
111
121 constexpr bool touches(ISegment auto const & other) const noexcept{
122 return (this->_p == other.p() or this->_p == other.q() or this->_q == other.q() or this->_q == other.p())
123 && not contains(other)
124 && not other.contains(*this);
125 }
126
127 template<fishnet::math::Number U>
128 constexpr bool operator==(const Segment<U> & other) const noexcept {
129 return (this->_p == other.p() and this->_q == other.q()) or (this->_q==other.p() and this->_p == other.q());
130 }
131
132 constexpr bool contains(IPoint auto const & point)const noexcept{
133 using FLOAT_TYPE = fishnet::math::DEFAULT_FLOATING_POINT;
134 auto EPSILON = fishnet::math::EPSILON;
135 if (not isValid()) // 0-length segment
136 return _p==point;
137 auto dir = direction();
138 // lambda is normalised over the segment, so an absolute tolerance on it means EPSILON *
139 // length in coordinate space. On a short segment that shrinks below one ulp of the
140 // coordinates, and this would deny a point which Vec2D::operator== calls equal to the
141 // endpoint. Scaling by the direction keeps the tolerance EPSILON where the points live.
142 if(dir.x == 0){ // vertical segment
143 FLOAT_TYPE lambdaY = FLOAT_TYPE(point.y - _p.y) / FLOAT_TYPE(dir.y); // lambda has to be between in the range [0,1] and the x-Coordinates have to be approx. equal
144 FLOAT_TYPE tolerance = EPSILON / fabs(FLOAT_TYPE(dir.y));
145 return lambdaY >= 0.0 - tolerance and lambdaY <= 1.0 + tolerance and fabs(_p.x - point.x) < EPSILON;
146 }
147 if(dir.y == 0){ // horizontal segment
148 FLOAT_TYPE lambdaX = FLOAT_TYPE(point.x - _p.x) / FLOAT_TYPE(dir.x); // lambda has to be between in the range [0,1] and the y-Coordinates have to be approx. equal
149 FLOAT_TYPE tolerance = EPSILON / fabs(FLOAT_TYPE(dir.x));
150 return lambdaX >= 0.0 - tolerance and lambdaX <= 1.0 + tolerance and fabs(_p.y - point.y) < EPSILON;
151 }
152 FLOAT_TYPE lambdaX = FLOAT_TYPE(point.x - _p.x) / FLOAT_TYPE(dir.x);
153 FLOAT_TYPE lambdaY = FLOAT_TYPE(point.y - _p.y) / FLOAT_TYPE(dir.y);
154 return fabs(lambdaX - lambdaY) < EPSILON and lambdaX >= 0.0 - EPSILON and lambdaY <= 1.0 + EPSILON; // both lambdas have to be equal by definition, so checking one for the range [0,1] is sufficient
155 }
156
157 constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(IPoint auto const & point) const noexcept {
158 auto orthogonalDirection = this->direction().orthogonal();
159 auto orthogonalLine = Line(point, point + orthogonalDirection);
160 auto intersection = this->intersection(orthogonalLine);
161 if(intersection)
162 return point.distance(*intersection); // intersection on the segment of orthogonal line between segment and point
163 return std::min(_p.distance(point), _q.distance(point)); // return closest endpoint of segment to the point otherwise
164 }
165
166 constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(ISegment auto const & other) const noexcept {
167 std::array<fishnet::math::DEFAULT_FLOATING_POINT,4> candidates {
168 other.distance(this->_p),
169 other.distance(this->_q),
170 this->distance(other.p()),
171 this->distance(other.q())
172 };
173 return *std::ranges::min_element(candidates);
174 }
175
176 constexpr fishnet::Option<Vec2DReal> intersection(LinearGeometry auto const& other)const noexcept {
177 return linearIntersection(*this,other);
178 }
179
180 constexpr size_t hash() const noexcept {
181 return this->_p.hash() ^ this->_q.hash();
182 }
183
184 constexpr std::string toString() const noexcept {
185 return "[" + this->_p.toString() +","+this->_q.toString()+"]";
186 }
187};
188static_assert(ISegment<Segment<double>>);
189static_assert(LinearGeometry<Segment<double>>);
190// Explicit template instantiation
191template class Segment<fishnet::math::DEFAULT_NUMERIC>;
192} // namespace fishnet::geometry
Definition Option.hpp:13
Implementation of a line.
Definition Line.hpp:14
Implementation of a segment.
Definition Segment.hpp:14
constexpr const Vec2D< T > & rightEndpoint() const noexcept
Definition Segment.hpp:65
constexpr Line< T > toLine() const noexcept
Definition Segment.hpp:83
constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(ISegment auto const &other) const noexcept
Definition Segment.hpp:166
constexpr bool isValid() const noexcept
Definition Segment.hpp:79
constexpr Segment(Vec2D< T > p, Vec2D< U > q)
Definition Segment.hpp:26
constexpr bool intersects(LinearGeometry auto const &other) const noexcept
Definition Segment.hpp:91
constexpr const Vec2D< T > & p() const noexcept
Definition Segment.hpp:31
constexpr Vec2D< T > direction() const noexcept
Definition Segment.hpp:43
constexpr bool operator==(const Segment< U > &other) const noexcept
Definition Segment.hpp:128
constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(IPoint auto const &point) const noexcept
Definition Segment.hpp:157
constexpr const Vec2D< T > & leftEndpoint() const noexcept
Definition Segment.hpp:59
constexpr const Vec2D< T > & lowerEndpoint() const noexcept
Definition Segment.hpp:53
constexpr const Vec2D< T > & q() const noexcept
Definition Segment.hpp:35
T numeric_type
Definition Segment.hpp:20
constexpr bool isEndpoint(IPoint auto const &point) const noexcept
Definition Segment.hpp:71
constexpr std::string toString() const noexcept
Definition Segment.hpp:184
constexpr bool contains(ISegment auto const &other) const noexcept
Definition Segment.hpp:108
constexpr bool overlaps(ISegment auto const &other) const noexcept
Two Segments have an Overlay if the are contained on the same line: -> the Segments must be parallel ...
Definition Segment.hpp:104
constexpr Segment< T > flip() const noexcept
Definition Segment.hpp:39
constexpr bool touches(ISegment auto const &other) const noexcept
Two Segments touch each other when one endpoint is equal and neither Segment is fully contained in th...
Definition Segment.hpp:121
constexpr fishnet::math::DEFAULT_FLOATING_POINT length() const noexcept
Definition Segment.hpp:75
constexpr bool isParallel(LinearGeometry auto const &other) const noexcept
Definition Segment.hpp:87
constexpr bool contains(IPoint auto const &point) const noexcept
Definition Segment.hpp:132
static constexpr GeometryType type
Definition Segment.hpp:21
constexpr const Vec2D< T > & upperEndpoint() const noexcept
Definition Segment.hpp:47
constexpr fishnet::Option< Vec2DReal > intersection(LinearGeometry auto const &other) const noexcept
Definition Segment.hpp:176
constexpr Segment(Vec2D< U > p, Vec2D< T > q)
Definition Segment.hpp:29
constexpr size_t hash() const noexcept
Definition Segment.hpp:180
constexpr Segment(Vec2D< T > p, Vec2D< T > q)
Definition Segment.hpp:23
Implementation of a two-dimensional vector.
Definition Vec2D.hpp:16
T y
Definition Vec2D.hpp:21
T x
Definition Vec2D.hpp:20
constexpr fishnet::math::DEFAULT_FLOATING_POINT length() const
Definition Vec2D.hpp:142
constexpr size_t hash() const noexcept
Definition Vec2D.hpp:179
constexpr std::string toString() const noexcept
Definition Vec2D.hpp:185
constexpr fishnet::math::DEFAULT_FLOATING_POINT distance(const IPoint auto &other) const
Definition Vec2D.hpp:146
constexpr Vec2D< T > orthogonal() const noexcept
Definition Vec2D.hpp:150
Interface for a point.
Definition IPoint.hpp:92
Interface for a segment A segment is formed between two points p and q, containing only the points on...
Definition ISegment.hpp:105
Definition IGeometry.hpp:13
Definition BoundingBoxWrapper.hpp:5
static constexpr fishnet::Option< Vec2DReal > linearIntersection(ILine auto const &l, ILine auto const &r) noexcept
Computation of line intersection.
Definition LinearIntersection.hpp:15
static constexpr bool areParallel(LinearGeometry auto const &lhs, LinearGeometry auto const &rhs) noexcept
Definition LinearIntersection.hpp:41
static constexpr bool intersect(LinearGeometry auto const &lhs, LinearGeometry auto const &rhs) noexcept
Definition LinearIntersection.hpp:45
GeometryType
Definition GeometryBase.hpp:6
constexpr bool areEqual(T lhs, U rhs) noexcept
Definition Constants.hpp:31
static constexpr DEFAULT_FLOATING_POINT EPSILON
Definition Constants.hpp:20
double DEFAULT_FLOATING_POINT
Definition NumericConcepts.hpp:12