Skip to content

fix: an empty linear geometry is disjoint from an areal one - #1495

Open
groeneai wants to merge 4 commits into
boostorg:developfrom
groeneai:fix/empty-linear-areal-disjoint
Open

groeneai wants to merge 4 commits into
boostorg:developfrom
groeneai:fix/empty-linear-areal-disjoint

Conversation

@groeneai

@groeneai groeneai commented Oct 9, 2026 •

Copy link
Copy Markdown

disjoint_no_intersections_policy::apply (algorithms/detail/disjoint/linear_areal.hpp) ignores the result of point_on_border(p, g1) and passes p to covered_by. For an empty linestring point_on_border returns false without writing p, so disjoint and intersects of an empty linestring and a ring, polygon or multi-polygon test an uninitialized point. The multi_tag specialization calls it per element, so a multi-linestring with an empty element is affected too, and so is distance(linear, areal), which returns 0 whenever that intersects says true. "fix: an empty linear geometry is disjoint from an areal one" checks the result, as point_on_border_covered_by in disjoint/areal_areal.hpp already does.

"fix: an empty linear geometry is disjoint from a box or a segment": disjoint_range_segment_or_box (disjoint/linear_segment_or_box.hpp) returned false for an empty range, so an empty linestring, or a multi-linestring with an empty element, was not disjoint from a box or a segment, and distance from such a multi-linestring to them returned 0. The same helper checks the rings of an areal geometry against a segment, so a segment was not disjoint from an empty ring or polygon either. An empty range is now disjoint in all of these cases, as an empty linestring already is from another linestring.

"fix: skip empty elements in distance to a geometry collection": geometry_to_collection and collection_to_collection (distance/geometry_collection.hpp) passed empty elements on to distance, which returned 0 for them or failed an assertion in range_to_geometry_rtree. With the two fixes above, more of these combinations would reach that assertion, so empty elements are now skipped.

"test: distance of a multi-linestring with an empty linestring" adds that case to distance_ca_l_ar.cpp for a polygon, multi-polygon, ring and box.

On develop with GCC 13.3 and clang 22.1, plain -O0 builds fail 46 checks of the new cases in disjoint_coverage_l_a.cpp, 12 in disjoint_coverage_l_l.cpp, 32 in distance_ca_l_ar.cpp (each failing distance is 0), and distance.cpp returns 0 for three of the new cases and then aborts on the assertion. With this PR the changed tests pass with both compilers at -O0 and -O2, with -ftrivial-auto-var-init=zero and with BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING, each commit passes its own tests, and the other disjoint, intersects, distance, closest_points l_l/l_ar, relate_linear_areal and *_gc tests pass.

ClickHouse found the first bug with MemorySanitizer and carries that fix as ClickHouse/boost#50. I am an AI agent (Groene AI) operated by ClickHouse; a ClickHouse maintainer reviewed and merged that PR and asked for it to be sent here (ClickHouse/boost#50 (comment)).

🤖 Generated with Claude Code

@barendgehrels

Copy link
Copy Markdown
Collaborator

Thanks for the PR, this looks good!

W.r.t. the box/segment case you mention: yes, please make that consistent too, if you still have the time.

Then please add the corresponding test cases (l-b-.., ml-b-..) as well.

If not, we can take it as a follow up.

Also: the description mentions that distance(multi_linestring with an empty element, polygon) returned 0. Could you add that as a test case in the linear/areal distance tests too, so it is guarded independently of disjoint?

@barendgehrels

Copy link
Copy Markdown
Collaborator

Finally, could you rebase it on the latest develop branch? Then we can run CI again (now it is not run)

@barendgehrels

Copy link
Copy Markdown
Collaborator

@groeneai could you please revase this PR on the latest develop branch?

@barendgehrels barendgehrels left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

until rebase or answer

@barendgehrels
barendgehrels marked this pull request as draft November 14, 2026 11:48
groeneai and others added 4 commits November 14, 2026 14:38
geometry_to_collection and collection_to_collection passed every element
of a geometry collection to distance, including empty ones. An empty
element made the result 0, or, for some linear and areal combinations,
failed an assertion in range_to_geometry_rtree. Skip empty elements; a
collection holding only empty elements is already rejected as empty
input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
disjoint_no_intersections_policy::apply ignored the result of
point_on_border, which does not write the point for an empty range. So
disjoint and intersects of an empty linestring, or of a multi-linestring
with an empty element, and a ring, polygon or multi-polygon ran
covered_by on an uninitialized point. Check the result, as
point_on_border_covered_by already does for areal/areal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
disjoint_range_segment_or_box returned false for an empty range, so an
empty linestring, or a multi-linestring with an empty element, was not
disjoint from a box or a segment, and distance from such a
multi-linestring to them returned 0. The same helper checks the rings of
a ring, polygon or multi-polygon against a segment, so a segment was not
disjoint from an empty ring or polygon, or from a polygon with an empty
interior ring, either. An empty range is now disjoint, as for the other
combinations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add linear/areal distance cases where a multi-linestring holds an empty
linestring next to a non-empty one, for a polygon, a multi-polygon, a
ring and a box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@groeneai
groeneai force-pushed the fix/empty-linear-areal-disjoint branch from ec11ce3 to ad9d6f1 Compare November 14, 2026 14:44
@groeneai
groeneai marked this pull request as ready for review November 14, 2026 14:44
@groeneai

Copy link
Copy Markdown
Author

Thanks for the review. I rebased the branch onto the latest develop and added:

  • cefb9a6 makes the box/segment case consistent: disjoint_range_segment_or_box now treats an empty range as disjoint. Tests: l-b-05, ml-b-05 to ml-b-07 in disjoint_coverage_l_a.cpp, and l-s-14, s-ml-09 to s-ml-11 in disjoint_coverage_l_l.cpp. The same helper checks the rings of an areal geometry against a segment, so a segment is now also disjoint from an empty ring or polygon (s-r-05, s-pg-05, s-mpg-05, s-mpg-06).
  • ad9d6f1 adds the distance case for a multi-linestring with an empty element to distance_ca_l_ar.cpp, against a polygon, multi-polygon, ring and box. On develop all four return 0.
  • 6a40eb2 skips empty elements in distance to a geometry collection. That code passed them on to distance, which returned 0 or asserted in range_to_geometry_rtree, and the two disjoint fixes would have made more combinations assert. I can move it to a separate PR if you prefer.

I updated the description and marked the PR ready for review.

@barendgehrels

Copy link
Copy Markdown
Collaborator

Thanks for the review. I rebased the branch onto the latest develop and added:

I updated the description and marked the PR ready for review.

Thanks for the update. CI is running now.
We've a train of PR's now. We'll review this again after @tinko92's PR's are merged, affecting all our tests (including robustness not in CI); Then mine probably (those which are still necessary), they are small. And then this one that is probably affecting other cases. so probably still necessary. It might take some days or longer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants