1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test
3
4 // Copyright (c) 2010-2015 Barend Gehrels, Amsterdam, the Netherlands.
5
6 // Use, modification and distribution is subject to the Boost Software License,
7 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9
10 #include <iostream>
11 #include <string>
12
13
14 #include <geometry_test_common.hpp>
15
16 #include <boost/geometry/algorithms/detail/overlay/dissolver.hpp>
17
18 #include <boost/geometry/strategies/strategies.hpp>
19 #include <boost/geometry/geometries/point_xy.hpp>
20 #include <boost/geometry/geometries/multi_polygon.hpp>
21 #include <boost/geometry/io/wkt/read.hpp>
22
23
24 #include <test_common/test_point.hpp>
25
26
27 #if defined(TEST_WITH_SVG)
28 # include <boost/geometry/io/svg/svg_mapper.hpp>
29 # include <boost/geometry/io/svg/write_svg_multi.hpp>
30 #endif
31
32 // Collection might be a multi-geometry, or std::vector<ring>
33 template <typename GeometryOut, typename Collection, typename T>
test_dissolve_plusmin(std::string const & caseid,Collection const & input,T const & expected_positive_area,T const & expected_negative_area)34 void test_dissolve_plusmin(std::string const& caseid, Collection const& input,
35 T const& expected_positive_area,
36 T const& expected_negative_area)
37 {
38 typedef typename boost::range_value<GeometryOut>::type geometry_type;
39 typedef typename bg::point_type<geometry_type>::type point_type;
40
41
42 GeometryOut output;
43 bg::dissolver(input, output);
44
45 T zero = T();
46 T positive_area = T();
47 T negative_area = T();
48
49 BOOST_FOREACH(geometry_type const& geometry, output)
50 {
51 T a = bg::area(geometry);
52 if (a > zero)
53 {
54 positive_area += a;
55 }
56 else
57 {
58 negative_area += a;
59 }
60 }
61
62 BOOST_CHECK_CLOSE(positive_area, expected_positive_area, 0.001);
63 BOOST_CHECK_CLOSE(negative_area, expected_negative_area, 0.001);
64
65
66 #if defined(TEST_WITH_SVG)
67 {
68 std::ostringstream filename;
69 filename << "dissolve_plusmin_"
70 << caseid << ".svg";
71
72 std::ofstream svg(filename.str().c_str());
73
74 bg::svg_mapper<point_type> mapper(svg, 500, 500);
75
76 typedef typename boost::range_value<Collection>::type value_type;
77 BOOST_FOREACH(value_type const& geometry, input)
78 {
79 mapper.add(geometry);
80 }
81
82 BOOST_FOREACH(value_type const& geometry, input)
83 {
84 mapper.map(geometry,
85 "opacity:0.6;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:0.5");
86 }
87 BOOST_FOREACH(geometry_type const& geometry, output)
88 {
89 mapper.map(geometry,
90 bg::area(geometry) > 0
91 ? "opacity:0.5;fill:none;stroke:rgb(255,0,0);stroke-width:5"
92 : "opacity:0.5;fill:none;stroke:rgb(0,0,255);stroke-width:5"
93 );
94 }
95 }
96 #endif
97
98 }
99
100 template <typename MultiPolygon, typename T>
test_geometry(std::string const & caseid,std::string const & wkt,T const & expected_positive_area,T const & expected_negative_area=T ())101 void test_geometry(std::string const& caseid, std::string const& wkt,
102 T const& expected_positive_area,
103 T const& expected_negative_area = T())
104 {
105
106 MultiPolygon multi_polygon;
107 bg::read_wkt(wkt, multi_polygon);
108
109 // Test std::vector<Polygon> (= multi_polygon)
110 test_dissolve_plusmin<MultiPolygon>(caseid, multi_polygon,
111 expected_positive_area,
112 expected_negative_area);
113
114 // Test std::vector<ring>
115 {
116 typedef typename boost::range_value<MultiPolygon>::type polygon_type;
117 typedef typename bg::ring_type<MultiPolygon>::type ring_type;
118 std::vector<ring_type> rings;
119 BOOST_FOREACH(polygon_type const& polygon, multi_polygon)
120 {
121 rings.push_back(bg::exterior_ring(polygon));
122 }
123
124 test_dissolve_plusmin<MultiPolygon>(caseid + "_rings", rings,
125 expected_positive_area,
126 expected_negative_area);
127 }
128
129 // Test different combinations
130 #define BOOST_GEOMETRY_TEST_PERMUTATIONS
131 #ifdef BOOST_GEOMETRY_TEST_PERMUTATIONS
132
133 int n = multi_polygon.size();
134
135 // test them in all orders
136 std::vector<int> indices;
137 for (int i = 0; i < n; i++)
138 {
139 indices.push_back(i);
140 }
141 int permutation = 0;
142 do
143 {
144 std::ostringstream out;
145 out << caseid;
146 MultiPolygon multi_polygon2;
147 for (int i = 0; i < n; i++)
148 {
149 int index = indices[i];
150 out << "_" << index;
151 multi_polygon2.push_back(multi_polygon[index]);
152 }
153 test_dissolve_plusmin<MultiPolygon>(out.str(), multi_polygon2, expected_positive_area,
154 expected_negative_area);
155 } while (std::next_permutation(indices.begin(), indices.end()));
156 #endif
157 }
158
159 template <typename Point>
test_all()160 void test_all()
161 {
162 typedef bg::model::polygon<Point> polygon;
163 typedef bg::model::multi_polygon<polygon> multi_polygon;
164
165 test_geometry<multi_polygon>("simplex_one",
166 "MULTIPOLYGON(((0 0,1 4,4 1,0 0)))",
167 7.5);
168
169 test_geometry<multi_polygon>("simplex_two",
170 "MULTIPOLYGON(((0 0,1 4,4 1,0 0)),((2 2,3 6,6 3,2 2)))",
171 14.7);
172 test_geometry<multi_polygon>("simplex_three",
173 "MULTIPOLYGON(((0 0,1 4,4 1,0 0)),((2 2,3 6,6 3,2 2)),((3 4,5 6,6 2,3 4)))",
174 16.7945);
175 test_geometry<multi_polygon>("simplex_four",
176 "MULTIPOLYGON(((0 0,1 4,4 1,0 0)),((2 2,3 6,6 3,2 2)),((3 4,5 6,6 2,3 4)),((5 5,7 7,8 4,5 5)))",
177 20.7581);
178
179 // disjoint
180 test_geometry<multi_polygon>("simplex_disjoint",
181 "MULTIPOLYGON(((0 0,1 4,4 1,0 0)),((1 6,2 10,5 7,1 6)),((3 4,5 6,6 2,3 4)),((6 5,8 7,9 4,6 5)))",
182 24.0);
183
184 // new hole of four
185 test_geometry<multi_polygon>("new_hole",
186 "MULTIPOLYGON(((0 0,1 4,4 1,0 0)),((2 2,3 6,6 3,2 2)),((3 4,5 6,6 2,3 4)),((3 1,5 4,8 4,3 1)))",
187 19.5206);
188
189 // intersection of positive/negative ring
190 test_geometry<multi_polygon>("plus_min_one",
191 "MULTIPOLYGON(((0 0,1 4,4 1,0 0)),((2 2,6 3,3 6,2 2)))",
192 7.5, -7.2);
193
194 // negative ring within a positive ring
195 test_geometry<multi_polygon>("plus_min_one_within",
196 "MULTIPOLYGON(((0 0,1 7,7 3,0 0)),((1 2,4 4,2 5,1 2)))",
197 23.0, -3.5);
198
199 // from buffer
200 test_geometry<multi_polygon>("from_buffer_1",
201 "MULTIPOLYGON(((2.4 3.03431,1.71716 3.71716,2.4 4,2.4 3.03431))"
202 ",((2.4 1.96569,2.4 1,1.71716 1.28284,2.4 1.96569))"
203 ",((2.93431 2.5,2.4 3.03431,2.4 1.96569,2.93431 2.5))"
204 ",((3.06569 2.5,3 2.43431,2.93431 2.5,3 2.56569,3.06569 2.5))"
205 ",((-0.4 5.4,4.4 5.4,4.4 3.83431,3.06569 2.5,4.4 1.16569,4.4 -0.4,-0.4 -0.4,-0.4 5.4)))"
206 ,
207 26.0596168239, -0.2854871761);
208
209 }
210
test_main(int,char * [])211 int test_main(int, char* [])
212 {
213 test_all<bg::model::d2::point_xy<double> >();
214 return 0;
215 }
216
217
218