`intersection` returns geometrically degenerate linestring (size < 2) for tangent line · Issue #1448 · boostorg/geometry · GitHub
Skip to content

intersection returns geometrically degenerate linestring (size < 2) for tangent line #1448

Open

Description

@nilsnolde

With boost 1.89, consider the following program where we compute the intersection of a box and a tangent line:

code
  #include <boost/geometry.hpp>                                                                                                                                                                                   
  #include <boost/geometry/geometries/point_xy.hpp>                                                                                                                                                               
  #include <boost/geometry/geometries/linestring.hpp>                                                                                                                                                             
  #include <boost/geometry/geometries/box.hpp>                                                                                                                                                                    
  #include <boost/geometry/geometries/multi_linestring.hpp>                                                                                                                                                       
  #include <iostream>                                                                                                                                                                                             
                                                                                                                                                                                                                  
  namespace bg = boost::geometry;                                                                                                                                                                                 
                                                                                                                                                                                                                  
  int main() {                                                                                                                                                                                                    
      using point_t = bg::model::d2::point_xy<int32_t>;                                                                                                                                                               
      using linestring_t = bg::model::linestring<point_t>;                                                                                                                                                        
      using box_t = bg::model::box<point_t>;                                                                                                                                                                      
      using multi_linestring_t = bg::model::multi_linestring<linestring_t>;                                                                                                                                       
                                                                                                                                                                                                                  
      box_t clip_box{{0, 0}, {4096, 4096}};                                                                                                                                                                       
                                                                                                                                                                                                                  
      // Line with one point exactly on the box border (4096, 4000)                                                                                                                                               
      // and the other point outside the box (4100, 4010)                                                                                                                                                         
      linestring_t line{{4100, 4000}, {4100, 4010}};                                                                                                                                                              
                                                                                                                                                                                                                  
      multi_linestring_t result;                                                                                                                                                                                  
      bg::intersection(line, clip_box, result);                                                                                                                                                                   
                                                                                                                                                                                                                  
      std::cout << "Input line: " << bg::wkt(line) << "\n";                                                                                                                                                       
      std::cout << "Clip box: " << bg::wkt(clip_box) << "\n";                                                                                                                                                     
      std::cout << "Result size: " << result.size() << "\n";                                                                                                                                                      
                                                                                                                                                                                                                  
      for (size_t i = 0; i < result.size(); ++i) {                                                                                                                                                                
          std::cout << "Result[" << i << "]: " << bg::wkt(result[i])                                                                                                                                              
                    << " (num_points=" << result[i].size() << ")\n";                                                                                                                                              
      }                                                                                                                                                                                                                         
                                                                                                                                                                                                                  
      return 0;                                                                                                                                                                                                   
  }                                                                                                                                                                                                      

Compile with g++ -std=c++17 -o boost_intersection_bug boost_intersection_bug.cpp and run ./boost_intersection_bug.

The output would be

  Input line: LINESTRING(4096 4000,4100 4010)                                                                                                                                                                     
  Clip box: POLYGON((0 0,0 4096,4096 4096,4096 0,0 0))             
  Result size: 1                                                                                                                                                                                                  
  Result[0]: LINESTRING(4096 4000) (num_points=1)

I'd have hoped for Result size: 0 because there is actually no intersection for all practical purposes well, that's bit far.. I understand that it's geometrically correct that the intersection is a point, but type-wise it's more a bug IMHO to return an invalid linestring type.

Sorry if this is a duplicate, skimming the issues didn't surface anything like-wise.

Activity

  1. tinko92 commented on Apr 16, 2026

    @tinko92
    Collaborator

    I don't get your output. I think

          linestring_t line{{4100, 4000}, {4100, 4010}};                                                                                                                                                              

    should be

          linestring_t line{{4096, 4000}, {4100, 4010}};                                                                                                                                                              

    From the OGC SFS

    ⎯ Intersection (anotherGeometry: Geometry): Geometry — Returns a geometric object that represents the
    Point set intersection of this geometric object with anotherGeometry.
    [...]
    Polygons are topologically closed; [i.e. they include their boundary points]
    [...]
    A Curve is defined as topologically closed, that is, it contains its endpoints f(a) and f(b).
    [...]
    A LineString is a Curve

    So the intersection being non-empty is correct geometrically and also by specification. But from my understanding LINESTRING(x y) is also not a valid LINESTRING but only a valid POINT (I cannot find specific wording in the OGC that prohibits this, but all examples of linestrings, lines and curves strongly indicate this).

    Changing the behaviour here sounds very dangerous. I propose to mark this wontfix and to document in the operations that degenerate output geometries are possible when the correct result is neither empty nor representable in the given output type.

    Otherwise it would be necessary to either change behaviour that users may already rely on, silently violate the spec of the operation, silently violate the spec of the output geometry or requiring the output for every overlay operation to be of some collection of variations type (which would also break user code).

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions