11// Boost.Geometry (aka GGL, Generic Geometry Library)
22// Unit Test
33
4- // Copyright (c) 2010-2017 Barend Gehrels, Amsterdam, the Netherlands.
4+ // Copyright (c) 2010-2025 Barend Gehrels, Amsterdam, the Netherlands.
55
66// This file was modified by Oracle on 2022.
77// Modifications copyright (c) 2022, Oracle and/or its affiliates.
1111// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
1212// http://www.boost.org/LICENSE_1_0.txt)
1313
14- // #define BOOST_GEOMETRY_DEBUG_ENRICH
15- // #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER
14+
15+ #if defined(TEST_WITH_GEOJSON)
16+ #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER
17+ #define BOOST_GEOMETRY_DEBUG_IDENTIFIER
18+ #endif
1619
1720#include < geometry_test_common.hpp>
1821
3336#include < boost/geometry/strategies/strategies.hpp>
3437
3538#include < boost/geometry/io/wkt/wkt.hpp>
36- #include < boost/geometry/multi/io/wkt/wkt.hpp>
37-
38- #include < boost/geometry/multi/algorithms/for_each.hpp>
3939
40- #include < boost/geometry/multi/geometries/multi_linestring.hpp>
41- #include < boost/geometry/multi/geometries/multi_polygon.hpp>
42-
43-
44- #if defined(TEST_WITH_SVG)
45- # include < boost/geometry/io/svg/svg_mapper.hpp>
46- # include < boost/geometry/io/svg/write_svg_multi.hpp>
47- # include < boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
40+ #if defined(TEST_WITH_GEOJSON)
41+ #include < boost/geometry/extensions/gis/io/geojson/geojson_writer.hpp>
42+ #include " dissolve_geojson_visitor.hpp"
4843#endif
4944
5045
@@ -176,135 +171,6 @@ namespace
176171 std::string const dissolve_ticket10713 = " POLYGON((-0.7189743518829346 4.1308121681213379, 0.0831791982054710 4.1034231185913086, 0.1004156470298767 4.1107301712036133, 0.1044322624802589 4.1026973724365234, 0.0831791982054710 4.1034231185913086, -0.7711903452873230 3.7412264347076416, -0.7189743518829346 4.1308121681213379))" ;
177172}
178173
179-
180- #if defined(TEST_WITH_SVG)
181- template <typename Mapper>
182- struct map_visitor
183- {
184- map_visitor (Mapper& mapper)
185- : m_mapper(mapper)
186- {}
187-
188- template <typename Turns>
189- void visit_turns (int phase, Turns const & turns)
190- {
191- typedef typename boost::range_value<Turns>::type turn_type;
192- std::size_t index = 0 ;
193- for (turn_type const & turn : turns)
194- {
195- switch (phase)
196- {
197- case 2 : // after self_turns and enrich
198- if (turn.discarded )
199- {
200- m_mapper.map (turn.point , " fill:rgb(255,128,0);" , 2 );
201- }
202- else
203- {
204- m_mapper.map (turn.point , " fill:rgb(255,128,0);"
205- " stroke:rgb(0,0,0);stroke-width:1" , 4 );
206- }
207- break ;
208- case 3 : // after enrich/traverse
209- label_turn (index, turn, -2 , " fill:rgb(0,0,128);" );
210- break ;
211- }
212- index++;
213- }
214- }
215-
216- template <typename Clusters, typename Turns>
217- void visit_clusters (Clusters const & , Turns const & ) {}
218-
219- template <typename Turns, typename Turn, typename Operation>
220- void visit_traverse (Turns const & , Turn const & , Operation const & , char const *)
221- {}
222-
223- template <typename Turns, typename Turn, typename Operation>
224- void visit_traverse_reject (Turns const & , Turn const & , Operation const & ,
225- bg::detail::overlay::traverse_error_type )
226- {}
227-
228- template <typename Rings>
229- void visit_generated_rings (Rings const & rings)
230- {
231- typedef typename boost::range_value<Rings>::type ring_type;
232- for (ring_type const & ring : rings)
233- {
234- double const area = bg::area (ring);
235- std::string const color = area < 0 ? " rgb(255,0,0)" : " rgb(0,0,255)" ;
236- std::string const style = " stroke:" + color
237- + " ;stroke-width:0.1;fill-opacity:0.1;fill:" + color;
238- m_mapper.map (ring, style);
239- }
240- }
241-
242-
243- private :
244-
245- template <typename Turn>
246- bool label_operation (Turn const & turn, std::size_t index, std::ostream& os)
247- {
248- os << bg::operation_char (turn.operations [index].operation );
249- bool result = false ;
250- if (! turn.discarded )
251- {
252- os << " ->" << turn.operations [index].enriched .get_next_turn_index ();
253- result = true ;
254- }
255- if (turn.operations [index].enriched .prefer_start )
256- {
257- os << " $" ;
258- }
259- if (! turn.operations [index].enriched .startable )
260- {
261- os << " @" ;
262- }
263-
264- return result;
265- }
266-
267- template <typename Turn>
268- void label_turn (std::size_t index, Turn const & turn, int y_offset, std::string const & color)
269- {
270- std::ostringstream out;
271- out << index;
272- if (turn.cluster_id != -1 )
273- {
274- out << " c=" << turn.cluster_id << " " ;
275- }
276- bool lab1 = label_operation (turn, 0 , out);
277- out << " / " ;
278- bool lab2 = label_operation (turn, 1 , out);
279- if (turn.discarded )
280- {
281- out << " !" ;
282- }
283-
284- std::string font8 = " font-family:Arial;font-size:6px" ;
285- std::string font6 = " font-family:Arial;font-size:4px" ;
286- std::string style = color + " ;" + font8;
287- if (turn.discarded )
288- {
289- style = " fill:rgb(92,92,92);" + font6;
290- }
291- else if (turn.cluster_id != -1 )
292- {
293- style = color + " ;" + font8;
294- }
295- else if (! lab1 || ! lab2)
296- {
297- style = color + " ;" + font6;
298- }
299-
300- m_mapper.text (turn.point , out.str (), style, 5 , y_offset, 6 );
301- }
302-
303- Mapper& m_mapper;
304- };
305-
306- #endif
307-
308174// ! Unittest settings
309175struct ut_settings
310176{
@@ -334,6 +200,17 @@ void test_dissolve(std::string const& caseid, Geometry const& geometry,
334200 std::size_t expected_point_count,
335201 ut_settings const & settings)
336202{
203+ #if defined(TEST_WITH_GEOJSON)
204+ std::ostringstream filename;
205+ // For QGis, it is usually convenient to always write to the same geojson file.
206+ filename << " /tmp/"
207+ // << caseid << "_"
208+ << " dissolve.geojson" ;
209+ std::ofstream geojson_file (filename.str ().c_str ());
210+
211+ boost::geometry::geojson_writer writer (geojson_file);
212+ #endif
213+
337214 using coordinate_type = typename bg::coordinate_type<Geometry>::type;
338215
339216 static const bool is_line = bg::geometry_id<GeometryOut>::type::value == 2 ;
@@ -350,59 +227,21 @@ void test_dissolve(std::string const& caseid, Geometry const& geometry,
350227 Geometry, Geometry
351228 >::type;
352229
353- using rescale_policy_type = typename bg::rescale_policy_type
354- <
355- typename bg::point_type<Geometry>::type
356- >::type;
357-
358- rescale_policy_type robust_policy
359- = bg::get_rescale_policy<rescale_policy_type>(geometry);
360-
361- // This will optionally also create SVG with turn-debug information
362230 strategy_type strategy;
363231
364-
365- #if ! defined(TEST_WITH_SVG)
366- bg::detail::overlay::overlay_null_visitor visitor;
232+ #if defined(TEST_WITH_GEOJSON)
233+ geojson_visitor visitor (writer);
367234#else
368- std::ostringstream filename;
369- filename << " dissolve_" << caseid << " _"
370- << string_from_type<coordinate_type>::name ()
371- << " .svg" ;
372-
373- std::ofstream svg (filename.str ().c_str ());
374-
375- using mapper_type = bg::svg_mapper
376- <
377- typename bg::point_type<Geometry>::type
378- >;
379-
380- mapper_type mapper (svg, 500 , 500 );
381- mapper.add (geometry);
382-
383- mapper.map (geometry, " fill-opacity:0.5;fill:rgb(153,204,0);"
384- " stroke:rgb(153,204,0);stroke-width:2;fill-rule:nonzero;" );
385-
386- map_visitor<mapper_type> visitor (mapper);
387- #endif
235+ bg::detail::overlay::overlay_null_visitor visitor;
236+ #endif
388237
389238 bg::dispatch::dissolve
390239 <
391240 Geometry,
392241 GeometryOut,
393242 false
394- >::apply (geometry, robust_policy, std::back_inserter (dissolved1),
243+ >::apply (geometry, std::back_inserter (dissolved1),
395244 strategy, visitor);
396-
397- #if defined(TEST_WITH_SVG)
398- for (GeometryOut& dissolved : dissolved1)
399- {
400- mapper.map (dissolved, " fill-opacity:0.1;fill:rgb(255,0,0);"
401- " stroke-opacity:0.4;stroke:rgb(255,0,255);stroke-width:3;"
402- " fill-rule:nonzero;" );
403- }
404- #endif
405-
406245 }
407246
408247 if (settings.test_validity )
@@ -482,8 +321,19 @@ void test_dissolve(std::string const& caseid, Geometry const& geometry,
482321 BOOST_CHECK_MESSAGE (wkt1 == wkt3, caseid << " : output differs: " << wkt1 << " VERSUS " << wkt3);
483322 }
484323 }
485- }
486324
325+ #if defined(TEST_WITH_GEOJSON)
326+ writer.feature (geometry);
327+ writer.add_property (" type" , " input" );
328+
329+ for (const auto & polygon : dissolved3)
330+ {
331+ writer.feature (polygon);
332+ writer.add_property (" type" , " dissolved" );
333+ }
334+ #endif
335+
336+ }
487337
488338template <typename Geometry, typename GeometryOut>
489339void test_one (std::string caseid, std::string const & wkt,
@@ -505,6 +355,8 @@ void test_one(std::string caseid, std::string const& wkt,
505355 expected_clip_count, expected_hole_count, expected_point_count,
506356 settings);
507357
358+ #ifdef BOOST_GEOMETRY_TEST_REVERSE
359+
508360 // Verify if reversed version is indeed identical (it should, because each
509361 // ring is now corrected within dissolve itself
510362 bg::reverse (geometry);
@@ -514,6 +366,7 @@ void test_one(std::string caseid, std::string const& wkt,
514366 expected_area,
515367 expected_clip_count, expected_hole_count, expected_point_count,
516368 settings);
369+ #endif
517370
518371#ifdef BOOST_GEOMETRY_TEST_MULTI_PERMUTATIONS
519372 // Test different combinations of a multi-polygon
@@ -652,7 +505,9 @@ void test_all(ut_settings const& settings_for_sensitive_cases)
652505
653506int test_main (int , char * [])
654507{
508+ #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
655509 test_all<bg::model::d2::point_xy<float >, true >(ut_settings (0.01 ));
510+ #endif
656511 test_all<bg::model::d2::point_xy<double >, true >(ut_settings ());
657512 // Counter clockwise input does not work correctly in all cases, it is
658513 // partly a problem of the test itself
0 commit comments