test_set_ops_linear_linear.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014-2015, Oracle and/or its affiliates.
  3. // Licensed under the Boost Software License version 1.0.
  4. // http://www.boost.org/users/license.html
  5. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  6. #ifndef BOOST_GEOMETRY_TEST_SET_OPS_LINEAR_LINEAR_HPP
  7. #define BOOST_GEOMETRY_TEST_SET_OPS_LINEAR_LINEAR_HPP
  8. #include <string>
  9. #include <fstream>
  10. #include <sstream>
  11. #include <algorithm>
  12. #include <boost/core/ignore_unused.hpp>
  13. #include <boost/range.hpp>
  14. #include <boost/typeof/typeof.hpp>
  15. #include <boost/geometry/policies/compare.hpp>
  16. #include <boost/geometry/algorithms/equals.hpp>
  17. #include <boost/geometry/algorithms/reverse.hpp>
  18. #include "test_get_turns_ll_invariance.hpp"
  19. namespace bg = ::boost::geometry;
  20. template <typename Linestring1, typename Linestring2>
  21. struct ls_less
  22. {
  23. typedef typename boost::range_iterator<Linestring1 const>::type Iterator1;
  24. typedef typename boost::range_iterator<Linestring2 const>::type Iterator2;
  25. typedef bg::less<typename bg::point_type<Linestring1>::type> point_less;
  26. bool operator()(Linestring1 const& linestring1,
  27. Linestring2 const& linestring2) const
  28. {
  29. if (boost::size(linestring1) != boost::size(linestring2))
  30. {
  31. return boost::size(linestring1) < boost::size(linestring2);
  32. }
  33. Iterator1 it1 = boost::begin(linestring1);
  34. Iterator2 it2 = boost::begin(linestring2);
  35. point_less less;
  36. for (; it1 != boost::end(linestring1); ++it1, ++it2)
  37. {
  38. if (less(*it1, *it2))
  39. {
  40. return true;
  41. }
  42. if (less(*it2, *it1))
  43. {
  44. return false;
  45. }
  46. }
  47. return false;
  48. }
  49. };
  50. template <typename Linestring1, typename Linestring2>
  51. struct ls_equal
  52. {
  53. bool operator()(Linestring1 const& linestring1,
  54. Linestring2 const& linestring2) const
  55. {
  56. ls_less<Linestring1, Linestring2> less;
  57. return ! less(linestring1, linestring2)
  58. && ! less(linestring2, linestring1);
  59. }
  60. };
  61. template <typename Point1, typename Point2>
  62. class pt_equal
  63. {
  64. private:
  65. double m_tolerence;
  66. template <typename T>
  67. static inline T const& get_max(T const& a, T const& b, T const& c)
  68. {
  69. return (std::max)((std::max)(a, b), c);
  70. }
  71. template <typename T>
  72. static inline bool check_close(T const& a, T const& b, T const& tol)
  73. {
  74. return (a == b)
  75. || (std::abs(a - b) <= tol * get_max(std::abs(a), std::abs(b), 1.0));
  76. }
  77. public:
  78. pt_equal(double tolerence) : m_tolerence(tolerence) {}
  79. bool operator()(Point1 const& point1, Point2 const& point2) const
  80. {
  81. // allow for some tolerence in testing equality of points
  82. return check_close(bg::get<0>(point1), bg::get<0>(point2), m_tolerence)
  83. && check_close(bg::get<1>(point1), bg::get<1>(point2), m_tolerence);
  84. }
  85. };
  86. template <bool EnableUnique = false>
  87. struct multilinestring_equals
  88. {
  89. template <typename MultiLinestring, bool Enable>
  90. struct unique
  91. {
  92. typedef typename boost::range_value<MultiLinestring>::type Linestring;
  93. typedef typename bg::point_type<MultiLinestring>::type point_type;
  94. typedef ls_equal<Linestring, Linestring> linestring_equal;
  95. typedef pt_equal<point_type, point_type> point_equal;
  96. template <typename Range, typename EqualTo>
  97. void apply_to_range(Range& range, EqualTo const& equal_to)
  98. {
  99. range.erase(std::unique(boost::begin(range), boost::end(range),
  100. equal_to),
  101. boost::end(range));
  102. }
  103. void operator()(MultiLinestring& mls, double tolerance)
  104. {
  105. for (typename boost::range_iterator<MultiLinestring>::type it
  106. = boost::begin(mls); it != boost::end(mls); ++it)
  107. {
  108. apply_to_range(*it, point_equal(tolerance));
  109. }
  110. apply_to_range(mls, linestring_equal());
  111. }
  112. };
  113. template <typename MultiLinestring>
  114. struct unique<MultiLinestring, false>
  115. {
  116. void operator()(MultiLinestring&, double)
  117. {
  118. }
  119. };
  120. template <typename MultiLinestring1, typename MultiLinestring2>
  121. static inline
  122. bool apply(MultiLinestring1 const& multilinestring1,
  123. MultiLinestring2 const& multilinestring2,
  124. double tolerance)
  125. {
  126. typedef typename boost::range_iterator
  127. <
  128. MultiLinestring1 const
  129. >::type ls1_iterator;
  130. typedef typename boost::range_iterator
  131. <
  132. MultiLinestring2 const
  133. >::type ls2_iterator;
  134. typedef typename boost::range_value<MultiLinestring1>::type Linestring1;
  135. typedef typename boost::range_value<MultiLinestring2>::type Linestring2;
  136. typedef typename boost::range_iterator
  137. <
  138. Linestring1 const
  139. >::type point1_iterator;
  140. typedef typename boost::range_iterator
  141. <
  142. Linestring2 const
  143. >::type point2_iterator;
  144. typedef ls_less<Linestring1, Linestring2> linestring_less;
  145. typedef pt_equal
  146. <
  147. typename boost::range_value
  148. <
  149. typename boost::range_value<MultiLinestring1>::type
  150. >::type,
  151. typename boost::range_value
  152. <
  153. typename boost::range_value<MultiLinestring2>::type
  154. >::type
  155. > point_equal;
  156. MultiLinestring1 mls1 = multilinestring1;
  157. MultiLinestring2 mls2 = multilinestring2;
  158. std::sort(boost::begin(mls1), boost::end(mls1), linestring_less());
  159. std::sort(boost::begin(mls2), boost::end(mls2), linestring_less());
  160. unique<MultiLinestring1, EnableUnique>()(mls1, tolerance);
  161. unique<MultiLinestring2, EnableUnique>()(mls2, tolerance);
  162. if (boost::size(mls1) != boost::size(mls2))
  163. {
  164. return false;
  165. }
  166. ls1_iterator it1 = boost::begin(mls1);
  167. ls2_iterator it2 = boost::begin(mls2);
  168. for (; it1 != boost::end(mls1); ++it1, ++it2)
  169. {
  170. if (boost::size(*it1) != boost::size(*it2))
  171. {
  172. return false;
  173. }
  174. point1_iterator pit1 = boost::begin(*it1);
  175. point2_iterator pit2 = boost::begin(*it2);
  176. for (; pit1 != boost::end(*it1); ++pit1, ++pit2)
  177. {
  178. if (! point_equal(tolerance)(*pit1, *pit2))
  179. {
  180. return false;
  181. }
  182. }
  183. }
  184. return true;
  185. }
  186. };
  187. class equals
  188. {
  189. private:
  190. template <typename Linestring, typename OutputIterator>
  191. static inline OutputIterator
  192. isolated_point_to_segment(Linestring const& linestring, OutputIterator oit)
  193. {
  194. BOOST_ASSERT( boost::size(linestring) == 1 );
  195. *oit++ = *boost::begin(linestring);
  196. *oit++ = *boost::begin(linestring);
  197. return oit;
  198. }
  199. template <typename MultiLinestring, typename OutputIterator>
  200. static inline OutputIterator
  201. convert_isolated_points_to_segments(MultiLinestring const& multilinestring,
  202. OutputIterator oit)
  203. {
  204. BOOST_AUTO_TPL(it, boost::begin(multilinestring));
  205. for (; it != boost::end(multilinestring); ++it)
  206. {
  207. if (boost::size(*it) == 1)
  208. {
  209. typename boost::range_value<MultiLinestring>::type linestring;
  210. isolated_point_to_segment(*it, std::back_inserter(linestring));
  211. *oit++ = linestring;
  212. }
  213. else
  214. {
  215. *oit++ = *it;
  216. }
  217. }
  218. return oit;
  219. }
  220. template <typename MultiLinestring1, typename MultiLinestring2>
  221. static inline bool apply_base(MultiLinestring1 const& multilinestring1,
  222. MultiLinestring2 const& multilinestring2,
  223. double tolerance)
  224. {
  225. typedef multilinestring_equals<true> mls_equals;
  226. if (mls_equals::apply(multilinestring1, multilinestring2, tolerance))
  227. {
  228. return true;
  229. }
  230. MultiLinestring1 reverse_multilinestring1 = multilinestring1;
  231. bg::reverse(reverse_multilinestring1);
  232. if (mls_equals::apply(reverse_multilinestring1,
  233. multilinestring2,
  234. tolerance))
  235. {
  236. return true;
  237. }
  238. MultiLinestring2 reverse_multilinestring2 = multilinestring2;
  239. bg::reverse(reverse_multilinestring2);
  240. if (mls_equals::apply(multilinestring1,
  241. reverse_multilinestring2,
  242. tolerance))
  243. {
  244. return true;
  245. }
  246. return mls_equals::apply(reverse_multilinestring1,
  247. reverse_multilinestring2,
  248. tolerance);
  249. }
  250. public:
  251. template <typename MultiLinestring1, typename MultiLinestring2>
  252. static inline bool apply(MultiLinestring1 const& multilinestring1,
  253. MultiLinestring2 const& multilinestring2,
  254. double tolerance)
  255. {
  256. #ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
  257. MultiLinestring1 converted_multilinestring1;
  258. convert_isolated_points_to_segments
  259. (multilinestring1, std::back_inserter(converted_multilinestring1));
  260. MultiLinestring2 converted_multilinestring2;
  261. convert_isolated_points_to_segments
  262. (multilinestring2, std::back_inserter(converted_multilinestring2));
  263. return apply_base(converted_multilinestring1,
  264. converted_multilinestring2, tolerance);
  265. #else
  266. return apply_base(multilinestring1, multilinestring2, tolerance);
  267. #endif
  268. }
  269. };
  270. template <typename Output, typename G1, typename G2>
  271. void set_operation_output(std::string const& set_op_id,
  272. std::string const& caseid,
  273. G1 const& g1, G2 const& g2,
  274. Output const& output)
  275. {
  276. boost::ignore_unused(set_op_id, caseid, g1, g2, output);
  277. #if defined(TEST_WITH_SVG)
  278. typedef typename bg::coordinate_type<G1>::type coordinate_type;
  279. typedef typename bg::point_type<G1>::type point_type;
  280. std::ostringstream filename;
  281. filename << "svgs/" << set_op_id << "_" << caseid << ".svg";
  282. std::ofstream svg(filename.str().c_str());
  283. bg::svg_mapper<point_type> mapper(svg, 500, 500);
  284. mapper.add(g1);
  285. mapper.add(g2);
  286. mapper.map(g2, "stroke-opacity:1;stroke:rgb(153,204,0);stroke-width:4");
  287. mapper.map(g1, "stroke-opacity:1;stroke:rgb(51,51,153);stroke-width:2");
  288. BOOST_AUTO_TPL(it, output.begin());
  289. for (; it != output.end(); ++it)
  290. {
  291. if ( boost::size(*it) == 2
  292. && bg::equals(*boost::begin(*it), *++boost::begin(*it)) )
  293. {
  294. // draw isolated points (generated by the intersection operation)
  295. mapper.map(*boost::begin(*it),
  296. "fill:rgb(255,0,255);stroke:rgb(0,0,0);stroke-width:1",
  297. 4);
  298. }
  299. else
  300. {
  301. mapper.map(*it,
  302. "stroke-opacity:0.4;stroke:rgb(255,0,255);stroke-width:8");
  303. }
  304. }
  305. #endif
  306. }
  307. #endif // BOOST_GEOMETRY_TEST_SET_OPS_LINEAR_LINEAR_HPP