Boost C++ Libraries: Ticket #10772: boost::geometry::within() does not recognize empty boxes https://svn.boost.org/trac10/ticket/10772 <p> If boost::geometry::within() is used to check whether an empty box (i.e. a point) is within another box, false is always returned. This is not the correct behavior because: </p> <ol><li>OGC defines: a.Within(b) ⇔ (a∩b=a) ∧ (I(a)∩E(b)=∅) which holds true. The intersection of an empty box <em>a</em> and a surrounding box <em>b</em> yields <em>a</em>. Since <em>a</em> has no interior, I(a)=∅, thus the second condition is also true. </li><li>Empty boxes should be treated as points. When using a point model instead of an empty box, the check returns the correct result as expected. </li></ol><p> See also the following complete minimal code (it includes also other geometry algorithms that are computed consistently for points and empty boxes): </p> <pre class="wiki">#include &lt;boost/geometry/geometries/point_xy.hpp&gt; #include &lt;boost/geometry/geometries/box.hpp&gt; #include &lt;boost/geometry/algorithms/convert.hpp&gt; #include &lt;boost/geometry/algorithms/within.hpp&gt; #include &lt;boost/geometry/algorithms/covered_by.hpp&gt; #include &lt;boost/geometry/algorithms/intersects.hpp&gt; #include &lt;boost/geometry/algorithms/disjoint.hpp&gt; #include &lt;boost/geometry/algorithms/distance.hpp&gt; // needed for within() -- is this intended? #include &lt;iostream&gt; namespace bg = boost::geometry; typedef bg::model::d2::point_xy&lt;float&gt; Point; typedef bg::model::box&lt;Point&gt; Box; int main() { Point point(3, 4); Box pointAsBox; bg::convert(point, pointAsBox); Box surrounding; surrounding.min_corner() = Point(2, 2); surrounding.max_corner() = Point(5, 5); std::cout &lt;&lt; " Point Box" &lt;&lt; std::endl; std::cout &lt;&lt; "within: " &lt;&lt; bg::within(point, surrounding) &lt;&lt; " " &lt;&lt; bg::within(pointAsBox, surrounding) &lt;&lt; "\n"; // 1 0 &lt;- std::cout &lt;&lt; "within (self): " &lt;&lt; bg::within(point, point) &lt;&lt; " " &lt;&lt; bg::within(pointAsBox, pointAsBox) &lt;&lt; "\n"; // 1 0 &lt;- std::cout &lt;&lt; "covered_by: " &lt;&lt; bg::covered_by(point, surrounding) &lt;&lt; " " &lt;&lt; bg::covered_by(pointAsBox, surrounding) &lt;&lt; "\n"; // 1 1 std::cout &lt;&lt; "intersects: " &lt;&lt; bg::intersects(point, surrounding) &lt;&lt; " " &lt;&lt; bg::intersects(pointAsBox, surrounding) &lt;&lt; "\n"; // 1 1 std::cout &lt;&lt; "disjoint: " &lt;&lt; bg::disjoint(point, surrounding) &lt;&lt; " " &lt;&lt; bg::disjoint(pointAsBox, surrounding) &lt;&lt; "\n"; // 0 0 std::cout &lt;&lt; std::endl; } </pre><p> The implementation looks as follows (boost/geometry/strategies/cartesian/box_in_box.hpp, line 32): </p> <pre class="wiki">struct box_within_range { template &lt;typename BoxContainedValue, typename BoxContainingValue&gt; static inline bool apply(BoxContainedValue const&amp; bed_min , BoxContainedValue const&amp; bed_max , BoxContainingValue const&amp; bing_min , BoxContainingValue const&amp; bing_max) { return bing_min &lt;= bed_min &amp;&amp; bed_max &lt;= bing_max // contained in containing &amp;&amp; bed_min &lt; bed_max; // interiors overlap } }; </pre><p> The problem is the second line, which uses &lt; and thus returns false if the coordinates are equal. I'm not sure what the intention is (despite the comment), and whether it is needed at all. </p> <p> The documentation about box model and concept doesn't state whether max_corner's coordinates must be component-wise greater or equal than min_corner's. If so, it seems like valid boxes are a precondition to within() and this line could be removed. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/10772 Trac 1.4.3 awulkiew Wed, 19 Aug 2015 18:48:49 GMT <link>https://svn.boost.org/trac10/ticket/10772#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10772#comment:1</guid> <description> <p> Do you have in mind some specific use case where this is problematic for you or do you think that the library is not OGC-conformant enough in this case? In the first case <code>covered_by()</code> could be used instead. If the latter is true then see below. </p> <p> TL,DR </p> <p> The OGC standard doesn't define Box Geometry (or to be more precise axis-aligned box), it doesn't define when a Box is valid and what's the interior, boundary and exterior of a Box. It's not said that a Box may degenerate to a Point or to a Segment and be still valid Geometry. It's not clear that the definition of an interior and boundary should be taken from other geometries like a Point or a Segment or a Polygon in the case of degenerated 3D Box. And even if it'd probably work well both points mentioned by you not necessarily are true simply because in the OGC specs axis-aligned Boxes doesn't exist. </p> <p> Indeed currently the library uses Box definition different than the one you presented. That is currently a degenerated Box consists only of a boundary (opposed to a Point which has no boundary). It's because this way it allows to use only this small set of 3 conditions to check the <code>within</code> predicate. The last condition is there because for <code>within</code> to be <code>true</code> the interiors must overlap. This way also a small set of conditions is needed to check <code>touches</code> or <code>overlaps</code> predicates and be consistent with <code>within</code>. </p> <p> Btw, I'm calling it "degenerated" because if it was empty it'd probably have no interior nor boundary, it'd be treated as an exterior so any special predicate should probably return <code>false</code> for it. </p> <p> Now, if we wanted to treat degenerated Box as a Point (a Geometry with no boundary) or Segment (linear interior and 2-point boundary) we couldn't remove the 3rd condition. Without the 3rd condition <code>within</code> would return <code>true</code> incorrectly e.g. for a degenerated Box overlapping the boundary of a second non-degenerated Box. In order to make it "OGC-conformant" we'd be forced to add 2 more conditions: </p> <ul><li>check if a contained degenerated <a class="missing wiki">Box/Point</a> is on the boundary of containing because then the interiors wouldn't overlap </li><li>check if containing Box is not degenerated as well because in this case it wouldn't have a boundary, so a <code>within</code> could return <code>true</code> in this case (for both degenerated). </li></ul><p> Not to mention that we'd be forced to change the implementation of <code>touches</code> in a similar way, so add more conditions. Also, since a Box might degenerate to a Segment we'd be forced to add more conditions to <code>overlaps</code> and support Boxes in <code>crosses</code>. To sum up, currently <code>within</code> uses a definition of a Box which is consistent across spatial predicates and allows to implement them with a minimal set of conditions. </p> <p> With that said, I'm not against removing the third condition. However I'd like to hear more "complete" proposal, taking into account other predicates and providing a clear definition of a Box. If we removed the 3rd condition the predicate check would be simpler/faster. The Box is not defined in the OGC-specification so we may basically do whatever we think is the best. But it would be less consistent across functions and still not "OGC-conformant". It would work exactly how <code>covered_by</code> works right now so wouldn't add functionality. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>awulkiew</dc:creator> <pubDate>Mon, 07 Sep 2015 12:54:36 GMT</pubDate> <title>owner, status changed https://svn.boost.org/trac10/ticket/10772#comment:2 https://svn.boost.org/trac10/ticket/10772#comment:2 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Barend Gehrels</span> to <span class="trac-author">awulkiew</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> Ticket