Boost C++ Libraries: Ticket #6366: Bug in "boost::polygon::contains" for polygon_90 type https://svn.boost.org/trac10/ticket/6366 <p> For a polygon ((0,0) (10,0) (10,10) (0,10)) the function "contains" returns true for (15,5) whereas it should return true </p> <pre class="wiki">#include &lt;boost/polygon/polygon.hpp&gt; #include &lt;cassert&gt; #include &lt;iostream&gt; namespace gtl = boost::polygon; using namespace boost::polygon::operators; int main() { //lets construct a 10x10 rectangle shaped polygon typedef gtl::polygon_90_data&lt;int&gt; Polygon; typedef gtl::polygon_traits_90&lt;Polygon&gt;::point_type Point; Point pts[] = { gtl::construct&lt;Point&gt;(0, 0), gtl::construct&lt;Point&gt;(10, 0), gtl::construct&lt;Point&gt;(10, 10), gtl::construct&lt;Point&gt;(0, 10)}; Polygon poly; gtl::set_points(poly, pts, pts+4); Point point = gtl::construct&lt;Point&gt;(15, 5); { // Wrong result here : bool result = gtl::contains(poly, point); std::cout &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; } //assert(!gtl::contains(poly, point)); //assert(!gtl::contains(poly, gtl::construct&lt;Point&gt;(15, 5))); return 0; } </pre><p> The bugs seems to come from line 1176 of "boost\polygon\polygon_traits.hpp" : </p> <pre class="wiki"> //an odd number of edges to the left implies interior pt return counts[winding(polygon) == COUNTERCLOCKWISE ? 0 : 1] % 4 != 0; </pre><p> There is "% 4" whereas the previous comment indicate "an odd number of edges" (this logicaly should be "% 2") </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/6366 Trac 1.4.3 sebastien.mirabel@… Sat, 07 Jan 2012 15:27:07 GMT attachment set https://svn.boost.org/trac10/ticket/6366 https://svn.boost.org/trac10/ticket/6366 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">gtl_polygon_usage_bug.cpp</span> </li> </ul> <p> Based on "gtl_polygon_usage" from the documentation </p> Ticket Lucanus Simonson Wed, 19 Sep 2012 00:36:05 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/6366#comment:1 https://svn.boost.org/trac10/ticket/6366#comment:1 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> This was fixed a long time ago. </p> Ticket sebastien.mirabel@… Mon, 29 Oct 2012 01:05:16 GMT status, version changed; resolution deleted https://svn.boost.org/trac10/ticket/6366#comment:2 https://svn.boost.org/trac10/ticket/6366#comment:2 <ul> <li><strong>status</strong> <span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span> </li> <li><strong>version</strong> <span class="trac-field-old">Boost 1.48.0</span> → <span class="trac-field-new">Boost 1.51.0</span> </li> <li><strong>resolution</strong> <span class="trac-field-deleted">fixed</span> </li> </ul> <p> The bug is still there in 1.51 and in trunk. The bug fixed "a long time ago" is probably an other one with similar behaviour. </p> <p> Here is a program that show more obviously the bug: </p> <pre class="wiki"> #include &lt;boost/polygon/polygon.hpp&gt; #include &lt;cassert&gt; #include &lt;iostream&gt; namespace gtl = boost::polygon; using namespace boost::polygon::operators; int main() { typedef gtl::polygon_90_data&lt;int&gt; Polygon; typedef gtl::polygon_traits_90&lt;Polygon&gt;::point_type Point; //lets construct a 10x10 rectangle shaped polygon Point pts1[] = { gtl::construct&lt;Point&gt;(0, 0), gtl::construct&lt;Point&gt;(10, 0), gtl::construct&lt;Point&gt;(10, 10), gtl::construct&lt;Point&gt;(0, 10) }; Point pts2[] = { gtl::construct&lt;Point&gt;(0, 10), gtl::construct&lt;Point&gt;(10, 10), gtl::construct&lt;Point&gt;(10, 0), gtl::construct&lt;Point&gt;(0, 0) }; Polygon poly1; gtl::set_points(poly1, pts1, pts1+4); Polygon poly2; gtl::set_points(poly2, pts2, pts2+4); Point point1 = gtl::construct&lt;Point&gt;(15, 5); Point point2 = gtl::construct&lt;Point&gt;(5, 5); { bool result; result = gtl::contains(poly1, point1); std::cout &lt;&lt; "15,5 in poly1 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; result = gtl::contains(poly1, point2); std::cout &lt;&lt; " 5,5 in poly1 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; result = gtl::contains(poly2, point1); std::cout &lt;&lt; "15,5 in poly2 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; result = gtl::contains(poly2, point2); std::cout &lt;&lt; " 5,5 in poly2 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; } return 0; } </pre><p> Output: </p> <pre class="wiki">15,5 in poly1 true 5,5 in poly1 true 15,5 in poly2 false 5,5 in poly2 true </pre> Ticket Andrii Sydorchuk Tue, 30 Oct 2012 22:23:40 GMT attachment set https://svn.boost.org/trac10/ticket/6366 https://svn.boost.org/trac10/ticket/6366 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">polygon_traits.patch</span> </li> </ul> <p> Patch </p> Ticket Andrii Sydorchuk Tue, 30 Oct 2012 22:24:47 GMT <link>https://svn.boost.org/trac10/ticket/6366#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:3</guid> <description> <p> Hi Sebastien, </p> <p> I fixed the issue. You can either sync with trunk or patch (check attachments). </p> </description> <category>Ticket</category> </item> <item> <author>sebastien.mirabel@…</author> <pubDate>Sat, 03 Nov 2012 15:17:32 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6366#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:4</guid> <description> <p> Hi Andrii, </p> <p> It works now (tested with trunk). Thanks ! </p> <p> Sébastien </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Andrii Sydorchuk</dc:creator> <pubDate>Wed, 14 Nov 2012 11:41:23 GMT</pubDate> <title>owner, status, milestone changed https://svn.boost.org/trac10/ticket/6366#comment:5 https://svn.boost.org/trac10/ticket/6366#comment:5 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Lucanus Simonson</span> to <span class="trac-author">Andrii Sydorchuk</span> </li> <li><strong>status</strong> <span class="trac-field-old">reopened</span> → <span class="trac-field-new">new</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.53.0</span> </li> </ul> Ticket Andrii Sydorchuk Wed, 06 Mar 2013 22:53:37 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/6366#comment:6 https://svn.boost.org/trac10/ticket/6366#comment:6 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> Ticket anonymous Tue, 25 Feb 2014 17:19:36 GMT <link>https://svn.boost.org/trac10/ticket/6366#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:7</guid> <description> <p> The bug is still there in 1.55 </p> <blockquote> <p> 59 typedef polygon_90_data&lt;int&gt; Polygon; 60 typedef polygon_traits_90&lt;Polygon&gt;::point_type Point; 61 Point pts1[] = { 62 construct&lt;Point&gt;(25200, 7100), 63 construct&lt;Point&gt;(29000, 7100), 64 construct&lt;Point&gt;(29000, 4950), 65 construct&lt;Point&gt;(27100, 4950), 66 construct&lt;Point&gt;(27100, 4250), 67 construct&lt;Point&gt;(33050, 4250), 68 construct&lt;Point&gt;(33050, 7050), 69 construct&lt;Point&gt;(36300, 7050), 70 construct&lt;Point&gt;(36300, 2300), 71 construct&lt;Point&gt;(34700, 2300), 72 construct&lt;Point&gt;(34700, 1600), 73 construct&lt;Point&gt;(37000, 1600), 74 construct&lt;Point&gt;(37000, 3500), 75 construct&lt;Point&gt;(40550, 3500), 76 construct&lt;Point&gt;(40550, 4850), 77 construct&lt;Point&gt;(37000, 4850), 78 construct&lt;Point&gt;(37000, 7100), 79 construct&lt;Point&gt;(37900, 7100), 80 construct&lt;Point&gt;(37900, 7800), 81 construct&lt;Point&gt;(32350, 7800), 82 construct&lt;Point&gt;(32350, 4950), 83 construct&lt;Point&gt;(29700, 4950), 84 construct&lt;Point&gt;(29700, 7100), 85 construct&lt;Point&gt;(30300, 7100), 86 construct&lt;Point&gt;(30300, 7800), 87 construct&lt;Point&gt;(25200, 7800) 88 }; 89 90 Point pts2[] = { 91 construct&lt;Point&gt;(25200, 7800), 92 construct&lt;Point&gt;(30300, 7800), 93 construct&lt;Point&gt;(30300, 7100), 94 construct&lt;Point&gt;(29700, 7100), 95 construct&lt;Point&gt;(29700, 4950), 96 construct&lt;Point&gt;(32350, 4950), 97 construct&lt;Point&gt;(32350, 7800), 98 construct&lt;Point&gt;(37900, 7800), 99 construct&lt;Point&gt;(37900, 7100), </p> </blockquote> <p> 100 construct&lt;Point&gt;(37000, 7100), 101 construct&lt;Point&gt;(37000, 4850), 102 construct&lt;Point&gt;(40550, 4850), 103 construct&lt;Point&gt;(40550, 3500), 104 construct&lt;Point&gt;(37000, 3500), 105 construct&lt;Point&gt;(37000, 1600), 106 construct&lt;Point&gt;(34700, 1600), 107 construct&lt;Point&gt;(34700, 2300), 108 construct&lt;Point&gt;(36300, 2300), 109 construct&lt;Point&gt;(36300, 7050), 110 construct&lt;Point&gt;(33050, 7050), 111 construct&lt;Point&gt;(33050, 4250), 112 construct&lt;Point&gt;(27100, 4250), 113 construct&lt;Point&gt;(27100, 4950), 114 construct&lt;Point&gt;(29000, 4950), 115 construct&lt;Point&gt;(29000, 7100), 116 construct&lt;Point&gt;(25200, 7100) 117 }; 118 119 Polygon poly1; 120 set_points(poly1, pts1, pts1+4); 121 Polygon poly2; 122 set_points(poly2, pts2, pts2+4); 123 124 Point point2 = construct&lt;Point&gt;(28000, 4950); 125 Point point1 = construct&lt;Point&gt;(41900, 4950); 126 127 { 128 bool result; 129 result = contains(poly1, point1, true); 130 std::cout &lt;&lt; x(point1) &lt;&lt; ", " &lt;&lt; y(point1) &lt;&lt; " in poly1 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; 131 132 result = contains(poly2, point1, true); 133 std::cout &lt;&lt; x(point1) &lt;&lt; ", " &lt;&lt; y(point1) &lt;&lt; " in poly2 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; 134 135 result = contains(poly1, point2, true); 136 std::cout &lt;&lt; x(point2) &lt;&lt; ", " &lt;&lt; y(point2) &lt;&lt; " in poly1 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; 137 138 result = contains(poly2, point2, true); 139 std::cout &lt;&lt; x(point2) &lt;&lt; ", " &lt;&lt; y(point2) &lt;&lt; " in poly2 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; 140 } </p> <p> Output: 41900, 4950 in poly1 false 41900, 4950 in poly2 false 28000, 4950 in poly1 true 28000, 4950 in poly2 false </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Tue, 25 Feb 2014 17:24:34 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6366#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:8</guid> <description> <p> The bug is still there in boost_1_55_0!! </p> <blockquote> <p> typedef polygon_90_data&lt;int&gt; Polygon; </p> </blockquote> <blockquote> <p> typedef polygon_traits_90&lt;Polygon&gt;::point_type Point; </p> </blockquote> <blockquote> <p> Point pts1[] = { </p> <blockquote> <p> construct&lt;Point&gt;(25200, 7100), construct&lt;Point&gt;(29000, 7100), construct&lt;Point&gt;(29000, 4950), construct&lt;Point&gt;(27100, 4950), construct&lt;Point&gt;(27100, 4250), construct&lt;Point&gt;(33050, 4250), construct&lt;Point&gt;(33050, 7050), construct&lt;Point&gt;(36300, 7050), construct&lt;Point&gt;(36300, 2300), construct&lt;Point&gt;(34700, 2300), construct&lt;Point&gt;(34700, 1600), construct&lt;Point&gt;(37000, 1600), construct&lt;Point&gt;(37000, 3500), construct&lt;Point&gt;(40550, 3500), construct&lt;Point&gt;(40550, 4850), construct&lt;Point&gt;(37000, 4850), construct&lt;Point&gt;(37000, 7100), construct&lt;Point&gt;(37900, 7100), construct&lt;Point&gt;(37900, 7800), construct&lt;Point&gt;(32350, 7800), construct&lt;Point&gt;(32350, 4950), construct&lt;Point&gt;(29700, 4950), construct&lt;Point&gt;(29700, 7100), construct&lt;Point&gt;(30300, 7100), construct&lt;Point&gt;(30300, 7800), construct&lt;Point&gt;(25200, 7800) </p> </blockquote> <p> }; </p> </blockquote> <blockquote> <p> Point pts2[] = { </p> <blockquote> <p> construct&lt;Point&gt;(25200, 7800), construct&lt;Point&gt;(30300, 7800), construct&lt;Point&gt;(30300, 7100), construct&lt;Point&gt;(29700, 7100), construct&lt;Point&gt;(29700, 4950), construct&lt;Point&gt;(32350, 4950), construct&lt;Point&gt;(32350, 7800), construct&lt;Point&gt;(37900, 7800), construct&lt;Point&gt;(37900, 7100), construct&lt;Point&gt;(37000, 7100), construct&lt;Point&gt;(37000, 4850), construct&lt;Point&gt;(40550, 4850), construct&lt;Point&gt;(40550, 3500), construct&lt;Point&gt;(37000, 3500), construct&lt;Point&gt;(37000, 1600), construct&lt;Point&gt;(34700, 1600), construct&lt;Point&gt;(34700, 2300), construct&lt;Point&gt;(36300, 2300), construct&lt;Point&gt;(36300, 7050), construct&lt;Point&gt;(33050, 7050), construct&lt;Point&gt;(33050, 4250), construct&lt;Point&gt;(27100, 4250), construct&lt;Point&gt;(27100, 4950), construct&lt;Point&gt;(29000, 4950), construct&lt;Point&gt;(29000, 7100), construct&lt;Point&gt;(25200, 7100) </p> </blockquote> <p> }; </p> </blockquote> <blockquote> <p> Polygon poly1; </p> </blockquote> <blockquote> <p> set_points(poly1, pts1, pts1+4); </p> </blockquote> <blockquote> <p> Polygon poly2; </p> </blockquote> <blockquote> <p> set_points(poly2, pts2, pts2+4); </p> </blockquote> <blockquote> <p> Point point2 = construct&lt;Point&gt;(28000, 4950); </p> </blockquote> <blockquote> <p> Point point1 = construct&lt;Point&gt;(41900, 4950); </p> </blockquote> <blockquote> <p> { </p> <blockquote> <p> bool result; </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> result = contains(poly1, point1, true); </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> std::cout &lt;&lt; x(point1) &lt;&lt; ", " &lt;&lt; y(point1) &lt;&lt; " in poly1 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> result = contains(poly2, point1, true); </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> std::cout &lt;&lt; x(point1) &lt;&lt; ", " &lt;&lt; y(point1) &lt;&lt; " in poly2 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> result = contains(poly1, point2, true); </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> std::cout &lt;&lt; x(point2) &lt;&lt; ", " &lt;&lt; y(point2) &lt;&lt; " in poly1 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> result = contains(poly2, point2, true); </p> </blockquote> </blockquote> <blockquote> <blockquote> <p> std::cout &lt;&lt; x(point2) &lt;&lt; ", " &lt;&lt; y(point2) &lt;&lt; " in poly2 " &lt;&lt; std::boolalpha &lt;&lt; result &lt;&lt; std::endl; </p> </blockquote> <p> } </p> </blockquote> <p> Output: </p> <p> 41900, 4950 in poly1 false </p> <p> 41900, 4950 in poly2 false </p> <p> 28000, 4950 in poly1 true </p> <p> 28000, 4950 in poly2 false </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Andrii Sydorchuk</dc:creator> <pubDate>Wed, 26 Feb 2014 21:56:43 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6366#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:9</guid> <description> <p> From the brief view on the last example I don't see any unexpected behavior. Please clarify the issue. </p> <p> Andrii </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Sébastien</dc:creator> <pubDate>Thu, 27 Feb 2014 01:03:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6366#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:10</guid> <description> <p> <strong>@Andrii:</strong> I just take a look at "anonymous" test and there is un error in his code because he uses "set_points(poly1, pts1, pts1<strong>+4</strong>);" whereas he use an array of <strong>26</strong> points. </p> <p> <strong>@anonymous:</strong> Do you still have the bug if you replace 4 by the correct size ? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Thu, 27 Feb 2014 13:30:25 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6366#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:11</guid> <description> <p> Sorry for my typo, set_points(poly1, pts1, pts1+4) and set_points(poly2, pts2, pts2+4) should be set_points(poly1, pts1, pts1+26) and set_points(poly2, pts2, pts2+26), respectively. </p> <p> However, it still got the wrong results after fixing the typo. poly1 and poly2 are actually the same shape and the results I got are shown as follows: </p> <p> 41900, 4950 in poly1 true </p> <p> 41900, 4950 in poly2 true </p> <p> 28000, 4950 in poly1 true </p> <p> 28000, 4950 in poly2 true </p> <p> The correct results should be as follows, where poly1(poly2) does not contain point1: </p> <p> 41900, 4950 in poly1 false </p> <p> 41900, 4950 in poly2 false </p> <p> 28000, 4950 in poly1 true </p> <p> 28000, 4950 in poly2 true </p> </description> <category>Ticket</category> </item> <item> <author>Sébastien <sebastien.mirabel@…></author> <pubDate>Mon, 03 Mar 2014 01:09:52 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6366#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:12</guid> <description> <p> <strong>@anonymous:</strong> I'm not sure "contains" is aware of orientation of polygons (I don't know very well this library, I have only submitted the bug). You should probably use it in combination with "winding" function. Somebody will probably answer you if you ask on boost mailing list. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Andrii Sydorchuk</dc:creator> <pubDate>Mon, 03 Mar 2014 02:00:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/6366#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/6366#comment:13</guid> <description> <p> Thanks for the follow up, I was able to reproduce the issue. Investigating. </p> <p> Andrii </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Andrii Sydorchuk</dc:creator> <pubDate>Wed, 19 Mar 2014 20:20:40 GMT</pubDate> <title>milestone changed https://svn.boost.org/trac10/ticket/6366#comment:14 https://svn.boost.org/trac10/ticket/6366#comment:14 <ul> <li><strong>milestone</strong> <span class="trac-field-old">Boost 1.53.0</span> → <span class="trac-field-new">Boost 1.57.0</span> </li> </ul> <p> Thanks for the report again! I've fixed the issue in both develop and master branches of <a class="ext-link" href="https://github.com/boostorg/polygon"><span class="icon">​</span>https://github.com/boostorg/polygon</a>. Please find the patch for your convenience attached. The change will permanently go into Boost 1.57. </p> Ticket Andrii Sydorchuk Wed, 19 Mar 2014 20:21:27 GMT attachment set https://svn.boost.org/trac10/ticket/6366 https://svn.boost.org/trac10/ticket/6366 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">0001-Polygon-fixing-reopend-issue-6366-defect-in-polygon-.patch</span> </li> </ul> Ticket