diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp index 1a64e1827..977ca9d49 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp @@ -63,6 +63,7 @@ public : inline void append_begin_join(point_type const& point) { + DEBUG("begin join"); check(point); cleanup(); @@ -73,11 +74,15 @@ public : inline void append_end_join(point_type const& point) { + clean_split_offs(); + + DEBUG("end join"); do_append(point); } inline void append_begin_hooklet(point_type const& point) { + DEBUG("begin hooklet"); #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER const_cast(m_mapper).map(point, "fill:rgb(0,0,192);", 3); #endif @@ -93,6 +98,7 @@ public : inline void append_end_hooklet(point_type const& point) { + DEBUG("end hooklet"); #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER const_cast(m_mapper).map(point, "fill:rgb(0,0,255);", 4); #endif @@ -149,16 +155,34 @@ private : { if (rit->end >= rit->begin && calculate_ip(point, *rit)) + { + // We HAVE to leave here + // because the deque is cleared in between + return; + } + } + + // Second loop to check for intersections on intersected pieces + for (typename std::deque::const_reverse_iterator rit + = m_pieces.rbegin(); + rit != m_pieces.rend(); + ++rit) + { + if (rit->end >= rit->begin) { - // We HAVE to leave here - // because the deque is cleared in between - return; + if (calculate_ip2(point, *rit)) + { + return; + } } + } #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER - const_cast(m_mapper).map(point, "fill:rgb(0,255,0);", 5); -#endif + if (! m_pieces.empty() && m_pieces.back().end > m_pieces.back().begin) + { + const_cast(m_mapper).map(point, "fill:rgb(0,255,0);", 4); } +#endif } inline bool calculate_ip(point_type const& point, piece const& the_piece) @@ -201,6 +225,46 @@ private : return true; } } + + return false; + } + + inline bool calculate_ip2(point_type const& point, piece const& the_piece) + { + segment_type segment1(m_previous_point, point); + + // No IP found. Check if it is in the split off + if (! the_piece.split_off.empty() && the_piece.type == 'I') + { + //typedef typename boost::reverse_iterator::type ritt; + typedef typename Range::const_reverse_iterator ritt; + ritt previous = the_piece.split_off.rbegin(); + for (ritt rit = previous++; rit != the_piece.split_off.rend(); ++rit) + { + segment_type segment2(*rit, *previous); + segment_intersection_points is + = policy::apply(segment1, segment2); + if (is.count == 1) + { + Range split_off; + if (get_valid_split(is.intersections[0], the_piece.begin + 1, split_off)) + { + DEBUG("split off from splitted off"); + + add_ip(is.intersections[0], the_piece.begin + 1, the_piece, split_off); + +#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER + const_cast(m_mapper).map(is.intersections[0], "fill:rgb(255,255,0);", 4); + const_cast(m_mapper).map(m_range[the_piece.begin], "fill:rgb(255,192,0);", 4); + const_cast(m_mapper).map(split_off, "fill:none;stroke:rgb(255,192,0);stroke-width:2"); +#endif + return true; + } + + } + previous = rit; + } + } return false; } @@ -249,6 +313,32 @@ private : m_pieces.resize(0); } } + + inline void clean_split_offs() + { + for (typename std::deque::iterator it = m_pieces.begin(); + it != m_pieces.end(); + ++it) + { + it->split_off.resize(0); + } + } + + inline void DEBUG(std::string const& caption) + { +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_APPENDER + std::cout << " " << caption; + for (typename std::deque::iterator it + = m_pieces.begin(); + it != m_pieces.end(); + ++it) + { + std::cout << " " << it->type << " " << it->begin << "-" << it->end + << " " << it->split_off.size(); + } + std::cout << std::endl; +#endif + } }; diff --git a/test_extensions/algorithms/buffer/polygon_buffer.cpp b/test_extensions/algorithms/buffer/polygon_buffer.cpp index 157c8e4d8..03e63b264 100644 --- a/test_extensions/algorithms/buffer/polygon_buffer.cpp +++ b/test_extensions/algorithms/buffer/polygon_buffer.cpp @@ -106,10 +106,12 @@ void test_all() test_one("arrow6", arrow, 'r', 32.2572740033805, 0.6); test_one(true, "tipped_aitch3", tipped_aitch, 'm', 54.865, 0.3); - test_one(true, "tipped_aitch9", tipped_aitch, 'm', 75.685, 0.9); + test_one(true, "tipped_aitch9", tipped_aitch, 'm', 77.44, 0.9); test_one(true, "tipped_aitch13", tipped_aitch, 'm', 89.365, 1.3); + + // SQL Server: 55.205415532967 76.6468846383224 90.642916957136 test_one(true, "tipped_aitch3", tipped_aitch, 'r', 54.7552, 0.3); - test_one(true, "tipped_aitch9", tipped_aitch, 'r', 75.2957, 0.9); + test_one(true, "tipped_aitch9", tipped_aitch, 'r', 76.6457, 0.9); test_one(true, "tipped_aitch13", tipped_aitch, 'r', 88.6906, 1.3); test_one(true, "snake4", snake, 'm', 63.76, 0.4); @@ -120,29 +122,33 @@ void test_all() //return; - test_one(true, "flower1", flower, 'r', 71.986, 0.1); + test_one("flower1", flower, 'm', 67.613949189084963, 0.1); + test_one("flower20", flower, 'm', 74.7020267929856, 0.20); test_one("flower25", flower, 'm', 78.225583936485492, 0.25); test_one("flower30", flower, 'm', 81.492494146177947, 0.30); //test_one("flower35", flower, 'm', 84.694183819917185, 0.35); - test_one("flower4", flower, 'm', 87.8306529577, 0.4); + test_one("flower40", flower, 'm', 87.8306529577, 0.40); test_one("flower45", flower, 'm', 90.901901559536029, 0.45); test_one("flower50", flower, 'm', 93.907929625415662, 0.50); test_one("flower55", flower, 'm', 96.848737155342079, 0.55); test_one("flower60", flower, 'm', 99.724324149315279, 0.60); - test_one("flower1", flower, 'm', 67.613949189084963, 0.1); - test_one("flower25", flower, 'r', 78.0709684961456, 0.25); - test_one("flower30", flower, 'r', 81.3528270913593, 0.30); - test_one("flower35", flower, 'r', 84.5467340913191, 0.35); - test_one("flower4", flower, 'r', 87.6653813523005, 0.4); - test_one("flower45", flower, 'r', 90.7092077149493, 0.45); - test_one("flower50", flower, 'r', 93.6802057531291, 0.50); - test_one("flower55", flower, 'r', 96.5796252237181, 0.55); - test_one("flower60", flower, 'r', 99.4081550761828, 0.60); + test_one(true, "flower1", flower, 'r', 71.986, 0.1); + test_one(true, "flower20", flower, 'r', 74.7020267929856, 0.20); + test_one(true, "flower25", flower, 'r', 78.0709684961456, 0.25); + test_one(true, "flower30", flower, 'r', 81.3528270913593, 0.30); + test_one(true, "flower35", flower, 'r', 84.5467340913191, 0.35); + test_one(true, "flower40", flower, 'r', 87.6653813523005, 0.40); + test_one(true, "flower45", flower, 'r', 90.7092077149493, 0.45); + test_one(true, "flower50", flower, 'r', 93.6802057531291, 0.50); + test_one(true, "flower55", flower, 'r', 96.5796252237181, 0.55); + test_one(true, "flower60", flower, 'r', 99.4081550761828, 0.60); - //test_one("flower35", flower, 'm', 84.694183819917185, 0.35); // Saw { + // SQL Server: +// 68.6258859984014 90.2254986930165 112.799509089077 136.392823913949 161.224547934625 187.427508982734 +//215.063576036522 244.167935815974 274.764905445676 306.878264367143 340.530496138041 375.720107548269 int const n = 12; double expected_round[n] = { @@ -166,18 +172,24 @@ void test_all() // Bowl { + // Note the values are not completely equal to SQL Server yet. + // This will be caused by the sometimes sloppy rounded corners we still have + // See query below. +//1 43.2425133175081 60.0257800296593 78.3497997564532 98.2145746255142 119.620102487345 142.482792724034 +//2 166.499856911107 191.763334982583 218.446279387336 246.615018368511 276.300134755606 307.518458532186 + int const n = 12; double expected_round[n] = { 44.492, 60.025, 77.097, 95.710, 115.863, 137.472, - 160.235, 184.244, 209.672, 236.586, 265.015, 294.978 + 166.485, 191.744, 209.672, 236.586, 265.015, 294.978 }; double expected_miter[n] = { 44.865, 61.014, 78.948, 98.666, 120.169, 143.374, - 167.974, 193.943, 221.279, 250.000, 280.375, 312.500 + 167.974, 207.443, 221.279, 250.000, 280.375, 312.500 }; for (int i = 1; i <= n; i++) @@ -274,3 +286,35 @@ int test_main(int, char* []) return 0; } + + +/* +BOWL QUERY +=== +with bowl as +( + select geometry::STGeomFromText('POLYGON((1 2,1 7,2 7,3 5,5 4,7 5,8 7,9 7,9 2,1 2))',0) as q +) +select +'1-6' as row +,q.STBuffer(0.5).STArea() as b1 +,q.STBuffer(1.0).STArea() as b2 +,q.STBuffer(1.5).STArea() as b3 +,q.STBuffer(2.0).STArea() as b4 +,q.STBuffer(2.5).STArea() as b5 +,q.STBuffer(3.0).STArea() as b6 + +from bowl +union all +select +'7-12' +,q.STBuffer(3.5).STArea() as b7 +,q.STBuffer(4.0).STArea() as b8 +,q.STBuffer(4.5).STArea() as b9 +,q.STBuffer(5.0).STArea() as b10 +,q.STBuffer(5.5).STArea() as b11 +,q.STBuffer(6.0).STArea() as b12 +from bowl + + +*/ \ No newline at end of file diff --git a/test_extensions/algorithms/buffer/test_buffer.hpp b/test_extensions/algorithms/buffer/test_buffer.hpp index 7dc7b46ad..2d66fc11f 100644 --- a/test_extensions/algorithms/buffer/test_buffer.hpp +++ b/test_extensions/algorithms/buffer/test_buffer.hpp @@ -10,7 +10,7 @@ #ifndef BOOST_GEOMETRY_TEST_BUFFER_HPP #define BOOST_GEOMETRY_TEST_BUFFER_HPP -// #define BOOST_GEOMETRY_DEBUG_WITH_MAPPER +//#define BOOST_GEOMETRY_DEBUG_WITH_MAPPER #define TEST_WITH_SVG #include @@ -112,6 +112,8 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, << string_from_type::name() << "_" << join; + //std::cout << complete.str() << std::endl; + std::ostringstream filename; filename << "buffer_" << complete.str() << ".svg"; @@ -183,17 +185,19 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, } #endif - if (boost::contains(complete.str(), "indentation4_d") - || boost::contains(complete.str(), "indentation5_d") - || boost::contains(complete.str(), "indentation6_d") - || boost::contains(complete.str(), "indentation7_d") - || boost::contains(complete.str(), "indentation8_d") - || boost::contains(complete.str(), "indentation12_d") + if (boost::contains(complete.str(), "bowl") + || boost::contains(complete.str(), "aitch") + || boost::contains(complete.str(), "snake") + || (boost::contains(complete.str(), "indentation") + && ! boost::contains(complete.str(), "neg")) + || (boost::contains(complete.str(), "flower") + && boost::contains(complete.str(), "d_r")) ) { // We dissolve some controlled cases (already, later we will dissolve all), // such that we can detect regressions bg::dissolve(buffered_step1, buffered); + mapper.map(buffered_step1, "opacity:0.3;fill:none;stroke:rgb(0,0,200);stroke-width:2"); } else {