clipper.core.h 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  1. /*******************************************************************************
  2. * Author : Angus Johnson *
  3. * Date : 24 March 2025 *
  4. * Website : https://www.angusj.com *
  5. * Copyright : Angus Johnson 2010-2025 *
  6. * Purpose : Core Clipper Library structures and functions *
  7. * License : https://www.boost.org/LICENSE_1_0.txt *
  8. *******************************************************************************/
  9. #ifndef CLIPPER_CORE_H
  10. #define CLIPPER_CORE_H
  11. #include "clipper2/clipper.version.h"
  12. #include <cstdint>
  13. #include <vector>
  14. #include <string>
  15. #include <iostream>
  16. #include <algorithm>
  17. #include <numeric>
  18. #include <cmath>
  19. #define CLIPPER2_THROW(exception) std::abort()
  20. namespace Clipper2Lib
  21. {
  22. #if (defined(__cpp_exceptions) && __cpp_exceptions) || (defined(__EXCEPTIONS) && __EXCEPTIONS)
  23. class Clipper2Exception : public std::exception {
  24. public:
  25. explicit Clipper2Exception(const char* description) :
  26. m_descr(description) {}
  27. virtual const char* what() const noexcept override { return m_descr.c_str(); }
  28. private:
  29. std::string m_descr;
  30. };
  31. static const char* precision_error =
  32. "Precision exceeds the permitted range";
  33. static const char* range_error =
  34. "Values exceed permitted range";
  35. static const char* scale_error =
  36. "Invalid scale (either 0 or too large)";
  37. static const char* non_pair_error =
  38. "There must be 2 values for each coordinate";
  39. static const char* undefined_error =
  40. "There is an undefined error in Clipper2";
  41. #endif
  42. // error codes (2^n)
  43. const int precision_error_i = 1; // non-fatal
  44. const int scale_error_i = 2; // non-fatal
  45. const int non_pair_error_i = 4; // non-fatal
  46. const int undefined_error_i = 32; // fatal
  47. const int range_error_i = 64;
  48. #ifndef PI
  49. static const double PI = 3.141592653589793238;
  50. #endif
  51. #ifdef CLIPPER2_MAX_DECIMAL_PRECISION
  52. const int CLIPPER2_MAX_DEC_PRECISION = CLIPPER2_MAX_DECIMAL_PRECISION;
  53. #else
  54. const int CLIPPER2_MAX_DEC_PRECISION = 8; // see Discussions #564
  55. #endif
  56. static const int64_t MAX_COORD = INT64_MAX >> 2;
  57. static const int64_t MIN_COORD = -MAX_COORD;
  58. static const int64_t INVALID = INT64_MAX;
  59. const double max_coord = static_cast<double>(MAX_COORD);
  60. const double min_coord = static_cast<double>(MIN_COORD);
  61. static const double MAX_DBL = (std::numeric_limits<double>::max)();
  62. static void DoError([[maybe_unused]] int error_code)
  63. {
  64. #if (defined(__cpp_exceptions) && __cpp_exceptions) || (defined(__EXCEPTIONS) && __EXCEPTIONS)
  65. switch (error_code)
  66. {
  67. case precision_error_i:
  68. CLIPPER2_THROW(Clipper2Exception(precision_error));
  69. case scale_error_i:
  70. CLIPPER2_THROW(Clipper2Exception(scale_error));
  71. case non_pair_error_i:
  72. CLIPPER2_THROW(Clipper2Exception(non_pair_error));
  73. case undefined_error_i:
  74. CLIPPER2_THROW(Clipper2Exception(undefined_error));
  75. case range_error_i:
  76. CLIPPER2_THROW(Clipper2Exception(range_error));
  77. // Should never happen, but adding this to stop a compiler warning
  78. default:
  79. CLIPPER2_THROW(Clipper2Exception("Unknown error"));
  80. }
  81. #else
  82. if(error_code) {}; // only to stop compiler 'parameter not used' warning
  83. #endif
  84. }
  85. // can we call std::round on T? (default false) (#824)
  86. template <typename T, typename = void>
  87. struct is_round_invocable : std::false_type {};
  88. template <typename T>
  89. struct is_round_invocable<T, std::void_t<decltype(std::round(std::declval<T>()))>> : std::true_type {};
  90. //By far the most widely used filling rules for polygons are EvenOdd
  91. //and NonZero, sometimes called Alternate and Winding respectively.
  92. //https://en.wikipedia.org/wiki/Nonzero-rule
  93. enum class FillRule { EvenOdd, NonZero, Positive, Negative };
  94. #ifdef USINGZ
  95. using z_type = int64_t;
  96. #endif
  97. // Point ------------------------------------------------------------------------
  98. template <typename T>
  99. struct Point {
  100. T x;
  101. T y;
  102. #ifdef USINGZ
  103. z_type z;
  104. template <typename T2>
  105. inline void Init(const T2 x_ = 0, const T2 y_ = 0, const z_type z_ = 0)
  106. {
  107. if constexpr (std::is_integral_v<T> &&
  108. is_round_invocable<T2>::value && !std::is_integral_v<T2>)
  109. {
  110. x = static_cast<T>(std::round(x_));
  111. y = static_cast<T>(std::round(y_));
  112. z = z_;
  113. }
  114. else
  115. {
  116. x = static_cast<T>(x_);
  117. y = static_cast<T>(y_);
  118. z = z_;
  119. }
  120. }
  121. explicit Point() : x(0), y(0), z(0) {};
  122. template <typename T2>
  123. Point(const T2 x_, const T2 y_, const z_type z_ = 0)
  124. {
  125. Init(x_, y_);
  126. z = z_;
  127. }
  128. template <typename T2>
  129. explicit Point(const Point<T2>& p)
  130. {
  131. Init(p.x, p.y, p.z);
  132. }
  133. template <typename T2>
  134. explicit Point(const Point<T2>& p, z_type z_)
  135. {
  136. Init(p.x, p.y, z_);
  137. }
  138. Point operator * (const double scale) const
  139. {
  140. return Point(x * scale, y * scale, z);
  141. }
  142. void SetZ(const z_type z_value) { z = z_value; }
  143. friend std::ostream& operator<<(std::ostream& os, const Point& point)
  144. {
  145. os << point.x << "," << point.y << "," << point.z;
  146. return os;
  147. }
  148. #else
  149. template <typename T2>
  150. inline void Init(const T2 x_ = 0, const T2 y_ = 0)
  151. {
  152. if constexpr (std::is_integral_v<T> &&
  153. is_round_invocable<T2>::value && !std::is_integral_v<T2>)
  154. {
  155. x = static_cast<T>(std::round(x_));
  156. y = static_cast<T>(std::round(y_));
  157. }
  158. else
  159. {
  160. x = static_cast<T>(x_);
  161. y = static_cast<T>(y_);
  162. }
  163. }
  164. explicit Point() : x(0), y(0) {};
  165. template <typename T2>
  166. Point(const T2 x_, const T2 y_) { Init(x_, y_); }
  167. template <typename T2>
  168. explicit Point(const Point<T2>& p) { Init(p.x, p.y); }
  169. Point operator * (const double scale) const
  170. {
  171. return Point(x * scale, y * scale);
  172. }
  173. friend std::ostream& operator<<(std::ostream& os, const Point& point)
  174. {
  175. os << point.x << "," << point.y;
  176. return os;
  177. }
  178. #endif
  179. friend bool operator==(const Point& a, const Point& b)
  180. {
  181. return a.x == b.x && a.y == b.y;
  182. }
  183. friend bool operator!=(const Point& a, const Point& b)
  184. {
  185. return !(a == b);
  186. }
  187. inline Point<T> operator-() const
  188. {
  189. return Point<T>(-x, -y);
  190. }
  191. inline Point operator+(const Point& b) const
  192. {
  193. return Point(x + b.x, y + b.y);
  194. }
  195. inline Point operator-(const Point& b) const
  196. {
  197. return Point(x - b.x, y - b.y);
  198. }
  199. inline void Negate() { x = -x; y = -y; }
  200. };
  201. //nb: using 'using' here (instead of typedef) as they can be used in templates
  202. using Point64 = Point<int64_t>;
  203. using PointD = Point<double>;
  204. template <typename T>
  205. using Path = std::vector<Point<T>>;
  206. template <typename T>
  207. using Paths = std::vector<Path<T>>;
  208. template <typename T, typename T2=T>
  209. Path<T>& operator<<(Path<T>& poly, const Point<T2>& p)
  210. {
  211. poly.emplace_back(p);
  212. return poly;
  213. }
  214. template <typename T>
  215. Paths<T>& operator<<(Paths<T>& polys, const Path<T>& p)
  216. {
  217. polys.emplace_back(p);
  218. return polys;
  219. }
  220. using Path64 = Path<int64_t>;
  221. using PathD = Path<double>;
  222. using Paths64 = std::vector< Path64>;
  223. using PathsD = std::vector< PathD>;
  224. static const Point64 InvalidPoint64 = Point64(
  225. (std::numeric_limits<int64_t>::max)(),
  226. (std::numeric_limits<int64_t>::max)());
  227. static const PointD InvalidPointD = PointD(
  228. (std::numeric_limits<double>::max)(),
  229. (std::numeric_limits<double>::max)());
  230. template<typename T>
  231. static inline Point<T> MidPoint(const Point<T>& p1, const Point<T>& p2)
  232. {
  233. Point<T> result;
  234. result.x = (p1.x + p2.x) / 2;
  235. result.y = (p1.y + p2.y) / 2;
  236. return result;
  237. }
  238. // Rect ------------------------------------------------------------------------
  239. template <typename T>
  240. struct Rect;
  241. using Rect64 = Rect<int64_t>;
  242. using RectD = Rect<double>;
  243. template <typename T>
  244. struct Rect {
  245. T left;
  246. T top;
  247. T right;
  248. T bottom;
  249. Rect(T l, T t, T r, T b) :
  250. left(l),
  251. top(t),
  252. right(r),
  253. bottom(b) {}
  254. Rect(bool is_valid = true)
  255. {
  256. if (is_valid)
  257. {
  258. left = right = top = bottom = 0;
  259. }
  260. else
  261. {
  262. left = top = (std::numeric_limits<T>::max)();
  263. right = bottom = std::numeric_limits<T>::lowest();
  264. }
  265. }
  266. static Rect<T> InvalidRect()
  267. {
  268. return {
  269. (std::numeric_limits<T>::max)(),
  270. (std::numeric_limits<T>::max)(),
  271. std::numeric_limits<T>::lowest(),
  272. std::numeric_limits<T>::lowest() };
  273. }
  274. bool IsValid() const { return left != (std::numeric_limits<T>::max)(); }
  275. T Width() const { return right - left; }
  276. T Height() const { return bottom - top; }
  277. void Width(T width) { right = left + width; }
  278. void Height(T height) { bottom = top + height; }
  279. Point<T> MidPoint() const
  280. {
  281. return Point<T>((left + right) / 2, (top + bottom) / 2);
  282. }
  283. Path<T> AsPath() const
  284. {
  285. Path<T> result;
  286. result.reserve(4);
  287. result.emplace_back(left, top);
  288. result.emplace_back(right, top);
  289. result.emplace_back(right, bottom);
  290. result.emplace_back(left, bottom);
  291. return result;
  292. }
  293. bool Contains(const Point<T>& pt) const
  294. {
  295. return pt.x > left && pt.x < right&& pt.y > top && pt.y < bottom;
  296. }
  297. bool Contains(const Rect<T>& rec) const
  298. {
  299. return rec.left >= left && rec.right <= right &&
  300. rec.top >= top && rec.bottom <= bottom;
  301. }
  302. void Scale(double scale) {
  303. left *= scale;
  304. top *= scale;
  305. right *= scale;
  306. bottom *= scale;
  307. }
  308. bool IsEmpty() const { return bottom <= top || right <= left; };
  309. bool Intersects(const Rect<T>& rec) const
  310. {
  311. return ((std::max)(left, rec.left) <= (std::min)(right, rec.right)) &&
  312. ((std::max)(top, rec.top) <= (std::min)(bottom, rec.bottom));
  313. };
  314. bool operator==(const Rect<T>& other) const {
  315. return left == other.left && right == other.right &&
  316. top == other.top && bottom == other.bottom;
  317. }
  318. Rect<T>& operator+=(const Rect<T>& other)
  319. {
  320. left = (std::min)(left, other.left);
  321. top = (std::min)(top, other.top);
  322. right = (std::max)(right, other.right);
  323. bottom = (std::max)(bottom, other.bottom);
  324. return *this;
  325. }
  326. Rect<T> operator+(const Rect<T>& other) const
  327. {
  328. Rect<T> result = *this;
  329. result += other;
  330. return result;
  331. }
  332. friend std::ostream& operator<<(std::ostream& os, const Rect<T>& rect) {
  333. os << "(" << rect.left << "," << rect.top << "," << rect.right << "," << rect.bottom << ") ";
  334. return os;
  335. }
  336. };
  337. template <typename T1, typename T2>
  338. inline Rect<T1> ScaleRect(const Rect<T2>& rect, double scale)
  339. {
  340. Rect<T1> result;
  341. if constexpr (std::is_integral_v<T1> &&
  342. is_round_invocable<T2>::value && !std::is_integral_v<T2>)
  343. {
  344. result.left = static_cast<T1>(std::round(rect.left * scale));
  345. result.top = static_cast<T1>(std::round(rect.top * scale));
  346. result.right = static_cast<T1>(std::round(rect.right * scale));
  347. result.bottom = static_cast<T1>(std::round(rect.bottom * scale));
  348. }
  349. else
  350. {
  351. result.left = static_cast<T1>(rect.left * scale);
  352. result.top = static_cast<T1>(rect.top * scale);
  353. result.right = static_cast<T1>(rect.right * scale);
  354. result.bottom = static_cast<T1>(rect.bottom * scale);
  355. }
  356. return result;
  357. }
  358. static const Rect64 InvalidRect64 = Rect64::InvalidRect();
  359. static const RectD InvalidRectD = RectD::InvalidRect();
  360. template <typename T>
  361. Rect<T> GetBounds(const Path<T>& path)
  362. {
  363. T xmin = (std::numeric_limits<T>::max)();
  364. T ymin = (std::numeric_limits<T>::max)();
  365. T xmax = std::numeric_limits<T>::lowest();
  366. T ymax = std::numeric_limits<T>::lowest();
  367. for (const auto& p : path)
  368. {
  369. if (p.x < xmin) xmin = p.x;
  370. if (p.x > xmax) xmax = p.x;
  371. if (p.y < ymin) ymin = p.y;
  372. if (p.y > ymax) ymax = p.y;
  373. }
  374. return Rect<T>(xmin, ymin, xmax, ymax);
  375. }
  376. template <typename T>
  377. Rect<T> GetBounds(const Paths<T>& paths)
  378. {
  379. T xmin = (std::numeric_limits<T>::max)();
  380. T ymin = (std::numeric_limits<T>::max)();
  381. T xmax = std::numeric_limits<T>::lowest();
  382. T ymax = std::numeric_limits<T>::lowest();
  383. for (const Path<T>& path : paths)
  384. for (const Point<T>& p : path)
  385. {
  386. if (p.x < xmin) xmin = p.x;
  387. if (p.x > xmax) xmax = p.x;
  388. if (p.y < ymin) ymin = p.y;
  389. if (p.y > ymax) ymax = p.y;
  390. }
  391. return Rect<T>(xmin, ymin, xmax, ymax);
  392. }
  393. template <typename T, typename T2>
  394. Rect<T> GetBounds(const Path<T2>& path)
  395. {
  396. T xmin = (std::numeric_limits<T>::max)();
  397. T ymin = (std::numeric_limits<T>::max)();
  398. T xmax = std::numeric_limits<T>::lowest();
  399. T ymax = std::numeric_limits<T>::lowest();
  400. for (const auto& p : path)
  401. {
  402. if (p.x < xmin) xmin = static_cast<T>(p.x);
  403. if (p.x > xmax) xmax = static_cast<T>(p.x);
  404. if (p.y < ymin) ymin = static_cast<T>(p.y);
  405. if (p.y > ymax) ymax = static_cast<T>(p.y);
  406. }
  407. return Rect<T>(xmin, ymin, xmax, ymax);
  408. }
  409. template <typename T, typename T2>
  410. Rect<T> GetBounds(const Paths<T2>& paths)
  411. {
  412. T xmin = (std::numeric_limits<T>::max)();
  413. T ymin = (std::numeric_limits<T>::max)();
  414. T xmax = std::numeric_limits<T>::lowest();
  415. T ymax = std::numeric_limits<T>::lowest();
  416. for (const Path<T2>& path : paths)
  417. for (const Point<T2>& p : path)
  418. {
  419. if (p.x < xmin) xmin = static_cast<T>(p.x);
  420. if (p.x > xmax) xmax = static_cast<T>(p.x);
  421. if (p.y < ymin) ymin = static_cast<T>(p.y);
  422. if (p.y > ymax) ymax = static_cast<T>(p.y);
  423. }
  424. return Rect<T>(xmin, ymin, xmax, ymax);
  425. }
  426. template <typename T>
  427. std::ostream& operator << (std::ostream& outstream, const Path<T>& path)
  428. {
  429. if (!path.empty())
  430. {
  431. auto pt = path.cbegin(), last = path.cend() - 1;
  432. while (pt != last)
  433. outstream << *pt++ << ", ";
  434. outstream << *last << std::endl;
  435. }
  436. return outstream;
  437. }
  438. template <typename T>
  439. std::ostream& operator << (std::ostream& outstream, const Paths<T>& paths)
  440. {
  441. for (auto p : paths)
  442. outstream << p;
  443. return outstream;
  444. }
  445. template <typename T1, typename T2>
  446. inline Path<T1> ScalePath(const Path<T2>& path,
  447. double scale_x, double scale_y, int& error_code)
  448. {
  449. Path<T1> result;
  450. if (scale_x == 0 || scale_y == 0)
  451. {
  452. error_code |= scale_error_i;
  453. DoError(scale_error_i);
  454. // if no exception, treat as non-fatal error
  455. if (scale_x == 0) scale_x = 1.0;
  456. if (scale_y == 0) scale_y = 1.0;
  457. }
  458. result.reserve(path.size());
  459. #ifdef USINGZ
  460. std::transform(path.begin(), path.end(), back_inserter(result),
  461. [scale_x, scale_y](const auto& pt)
  462. { return Point<T1>(pt.x * scale_x, pt.y * scale_y, pt.z); });
  463. #else
  464. std::transform(path.begin(), path.end(), back_inserter(result),
  465. [scale_x, scale_y](const auto& pt)
  466. { return Point<T1>(pt.x * scale_x, pt.y * scale_y); });
  467. #endif
  468. return result;
  469. }
  470. template <typename T1, typename T2>
  471. inline Path<T1> ScalePath(const Path<T2>& path,
  472. double scale, int& error_code)
  473. {
  474. return ScalePath<T1, T2>(path, scale, scale, error_code);
  475. }
  476. template <typename T1, typename T2>
  477. inline Paths<T1> ScalePaths(const Paths<T2>& paths,
  478. double scale_x, double scale_y, int& error_code)
  479. {
  480. Paths<T1> result;
  481. if constexpr (std::is_integral_v<T1>)
  482. {
  483. RectD r = GetBounds<double, T2>(paths);
  484. if ((r.left * scale_x) < min_coord ||
  485. (r.right * scale_x) > max_coord ||
  486. (r.top * scale_y) < min_coord ||
  487. (r.bottom * scale_y) > max_coord)
  488. {
  489. error_code |= range_error_i;
  490. DoError(range_error_i);
  491. return result; // empty path
  492. }
  493. }
  494. result.reserve(paths.size());
  495. std::transform(paths.begin(), paths.end(), back_inserter(result),
  496. [=, &error_code](const auto& path)
  497. { return ScalePath<T1, T2>(path, scale_x, scale_y, error_code); });
  498. return result;
  499. }
  500. template <typename T1, typename T2>
  501. inline Paths<T1> ScalePaths(const Paths<T2>& paths,
  502. double scale, int& error_code)
  503. {
  504. return ScalePaths<T1, T2>(paths, scale, scale, error_code);
  505. }
  506. template <typename T1, typename T2>
  507. inline Path<T1> TransformPath(const Path<T2>& path)
  508. {
  509. Path<T1> result;
  510. result.reserve(path.size());
  511. std::transform(path.cbegin(), path.cend(), std::back_inserter(result),
  512. [](const Point<T2>& pt) {return Point<T1>(pt); });
  513. return result;
  514. }
  515. template <typename T1, typename T2>
  516. inline Paths<T1> TransformPaths(const Paths<T2>& paths)
  517. {
  518. Paths<T1> result;
  519. std::transform(paths.cbegin(), paths.cend(), std::back_inserter(result),
  520. [](const Path<T2>& path) {return TransformPath<T1, T2>(path); });
  521. return result;
  522. }
  523. template<typename T>
  524. inline double Sqr(T val)
  525. {
  526. return static_cast<double>(val) * static_cast<double>(val);
  527. }
  528. template<typename T>
  529. inline bool NearEqual(const Point<T>& p1,
  530. const Point<T>& p2, double max_dist_sqrd)
  531. {
  532. return Sqr(p1.x - p2.x) + Sqr(p1.y - p2.y) < max_dist_sqrd;
  533. }
  534. template<typename T>
  535. inline Path<T> StripNearEqual(const Path<T>& path,
  536. double max_dist_sqrd, bool is_closed_path)
  537. {
  538. if (path.size() == 0) return Path<T>();
  539. Path<T> result;
  540. result.reserve(path.size());
  541. typename Path<T>::const_iterator path_iter = path.cbegin();
  542. Point<T> first_pt = *path_iter++, last_pt = first_pt;
  543. result.emplace_back(first_pt);
  544. for (; path_iter != path.cend(); ++path_iter)
  545. {
  546. if (!NearEqual(*path_iter, last_pt, max_dist_sqrd))
  547. {
  548. last_pt = *path_iter;
  549. result.emplace_back(last_pt);
  550. }
  551. }
  552. if (!is_closed_path) return result;
  553. while (result.size() > 1 &&
  554. NearEqual(result.back(), first_pt, max_dist_sqrd)) result.pop_back();
  555. return result;
  556. }
  557. template<typename T>
  558. inline Paths<T> StripNearEqual(const Paths<T>& paths,
  559. double max_dist_sqrd, bool is_closed_path)
  560. {
  561. Paths<T> result;
  562. result.reserve(paths.size());
  563. for (typename Paths<T>::const_iterator paths_citer = paths.cbegin();
  564. paths_citer != paths.cend(); ++paths_citer)
  565. {
  566. result.emplace_back(std::move(StripNearEqual(*paths_citer, max_dist_sqrd, is_closed_path)));
  567. }
  568. return result;
  569. }
  570. template<typename T>
  571. inline void StripDuplicates( Path<T>& path, bool is_closed_path)
  572. {
  573. //https://stackoverflow.com/questions/1041620/whats-the-most-efficient-way-to-erase-duplicates-and-sort-a-vector#:~:text=Let%27s%20compare%20three%20approaches%3A
  574. path.erase(std::unique(path.begin(), path.end()), path.end());
  575. if (is_closed_path)
  576. while (path.size() > 1 && path.back() == path.front()) path.pop_back();
  577. }
  578. template<typename T>
  579. inline void StripDuplicates( Paths<T>& paths, bool is_closed_path)
  580. {
  581. for (typename Paths<T>::iterator paths_citer = paths.begin();
  582. paths_citer != paths.end(); ++paths_citer)
  583. {
  584. StripDuplicates(*paths_citer, is_closed_path);
  585. }
  586. }
  587. // Miscellaneous ------------------------------------------------------------
  588. inline void CheckPrecisionRange(int& precision, int& error_code)
  589. {
  590. if (precision >= -CLIPPER2_MAX_DEC_PRECISION &&
  591. precision <= CLIPPER2_MAX_DEC_PRECISION) return;
  592. error_code |= precision_error_i; // non-fatal error
  593. DoError(precision_error_i); // does nothing when exceptions are disabled
  594. precision = precision > 0 ? CLIPPER2_MAX_DEC_PRECISION : -CLIPPER2_MAX_DEC_PRECISION;
  595. }
  596. inline void CheckPrecisionRange(int& precision)
  597. {
  598. int error_code = 0;
  599. CheckPrecisionRange(precision, error_code);
  600. }
  601. inline int TriSign(int64_t x) // returns 0, 1 or -1
  602. {
  603. return (x > 0) - (x < 0);
  604. }
  605. struct UInt128Struct
  606. {
  607. const uint64_t lo = 0;
  608. const uint64_t hi = 0;
  609. bool operator==(const UInt128Struct& other) const
  610. {
  611. return lo == other.lo && hi == other.hi;
  612. };
  613. };
  614. inline UInt128Struct Multiply(uint64_t a, uint64_t b) // #834, #835
  615. {
  616. // note to self - lamba expressions follow
  617. const auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; };
  618. const auto hi = [](uint64_t x) { return x >> 32; };
  619. const uint64_t x1 = lo(a) * lo(b);
  620. const uint64_t x2 = hi(a) * lo(b) + hi(x1);
  621. const uint64_t x3 = lo(a) * hi(b) + lo(x2);
  622. const uint64_t lobits = lo(x3) << 32 | lo(x1);
  623. const uint64_t hibits = hi(a) * hi(b) + hi(x2) + hi(x3);
  624. return { lobits, hibits };
  625. }
  626. // returns true if (and only if) a * b == c * d
  627. inline bool ProductsAreEqual(int64_t a, int64_t b, int64_t c, int64_t d)
  628. {
  629. #if (defined(__clang__) || defined(__GNUC__)) && UINTPTR_MAX >= UINT64_MAX
  630. const auto ab = static_cast<__int128_t>(a) * static_cast<__int128_t>(b);
  631. const auto cd = static_cast<__int128_t>(c) * static_cast<__int128_t>(d);
  632. return ab == cd;
  633. #else
  634. // nb: unsigned values needed for calculating overflow carry
  635. const auto abs_a = static_cast<uint64_t>(std::abs(a));
  636. const auto abs_b = static_cast<uint64_t>(std::abs(b));
  637. const auto abs_c = static_cast<uint64_t>(std::abs(c));
  638. const auto abs_d = static_cast<uint64_t>(std::abs(d));
  639. const auto ab = Multiply(abs_a, abs_b);
  640. const auto cd = Multiply(abs_c, abs_d);
  641. // nb: it's important to differentiate 0 values here from other values
  642. const auto sign_ab = TriSign(a) * TriSign(b);
  643. const auto sign_cd = TriSign(c) * TriSign(d);
  644. return ab == cd && sign_ab == sign_cd;
  645. #endif
  646. }
  647. template <typename T>
  648. inline int CrossProductSign(const Point<T>& pt1, const Point<T>& pt2, const Point<T>& pt3)
  649. {
  650. const auto a = pt2.x - pt1.x;
  651. const auto b = pt3.y - pt2.y;
  652. const auto c = pt2.y - pt1.y;
  653. const auto d = pt3.x - pt2.x;
  654. #if (defined(__clang__) || defined(__GNUC__)) && UINTPTR_MAX >= UINT64_MAX
  655. const auto ab = static_cast<__int128_t>(a) * static_cast<__int128_t>(b);
  656. const auto cd = static_cast<__int128_t>(c) * static_cast<__int128_t>(d);
  657. if (ab > cd) return 1;
  658. else if (ab < cd) return -1;
  659. else return 0;
  660. #else
  661. // nb: unsigned values needed for calculating carry into 'hi'
  662. const auto abs_a = static_cast<uint64_t>(std::abs(a));
  663. const auto abs_b = static_cast<uint64_t>(std::abs(b));
  664. const auto abs_c = static_cast<uint64_t>(std::abs(c));
  665. const auto abs_d = static_cast<uint64_t>(std::abs(d));
  666. const auto ab = Multiply(abs_a, abs_b);
  667. const auto cd = Multiply(abs_c, abs_d);
  668. const auto sign_ab = TriSign(a) * TriSign(b);
  669. const auto sign_cd = TriSign(c) * TriSign(d);
  670. if (sign_ab == sign_cd)
  671. {
  672. int result;
  673. if (ab.hi == cd.hi)
  674. {
  675. if (ab.lo == cd.lo) return 0;
  676. result = (ab.lo > cd.lo) ? 1 : -1;
  677. }
  678. else result = (ab.hi > cd.hi) ? 1 : -1;
  679. return (sign_ab > 0) ? result : -result;
  680. }
  681. return (sign_ab > sign_cd) ? 1 : -1;
  682. #endif
  683. }
  684. template <typename T>
  685. inline bool IsCollinear(const Point<T>& pt1,
  686. const Point<T>& sharedPt, const Point<T>& pt2) // #777
  687. {
  688. const auto a = sharedPt.x - pt1.x;
  689. const auto b = pt2.y - sharedPt.y;
  690. const auto c = sharedPt.y - pt1.y;
  691. const auto d = pt2.x - sharedPt.x;
  692. // When checking for collinearity with very large coordinate values
  693. // then ProductsAreEqual is more accurate than using CrossProduct.
  694. return ProductsAreEqual(a, b, c, d);
  695. }
  696. template <typename T>
  697. inline double CrossProduct(const Point<T>& pt1, const Point<T>& pt2, const Point<T>& pt3) {
  698. return (static_cast<double>(pt2.x - pt1.x) * static_cast<double>(pt3.y -
  699. pt2.y) - static_cast<double>(pt2.y - pt1.y) * static_cast<double>(pt3.x - pt2.x));
  700. }
  701. template <typename T>
  702. inline double CrossProduct(const Point<T>& vec1, const Point<T>& vec2)
  703. {
  704. return static_cast<double>(vec1.y * vec2.x) - static_cast<double>(vec2.y * vec1.x);
  705. }
  706. template <typename T>
  707. inline double DotProduct(const Point<T>& pt1, const Point<T>& pt2, const Point<T>& pt3) {
  708. return (static_cast<double>(pt2.x - pt1.x) * static_cast<double>(pt3.x - pt2.x) +
  709. static_cast<double>(pt2.y - pt1.y) * static_cast<double>(pt3.y - pt2.y));
  710. }
  711. template <typename T>
  712. inline double DotProduct(const Point<T>& vec1, const Point<T>& vec2)
  713. {
  714. return static_cast<double>(vec1.x * vec2.x) + static_cast<double>(vec1.y * vec2.y);
  715. }
  716. template <typename T>
  717. inline double DistanceSqr(const Point<T> pt1, const Point<T> pt2)
  718. {
  719. return Sqr(pt1.x - pt2.x) + Sqr(pt1.y - pt2.y);
  720. }
  721. template <typename T>
  722. inline double PerpendicDistFromLineSqrd(const Point<T>& pt,
  723. const Point<T>& line1, const Point<T>& line2)
  724. {
  725. //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
  726. //see https://en.wikipedia.org/wiki/Perpendicular_distance
  727. double a = static_cast<double>(pt.x - line1.x);
  728. double b = static_cast<double>(pt.y - line1.y);
  729. double c = static_cast<double>(line2.x - line1.x);
  730. double d = static_cast<double>(line2.y - line1.y);
  731. if (c == 0 && d == 0) return 0;
  732. return Sqr(a * d - c * b) / (c * c + d * d);
  733. }
  734. template <typename T>
  735. inline double Area(const Path<T>& path)
  736. {
  737. size_t cnt = path.size();
  738. if (cnt < 3) return 0.0;
  739. double a = 0.0;
  740. typename Path<T>::const_iterator it1, it2 = path.cend() - 1, stop = it2;
  741. if (!(cnt & 1)) ++stop;
  742. for (it1 = path.cbegin(); it1 != stop;)
  743. {
  744. a += static_cast<double>(it2->y + it1->y) * (it2->x - it1->x);
  745. it2 = it1 + 1;
  746. a += static_cast<double>(it1->y + it2->y) * (it1->x - it2->x);
  747. it1 += 2;
  748. }
  749. if (cnt & 1)
  750. a += static_cast<double>(it2->y + it1->y) * (it2->x - it1->x);
  751. return (a * 0.5);
  752. }
  753. template <typename T>
  754. inline double Area(const Paths<T>& paths)
  755. {
  756. double a = 0.0;
  757. for (typename Paths<T>::const_iterator paths_iter = paths.cbegin();
  758. paths_iter != paths.cend(); ++paths_iter)
  759. {
  760. a += Area<T>(*paths_iter);
  761. }
  762. return a;
  763. }
  764. template <typename T>
  765. inline bool IsPositive(const Path<T>& poly)
  766. {
  767. // A curve has positive orientation [and area] if a region 'R'
  768. // is on the left when traveling around the outside of 'R'.
  769. //https://mathworld.wolfram.com/CurveOrientation.html
  770. //nb: This statement is premised on using Cartesian coordinates
  771. return Area<T>(poly) >= 0;
  772. }
  773. #if CLIPPER2_HI_PRECISION
  774. // caution: this will compromise performance
  775. // https://github.com/AngusJohnson/Clipper2/issues/317#issuecomment-1314023253
  776. // See also CPP/BenchMark/GetIntersectPtBenchmark.cpp
  777. #define CC_MIN(x,y) ((x)>(y)?(y):(x))
  778. #define CC_MAX(x,y) ((x)<(y)?(y):(x))
  779. template<typename T>
  780. inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
  781. const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
  782. {
  783. double ln1dy = static_cast<double>(ln1b.y - ln1a.y);
  784. double ln1dx = static_cast<double>(ln1a.x - ln1b.x);
  785. double ln2dy = static_cast<double>(ln2b.y - ln2a.y);
  786. double ln2dx = static_cast<double>(ln2a.x - ln2b.x);
  787. double det = (ln2dy * ln1dx) - (ln1dy * ln2dx);
  788. if (det == 0.0) return false;
  789. T bb0minx = CC_MIN(ln1a.x, ln1b.x);
  790. T bb0miny = CC_MIN(ln1a.y, ln1b.y);
  791. T bb0maxx = CC_MAX(ln1a.x, ln1b.x);
  792. T bb0maxy = CC_MAX(ln1a.y, ln1b.y);
  793. T bb1minx = CC_MIN(ln2a.x, ln2b.x);
  794. T bb1miny = CC_MIN(ln2a.y, ln2b.y);
  795. T bb1maxx = CC_MAX(ln2a.x, ln2b.x);
  796. T bb1maxy = CC_MAX(ln2a.y, ln2b.y);
  797. if constexpr (std::is_integral_v<T>)
  798. {
  799. int64_t originx = (CC_MIN(bb0maxx, bb1maxx) + CC_MAX(bb0minx, bb1minx)) >> 1;
  800. int64_t originy = (CC_MIN(bb0maxy, bb1maxy) + CC_MAX(bb0miny, bb1miny)) >> 1;
  801. double ln0c = (ln1dy * static_cast<double>(ln1a.x - originx)) +
  802. (ln1dx * static_cast<double>(ln1a.y - originy));
  803. double ln1c = (ln2dy * static_cast<double>(ln2a.x - originx)) +
  804. (ln2dx * static_cast<double>(ln2a.y - originy));
  805. double hitx = ((ln1dx * ln1c) - (ln2dx * ln0c)) / det;
  806. double hity = ((ln2dy * ln0c) - (ln1dy * ln1c)) / det;
  807. ip.x = originx + (T)nearbyint(hitx);
  808. ip.y = originy + (T)nearbyint(hity);
  809. }
  810. else
  811. {
  812. double originx = (CC_MIN(bb0maxx, bb1maxx) + CC_MAX(bb0minx, bb1minx)) / 2.0;
  813. double originy = (CC_MIN(bb0maxy, bb1maxy) + CC_MAX(bb0miny, bb1miny)) / 2.0;
  814. double ln0c = (ln1dy * static_cast<double>(ln1a.x - originx)) +
  815. (ln1dx * static_cast<double>(ln1a.y - originy));
  816. double ln1c = (ln2dy * static_cast<double>(ln2a.x - originx)) +
  817. (ln2dx * static_cast<double>(ln2a.y - originy));
  818. double hitx = ((ln1dx * ln1c) - (ln2dx * ln0c)) / det;
  819. double hity = ((ln2dy * ln0c) - (ln1dy * ln1c)) / det;
  820. ip.x = originx + static_cast<T>(hitx);
  821. ip.y = originy + static_cast<T>(hity);
  822. }
  823. return true;
  824. }
  825. #else
  826. template<typename T>
  827. inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
  828. const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
  829. {
  830. // https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
  831. double dx1 = static_cast<double>(ln1b.x - ln1a.x);
  832. double dy1 = static_cast<double>(ln1b.y - ln1a.y);
  833. double dx2 = static_cast<double>(ln2b.x - ln2a.x);
  834. double dy2 = static_cast<double>(ln2b.y - ln2a.y);
  835. double det = dy1 * dx2 - dy2 * dx1;
  836. if (det == 0.0) return false;
  837. double t = ((ln1a.x - ln2a.x) * dy2 - (ln1a.y - ln2a.y) * dx2) / det;
  838. if (t <= 0.0) ip = ln1a;
  839. else if (t >= 1.0) ip = ln1b;
  840. else
  841. {
  842. ip.x = static_cast<T>(ln1a.x + t * dx1);
  843. ip.y = static_cast<T>(ln1a.y + t * dy1);
  844. }
  845. return true;
  846. }
  847. #endif
  848. template<typename T>
  849. inline Point<T> TranslatePoint(const Point<T>& pt, double dx, double dy)
  850. {
  851. #ifdef USINGZ
  852. return Point<T>(pt.x + dx, pt.y + dy, pt.z);
  853. #else
  854. return Point<T>(pt.x + dx, pt.y + dy);
  855. #endif
  856. }
  857. template<typename T>
  858. inline Point<T> ReflectPoint(const Point<T>& pt, const Point<T>& pivot)
  859. {
  860. #ifdef USINGZ
  861. return Point<T>(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y), pt.z);
  862. #else
  863. return Point<T>(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y));
  864. #endif
  865. }
  866. template<typename T>
  867. inline int GetSign(const T& val)
  868. {
  869. if (!val) return 0;
  870. return (val > 0) ? 1 : -1;
  871. }
  872. inline bool SegmentsIntersect(const Point64& seg1a, const Point64& seg1b,
  873. const Point64& seg2a, const Point64& seg2b, bool inclusive = false)
  874. {
  875. if (inclusive)
  876. {
  877. double res1 = CrossProduct(seg1a, seg2a, seg2b);
  878. double res2 = CrossProduct(seg1b, seg2a, seg2b);
  879. if (res1 * res2 > 0) return false;
  880. double res3 = CrossProduct(seg2a, seg1a, seg1b);
  881. double res4 = CrossProduct(seg2b, seg1a, seg1b);
  882. if (res3 * res4 > 0) return false;
  883. return (res1 || res2 || res3 || res4); // ensures not collinear
  884. }
  885. else {
  886. return (GetSign(CrossProduct(seg1a, seg2a, seg2b)) *
  887. GetSign(CrossProduct(seg1b, seg2a, seg2b)) < 0) &&
  888. (GetSign(CrossProduct(seg2a, seg1a, seg1b)) *
  889. GetSign(CrossProduct(seg2b, seg1a, seg1b)) < 0);
  890. }
  891. }
  892. template<typename T>
  893. inline Point<T> GetClosestPointOnSegment(const Point<T>& offPt,
  894. const Point<T>& seg1, const Point<T>& seg2)
  895. {
  896. if (seg1.x == seg2.x && seg1.y == seg2.y) return seg1;
  897. double dx = static_cast<double>(seg2.x - seg1.x);
  898. double dy = static_cast<double>(seg2.y - seg1.y);
  899. double q =
  900. (static_cast<double>(offPt.x - seg1.x) * dx +
  901. static_cast<double>(offPt.y - seg1.y) * dy) /
  902. (Sqr(dx) + Sqr(dy));
  903. if (q < 0) q = 0; else if (q > 1) q = 1;
  904. if constexpr (std::is_integral_v<T>)
  905. return Point<T>(
  906. seg1.x + static_cast<T>(nearbyint(q * dx)),
  907. seg1.y + static_cast<T>(nearbyint(q * dy)));
  908. else
  909. return Point<T>(
  910. seg1.x + static_cast<T>(q * dx),
  911. seg1.y + static_cast<T>(q * dy));
  912. }
  913. enum class PointInPolygonResult { IsOn, IsInside, IsOutside };
  914. template <typename T>
  915. inline PointInPolygonResult PointInPolygon(const Point<T>& pt, const Path<T>& polygon)
  916. {
  917. if (polygon.size() < 3)
  918. return PointInPolygonResult::IsOutside;
  919. int val = 0;
  920. typename Path<T>::const_iterator cbegin = polygon.cbegin(), first = cbegin, curr, prev;
  921. typename Path<T>::const_iterator cend = polygon.cend();
  922. while (first != cend && first->y == pt.y) ++first;
  923. if (first == cend) // not a proper polygon
  924. return PointInPolygonResult::IsOutside;
  925. bool is_above = first->y < pt.y, starting_above = is_above;
  926. curr = first +1;
  927. while (true)
  928. {
  929. if (curr == cend)
  930. {
  931. if (cend == first || first == cbegin) break;
  932. cend = first;
  933. curr = cbegin;
  934. }
  935. if (is_above)
  936. {
  937. while (curr != cend && curr->y < pt.y) ++curr;
  938. if (curr == cend) continue;
  939. }
  940. else
  941. {
  942. while (curr != cend && curr->y > pt.y) ++curr;
  943. if (curr == cend) continue;
  944. }
  945. if (curr == cbegin)
  946. prev = polygon.cend() - 1; //nb: NOT cend (since might equal first)
  947. else
  948. prev = curr - 1;
  949. if (curr->y == pt.y)
  950. {
  951. if (curr->x == pt.x ||
  952. (curr->y == prev->y &&
  953. ((pt.x < prev->x) != (pt.x < curr->x))))
  954. return PointInPolygonResult::IsOn;
  955. ++curr;
  956. if (curr == first) break;
  957. continue;
  958. }
  959. if (pt.x < curr->x && pt.x < prev->x)
  960. {
  961. // we're only interested in edges crossing on the left
  962. }
  963. else if (pt.x > prev->x && pt.x > curr->x)
  964. val = 1 - val; // toggle val
  965. else
  966. {
  967. double d = CrossProduct(*prev, *curr, pt);
  968. if (d == 0) return PointInPolygonResult::IsOn;
  969. if ((d < 0) == is_above) val = 1 - val;
  970. }
  971. is_above = !is_above;
  972. ++curr;
  973. }
  974. if (is_above != starting_above)
  975. {
  976. cend = polygon.cend();
  977. if (curr == cend) curr = cbegin;
  978. if (curr == cbegin) prev = cend - 1;
  979. else prev = curr - 1;
  980. double d = CrossProduct(*prev, *curr, pt);
  981. if (d == 0) return PointInPolygonResult::IsOn;
  982. if ((d < 0) == is_above) val = 1 - val;
  983. }
  984. return (val == 0) ?
  985. PointInPolygonResult::IsOutside :
  986. PointInPolygonResult::IsInside;
  987. }
  988. } // namespace
  989. #endif // CLIPPER_CORE_H