| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** @file | ||
| 2 | * @brief Cartesian point / 2D vector and related operations | ||
| 3 | *//* | ||
| 4 | * Authors: | ||
| 5 | * Michael G. Sloan <mgsloan@gmail.com> | ||
| 6 | * Nathan Hurst <njh@njhurst.com> | ||
| 7 | * Krzysztof KosiĆski <tweenk.pl@gmail.com> | ||
| 8 | * | ||
| 9 | * Copyright (C) 2006-2009 Authors | ||
| 10 | * | ||
| 11 | * This library is free software; you can redistribute it and/or | ||
| 12 | * modify it either under the terms of the GNU Lesser General Public | ||
| 13 | * License version 2.1 as published by the Free Software Foundation | ||
| 14 | * (the "LGPL") or, at your option, under the terms of the Mozilla | ||
| 15 | * Public License Version 1.1 (the "MPL"). If you do not alter this | ||
| 16 | * notice, a recipient may use your version of this file under either | ||
| 17 | * the MPL or the LGPL. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the LGPL along with this library | ||
| 20 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | * You should have received a copy of the MPL along with this library | ||
| 23 | * in the file COPYING-MPL-1.1 | ||
| 24 | * | ||
| 25 | * The contents of this file are subject to the Mozilla Public License | ||
| 26 | * Version 1.1 (the "License"); you may not use this file except in | ||
| 27 | * compliance with the License. You may obtain a copy of the License at | ||
| 28 | * http://www.mozilla.org/MPL/ | ||
| 29 | * | ||
| 30 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY | ||
| 31 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for | ||
| 32 | * the specific language governing rights and limitations. | ||
| 33 | */ | ||
| 34 | |||
| 35 | #ifndef LIB2GEOM_SEEN_POINT_H | ||
| 36 | #define LIB2GEOM_SEEN_POINT_H | ||
| 37 | |||
| 38 | #include <cassert> | ||
| 39 | #include <iostream> | ||
| 40 | #include <iterator> | ||
| 41 | #include <tuple> | ||
| 42 | #include <boost/functional/hash.hpp> | ||
| 43 | #include <boost/operators.hpp> | ||
| 44 | #include <2geom/forward.h> | ||
| 45 | #include <2geom/coord.h> | ||
| 46 | #include <2geom/int-point.h> | ||
| 47 | #include <2geom/math-utils.h> | ||
| 48 | #include <2geom/utils.h> | ||
| 49 | |||
| 50 | namespace Geom { | ||
| 51 | |||
| 52 | class Point | ||
| 53 | : boost::additive< Point | ||
| 54 | , boost::totally_ordered< Point | ||
| 55 | , boost::multiplicative< Point, Coord | ||
| 56 | , boost::multiplicative< Point | ||
| 57 | , boost::multiplicative< Point, IntPoint | ||
| 58 | , MultipliableNoncommutative< Point, Affine | ||
| 59 | , MultipliableNoncommutative< Point, Translate | ||
| 60 | , MultipliableNoncommutative< Point, Rotate | ||
| 61 | , MultipliableNoncommutative< Point, Scale | ||
| 62 | , MultipliableNoncommutative< Point, HShear | ||
| 63 | , MultipliableNoncommutative< Point, VShear | ||
| 64 | , MultipliableNoncommutative< Point, Zoom | ||
| 65 | >>>>>>>>>>>> // base class chaining, see documentation for Boost.Operator | ||
| 66 | { | ||
| 67 | Coord _pt[2] = { 0, 0 }; | ||
| 68 | public: | ||
| 69 | using D1Value = Coord; | ||
| 70 | using D1Reference = Coord &; | ||
| 71 | using D1ConstReference = Coord const &; | ||
| 72 | |||
| 73 | /// @name Create points | ||
| 74 | /// @{ | ||
| 75 | /** Construct a point at the origin. */ | ||
| 76 | 6709890 | constexpr Point() = default; | |
| 77 | /** Construct a point from its coordinates. */ | ||
| 78 | 5327826 | constexpr Point(Coord x, Coord y) | |
| 79 | 5327826 | : _pt{ x, y } | |
| 80 | 5327826 | {} | |
| 81 | /** Construct from integer point. */ | ||
| 82 | constexpr Point(IntPoint const &p) | ||
| 83 | : Point(p[X], p[Y]) | ||
| 84 | {} | ||
| 85 | /** @brief Construct a point from its polar coordinates. | ||
| 86 | * The angle is specified in radians, in the mathematical convention (increasing | ||
| 87 | * counter-clockwise from +X). */ | ||
| 88 | static Point polar(Coord angle, Coord radius) { | ||
| 89 | return polar(angle) * radius; | ||
| 90 | } | ||
| 91 | /** @brief Construct an unit vector from its angle. | ||
| 92 | * The angle is specified in radians, in the mathematical convention (increasing | ||
| 93 | * counter-clockwise from +X). */ | ||
| 94 | static Point polar(Coord angle); | ||
| 95 | /// @} | ||
| 96 | |||
| 97 | /// @name Access the coordinates of a point | ||
| 98 | /// @{ | ||
| 99 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8092860 times.
|
8092860 | Coord operator[](unsigned i) const { assert(i < 2); return _pt[i]; } |
| 100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15184452 times.
|
15184452 | Coord &operator[](unsigned i) { assert(i < 2); return _pt[i]; } |
| 101 | 241450088 | constexpr Coord operator[](Dim2 d) const noexcept { return _pt[d]; } | |
| 102 | 748539 | constexpr Coord &operator[](Dim2 d) noexcept { return _pt[d]; } | |
| 103 | |||
| 104 | 216 | constexpr Coord x() const noexcept { return _pt[X]; } | |
| 105 | 3 | constexpr Coord &x() noexcept { return _pt[X]; } | |
| 106 | 80 | constexpr Coord y() const noexcept { return _pt[Y]; } | |
| 107 | 102 | constexpr Coord &y() noexcept { return _pt[Y]; } | |
| 108 | |||
| 109 | // Structured binding support | ||
| 110 | template <size_t I> constexpr Coord get() const { static_assert(I < 2); return _pt[I]; } | ||
| 111 | template <size_t I> constexpr Coord &get() { static_assert(I < 2); return _pt[I]; } | ||
| 112 | /// @} | ||
| 113 | |||
| 114 | /// @name Vector operations | ||
| 115 | /// @{ | ||
| 116 | /** @brief Compute the distance from origin. | ||
| 117 | * @return Length of the vector from origin to this point */ | ||
| 118 | 10566246 | Coord length() const { return std::hypot(_pt[X], _pt[Y]); } | |
| 119 | 2388 | constexpr Coord lengthSq() const { return _pt[X] * _pt[X] + _pt[Y] * _pt[Y]; } | |
| 120 | void normalize(); | ||
| 121 | 20128 | Point normalized() const { | |
| 122 | 20128 | auto ret = *this; | |
| 123 |
1/2✓ Branch 1 taken 20128 times.
✗ Branch 2 not taken.
|
20128 | ret.normalize(); |
| 124 | 20128 | return ret; | |
| 125 | } | ||
| 126 | |||
| 127 | /** @brief Return a point like this point but rotated -90 degrees. | ||
| 128 | * If the y axis grows downwards and the x axis grows to the | ||
| 129 | * right, then this is 90 degrees counter-clockwise. */ | ||
| 130 | ✗ | constexpr Point ccw() const { | |
| 131 | ✗ | return Point(_pt[Y], -_pt[X]); | |
| 132 | } | ||
| 133 | |||
| 134 | /** @brief Return a point like this point but rotated +90 degrees. | ||
| 135 | * If the y axis grows downwards and the x axis grows to the | ||
| 136 | * right, then this is 90 degrees clockwise. */ | ||
| 137 | 27487 | constexpr Point cw() const { | |
| 138 | 27487 | return Point(-_pt[Y], _pt[X]); | |
| 139 | } | ||
| 140 | /// @} | ||
| 141 | |||
| 142 | /// @name Vector-like arithmetic operations | ||
| 143 | /// @{ | ||
| 144 | 603178 | constexpr Point operator-() const { | |
| 145 | 603178 | return Point(-_pt[X], -_pt[Y]); | |
| 146 | } | ||
| 147 | 64328421 | constexpr Point &operator+=(Point const &o) { | |
| 148 | 64328421 | _pt[X] += o._pt[X]; | |
| 149 | 64328421 | _pt[Y] += o._pt[Y]; | |
| 150 | 64328421 | return *this; | |
| 151 | } | ||
| 152 | 53191665 | constexpr Point &operator-=(Point const &o) { | |
| 153 | 53191665 | _pt[X] -= o._pt[X]; | |
| 154 | 53191665 | _pt[Y] -= o._pt[Y]; | |
| 155 | 53191665 | return *this; | |
| 156 | } | ||
| 157 | 130560333 | constexpr Point &operator*=(Coord s) { | |
| 158 |
2/2✓ Branch 0 taken 261120666 times.
✓ Branch 1 taken 130560333 times.
|
391680999 | for (auto &i : _pt) i *= s; |
| 159 | 130560333 | return *this; | |
| 160 | } | ||
| 161 | constexpr Point &operator*=(Point const &o) { | ||
| 162 | _pt[X] *= o._pt[X]; | ||
| 163 | _pt[Y] *= o._pt[Y]; | ||
| 164 | return *this; | ||
| 165 | } | ||
| 166 | constexpr Point &operator*=(IntPoint const &o) { | ||
| 167 | _pt[X] *= o.x(); | ||
| 168 | _pt[Y] *= o.y(); | ||
| 169 | return *this; | ||
| 170 | } | ||
| 171 | 1595586 | constexpr Point &operator/=(Coord s) { | |
| 172 |
2/2✓ Branch 0 taken 3191172 times.
✓ Branch 1 taken 1595586 times.
|
4786758 | for (auto &i : _pt) i /= s; |
| 173 | 1595586 | return *this; | |
| 174 | } | ||
| 175 | constexpr Point &operator/=(Point const &o) { | ||
| 176 | _pt[X] /= o._pt[X]; | ||
| 177 | _pt[Y] /= o._pt[Y]; | ||
| 178 | return *this; | ||
| 179 | } | ||
| 180 | constexpr Point &operator/=(IntPoint const &o) { | ||
| 181 | _pt[X] /= o.x(); | ||
| 182 | _pt[Y] /= o.y(); | ||
| 183 | return *this; | ||
| 184 | } | ||
| 185 | /// @} | ||
| 186 | |||
| 187 | /// @name Affine transformations | ||
| 188 | /// @{ | ||
| 189 | Point &operator*=(Affine const &m); | ||
| 190 | // implemented in transforms.cpp | ||
| 191 | Point &operator*=(Translate const &t); | ||
| 192 | Point &operator*=(Scale const &s); | ||
| 193 | Point &operator*=(Rotate const &r); | ||
| 194 | Point &operator*=(HShear const &s); | ||
| 195 | Point &operator*=(VShear const &s); | ||
| 196 | Point &operator*=(Zoom const &z); | ||
| 197 | /// @} | ||
| 198 | |||
| 199 | /// @name Conversion to integer points | ||
| 200 | /// @{ | ||
| 201 | /** @brief Round to nearest integer coordinates. */ | ||
| 202 | ✗ | IntPoint round() const { | |
| 203 | ✗ | return IntPoint(::round(_pt[X]), ::round(_pt[Y])); | |
| 204 | } | ||
| 205 | /** @brief Round coordinates downwards. */ | ||
| 206 | IntPoint floor() const { | ||
| 207 | return IntPoint(::floor(_pt[X]), ::floor(_pt[Y])); | ||
| 208 | } | ||
| 209 | /** @brief Round coordinates upwards. */ | ||
| 210 | IntPoint ceil() const { | ||
| 211 | return IntPoint(::ceil(_pt[X]), ::ceil(_pt[Y])); | ||
| 212 | } | ||
| 213 | /// @} | ||
| 214 | |||
| 215 | /// @name Various utilities | ||
| 216 | /// @{ | ||
| 217 | /** @brief Check whether both coordinates are finite. */ | ||
| 218 | bool isFinite() const { | ||
| 219 | for (auto i : _pt) { | ||
| 220 | if (!std::isfinite(i)) { | ||
| 221 | return false; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | return true; | ||
| 225 | } | ||
| 226 | /** @brief Check whether both coordinates are zero. */ | ||
| 227 | 760200 | constexpr bool isZero() const { | |
| 228 |
3/4✓ Branch 0 taken 150107 times.
✓ Branch 1 taken 610093 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 150107 times.
|
760200 | return _pt[X] == 0 && _pt[Y] == 0; |
| 229 | } | ||
| 230 | /** @brief Check whether the length of the vector is close to 1. */ | ||
| 231 | bool isNormalized(Coord eps = EPSILON) const { | ||
| 232 | return are_near(length(), 1.0, eps); | ||
| 233 | } | ||
| 234 | /** @brief Equality operator. | ||
| 235 | * This tests for exact identity (as opposed to are_near()). Note that due to numerical | ||
| 236 | * errors, this test might return false even if the points should be identical. */ | ||
| 237 | 5104743 | constexpr bool operator==(Point const &p) const { | |
| 238 |
4/4✓ Branch 1 taken 4343264 times.
✓ Branch 2 taken 761479 times.
✓ Branch 4 taken 3875199 times.
✓ Branch 5 taken 468065 times.
|
5104743 | return _pt[X] == p[X] && _pt[Y] == p[Y]; |
| 239 | } | ||
| 240 | /** @brief Lexicographical ordering for points. | ||
| 241 | * Y coordinate is regarded as more significant. When sorting according to this | ||
| 242 | * ordering, the points will be sorted according to the Y coordinate, and within | ||
| 243 | * points with the same Y coordinate according to the X coordinate. */ | ||
| 244 | ✗ | constexpr bool operator<(Point const &p) const { | |
| 245 | ✗ | return _pt[Y] < p[Y] || (_pt[Y] == p[Y] && _pt[X] < p[X]); | |
| 246 | } | ||
| 247 | /// @} | ||
| 248 | |||
| 249 | /** @brief Lexicographical ordering functor. | ||
| 250 | * @param d The dimension with higher significance */ | ||
| 251 | template <Dim2 DIM> struct LexLess; | ||
| 252 | template <Dim2 DIM> struct LexGreater; | ||
| 253 | //template <Dim2 DIM, typename First = std::less<Coord>, typename Second = std::less<Coord> > LexOrder; | ||
| 254 | /** @brief Lexicographical ordering functor with runtime dimension. */ | ||
| 255 | struct LexLessRt { | ||
| 256 | LexLessRt(Dim2 d) : dim(d) {} | ||
| 257 | inline bool operator()(Point const &a, Point const &b) const; | ||
| 258 | private: | ||
| 259 | Dim2 dim; | ||
| 260 | }; | ||
| 261 | struct LexGreaterRt { | ||
| 262 | LexGreaterRt(Dim2 d) : dim(d) {} | ||
| 263 | inline bool operator()(Point const &a, Point const &b) const; | ||
| 264 | private: | ||
| 265 | Dim2 dim; | ||
| 266 | }; | ||
| 267 | }; | ||
| 268 | |||
| 269 | /** @brief Output operator for points. | ||
| 270 | * Prints out the coordinates. | ||
| 271 | * @relates Point */ | ||
| 272 | std::ostream &operator<<(std::ostream &out, Point const &p); | ||
| 273 | |||
| 274 | template<> struct Point::LexLess<X> { | ||
| 275 | typedef std::less<Coord> Primary; | ||
| 276 | typedef std::less<Coord> Secondary; | ||
| 277 | typedef std::less<Coord> XOrder; | ||
| 278 | typedef std::less<Coord> YOrder; | ||
| 279 | 10021 | bool operator()(Point const &a, Point const &b) const { | |
| 280 |
6/6✓ Branch 2 taken 7382 times.
✓ Branch 3 taken 2639 times.
✓ Branch 6 taken 511 times.
✓ Branch 7 taken 6871 times.
✓ Branch 10 taken 281 times.
✓ Branch 11 taken 230 times.
|
10021 | return a[X] < b[X] || (a[X] == b[X] && a[Y] < b[Y]); |
| 281 | } | ||
| 282 | }; | ||
| 283 | template<> struct Point::LexLess<Y> { | ||
| 284 | typedef std::less<Coord> Primary; | ||
| 285 | typedef std::less<Coord> Secondary; | ||
| 286 | typedef std::less<Coord> XOrder; | ||
| 287 | typedef std::less<Coord> YOrder; | ||
| 288 | bool operator()(Point const &a, Point const &b) const { | ||
| 289 | return a[Y] < b[Y] || (a[Y] == b[Y] && a[X] < b[X]); | ||
| 290 | } | ||
| 291 | }; | ||
| 292 | template<> struct Point::LexGreater<X> { | ||
| 293 | typedef std::greater<Coord> Primary; | ||
| 294 | typedef std::greater<Coord> Secondary; | ||
| 295 | typedef std::greater<Coord> XOrder; | ||
| 296 | typedef std::greater<Coord> YOrder; | ||
| 297 | 2824 | bool operator()(Point const &a, Point const &b) const { | |
| 298 |
6/6✓ Branch 2 taken 1431 times.
✓ Branch 3 taken 1393 times.
✓ Branch 6 taken 363 times.
✓ Branch 7 taken 1068 times.
✓ Branch 10 taken 133 times.
✓ Branch 11 taken 230 times.
|
2824 | return a[X] > b[X] || (a[X] == b[X] && a[Y] > b[Y]); |
| 299 | } | ||
| 300 | }; | ||
| 301 | template<> struct Point::LexGreater<Y> { | ||
| 302 | typedef std::greater<Coord> Primary; | ||
| 303 | typedef std::greater<Coord> Secondary; | ||
| 304 | typedef std::greater<Coord> XOrder; | ||
| 305 | typedef std::greater<Coord> YOrder; | ||
| 306 | bool operator()(Point const &a, Point const &b) const { | ||
| 307 | return a[Y] > b[Y] || (a[Y] == b[Y] && a[X] > b[X]); | ||
| 308 | } | ||
| 309 | }; | ||
| 310 | inline bool Point::LexLessRt::operator()(Point const &a, Point const &b) const { | ||
| 311 | return dim ? Point::LexLess<Y>()(a, b) : Point::LexLess<X>()(a, b); | ||
| 312 | } | ||
| 313 | inline bool Point::LexGreaterRt::operator()(Point const &a, Point const &b) const { | ||
| 314 | return dim ? Point::LexGreater<Y>()(a, b) : Point::LexGreater<X>()(a, b); | ||
| 315 | } | ||
| 316 | |||
| 317 | /** @brief Compute the second (Euclidean) norm of @a p. | ||
| 318 | * This corresponds to the length of @a p. The result will not overflow even if | ||
| 319 | * \f$p_X^2 + p_Y^2\f$ is larger that the maximum value that can be stored | ||
| 320 | * in a <code>double</code>. | ||
| 321 | * @return \f$\sqrt{p_X^2 + p_Y^2}\f$ | ||
| 322 | * @relates Point */ | ||
| 323 | 4 | inline Coord L2(Point const &p) { | |
| 324 | 4 | return p.length(); | |
| 325 | } | ||
| 326 | |||
| 327 | /** @brief Compute the square of the Euclidean norm of @a p. | ||
| 328 | * Warning: this can overflow where L2 won't. | ||
| 329 | * @return \f$p_X^2 + p_Y^2\f$ | ||
| 330 | * @relates Point */ | ||
| 331 | 1845 | constexpr Coord L2sq(Point const &p) { | |
| 332 | 1845 | return p.lengthSq(); | |
| 333 | } | ||
| 334 | |||
| 335 | /** @brief Returns p * Geom::rotate_degrees(90), but more efficient. | ||
| 336 | * | ||
| 337 | * Angle direction in 2Geom: If you use the traditional mathematics convention that y | ||
| 338 | * increases upwards, then positive angles are anticlockwise as per the mathematics convention. If | ||
| 339 | * you take the common non-mathematical convention that y increases downwards, then positive angles | ||
| 340 | * are clockwise, as is common outside of mathematics. | ||
| 341 | * | ||
| 342 | * There is no function to rotate by -90 degrees: use -rot90(p) instead. | ||
| 343 | * @relates Point */ | ||
| 344 | 36000 | constexpr Point rot90(Point const &p) { | |
| 345 | 36000 | return Point(-p[Y], p[X]); | |
| 346 | } | ||
| 347 | |||
| 348 | /** @brief Linear interpolation between two points. | ||
| 349 | * @param t Time value | ||
| 350 | * @param a First point | ||
| 351 | * @param b Second point | ||
| 352 | * @return Point on a line between a and b. The ratio of its distance from a | ||
| 353 | * and the distance between a and b will be equal to t. | ||
| 354 | * @relates Point */ | ||
| 355 | 142123 | inline Point lerp(Coord t, Point const &a, Point const &b) { | |
| 356 | 142123 | return (1 - t) * a + t * b; | |
| 357 | } | ||
| 358 | |||
| 359 | /** @brief Return a point halfway between the specified ones. | ||
| 360 | * @relates Point */ | ||
| 361 | 91867 | inline Point middle_point(Point const &p1, Point const &p2) { | |
| 362 | 91867 | return lerp(0.5, p1, p2); | |
| 363 | } | ||
| 364 | |||
| 365 | /** @brief Compute the dot product of a and b. | ||
| 366 | * Dot product can be interpreted as a measure of how parallel the vectors are. | ||
| 367 | * For perpendicular vectors, it is zero. For parallel ones, its absolute value is highest, | ||
| 368 | * and the sign depends on whether they point in the same direction (+) or opposite ones (-). | ||
| 369 | * @return \f$a \cdot b = a_X b_X + a_Y b_Y\f$. | ||
| 370 | * @relates Point */ | ||
| 371 | 55287253 | constexpr Coord dot(Point const &a, Point const &b) { | |
| 372 | 55287253 | return a[X] * b[X] + a[Y] * b[Y]; | |
| 373 | } | ||
| 374 | |||
| 375 | /** @brief Compute the 2D cross product. | ||
| 376 | * This is also known as "perp dot product". It will be zero for parallel vectors, | ||
| 377 | * and the absolute value will be highest for perpendicular vectors. | ||
| 378 | * @return \f$a \times b = a_X b_Y - a_Y b_X\f$. | ||
| 379 | * @relates Point*/ | ||
| 380 | 1074145 | constexpr Coord cross(Point const &a, Point const &b) | |
| 381 | { | ||
| 382 | // equivalent implementation: | ||
| 383 | // return dot(a, b.ccw()); | ||
| 384 | 1074145 | return a[X] * b[Y] - a[Y] * b[X]; | |
| 385 | } | ||
| 386 | |||
| 387 | /// Compute the (Euclidean) distance between points. | ||
| 388 | /// @relates Point | ||
| 389 | 10696124 | inline Coord distance(Point const &a, Point const &b) { | |
| 390 | 10696124 | return (a - b).length(); | |
| 391 | } | ||
| 392 | |||
| 393 | /// Compute the square of the distance between points. | ||
| 394 | /// @relates Point | ||
| 395 | 158 | inline Coord distanceSq(Point const &a, Point const &b) { | |
| 396 | 158 | return L2sq(a - b); | |
| 397 | } | ||
| 398 | |||
| 399 | //IMPL: NearConcept | ||
| 400 | /// Test whether two points are no further apart than some threshold. | ||
| 401 | /// @relates Point | ||
| 402 | ✗ | inline bool are_near(Point const &a, Point const &b, double eps = EPSILON) { | |
| 403 | // do not use an unqualified calls to distance before the empty | ||
| 404 | // specialization of iterator_traits is defined - see end of file | ||
| 405 | ✗ | return are_near((a - b).length(), 0, eps); | |
| 406 | } | ||
| 407 | |||
| 408 | /// Test whether the relative distance between two points is less than some threshold. | ||
| 409 | 30074 | inline bool are_near_rel(Point const &a, Point const &b, double eps = EPSILON) { | |
| 410 | 30074 | return (a - b).length() <= eps * (a.length() + b.length()) / 2; | |
| 411 | } | ||
| 412 | |||
| 413 | /// Test whether three points lie approximately on the same line. | ||
| 414 | /// @relates Point | ||
| 415 | ✗ | inline bool are_collinear(Point const &p1, Point const &p2, Point const &p3, | |
| 416 | double eps = EPSILON) | ||
| 417 | { | ||
| 418 | ✗ | return are_near(cross(p1, p2) + cross(p2, p3) + cross(p3, p1), 0, eps); | |
| 419 | } | ||
| 420 | |||
| 421 | Point unit_vector(Point const &a); | ||
| 422 | Coord L1(Point const &p); | ||
| 423 | Coord LInfty(Point const &p); | ||
| 424 | bool is_zero(Point const &p); | ||
| 425 | bool is_unit_vector(Point const &p, Coord eps = EPSILON); | ||
| 426 | double atan2(Point const &p); | ||
| 427 | double angle_between(Point const &a, Point const &b); | ||
| 428 | Point abs(Point const &b); | ||
| 429 | Point constrain_angle(Point const &A, Point const &B, unsigned n = 4, Point const &dir = {1, 0}); | ||
| 430 | |||
| 431 | } // namespace Geom | ||
| 432 | |||
| 433 | // This is required to fix a bug in GCC 4.3.3 (and probably others) that causes the compiler | ||
| 434 | // to try to instantiate the iterator_traits template and fail. Probably it thinks that Point | ||
| 435 | // is an iterator and tries to use std::distance instead of Geom::distance. | ||
| 436 | namespace std { | ||
| 437 | template <> class iterator_traits<Geom::Point> {}; | ||
| 438 | } | ||
| 439 | |||
| 440 | // Structured binding support | ||
| 441 | template <> struct std::tuple_size<Geom::Point> : std::integral_constant<size_t, 2> {}; | ||
| 442 | template <size_t I> struct std::tuple_element<I, Geom::Point> { using type = Geom::Coord; }; | ||
| 443 | |||
| 444 | // Hash support | ||
| 445 | template <> struct std::hash<Geom::Point> | ||
| 446 | { | ||
| 447 | size_t operator()(Geom::Point const &p) const noexcept { | ||
| 448 | size_t hash = 0; | ||
| 449 | boost::hash_combine(hash, p.x()); | ||
| 450 | boost::hash_combine(hash, p.y()); | ||
| 451 | return hash; | ||
| 452 | } | ||
| 453 | }; | ||
| 454 | |||
| 455 | #endif // LIB2GEOM_SEEN_POINT_H | ||
| 456 | |||
| 457 | /* | ||
| 458 | Local Variables: | ||
| 459 | mode:c++ | ||
| 460 | c-file-style:"stroustrup" | ||
| 461 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
| 462 | indent-tabs-mode:nil | ||
| 463 | fill-column:99 | ||
| 464 | End: | ||
| 465 | */ | ||
| 466 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : | ||
| 467 |