0

I want to determine if point is inside polygon with boost::geometry.

I use function boost::geometry::within and type boost::geometry::linear_ring<boost::geometry::point_2d> to specify contour.

All work fine if I don't need to account orientation of contour.
But in my case I want to account orientation. I mean that if inner region for specific contour is considered limited by its border and finite, then the inner area of inverted contour should be infinite - complementation to area of initial contour.

Is it possible to account orientation of contour in within function?

It can be expessed in the following code:

// Create contour which defines square
boost::geometry::linear_ring<boost::geometry::point_2d> contour;
contour.push_back(boost::geometry::point_2d(4, 2));
contour.push_back(boost::geometry::point_2d(2, 2));
contour.push_back(boost::geometry::point_2d(2, 4));
contour.push_back(boost::geometry::point_2d(4, 4));
contour.push_back(boost::geometry::point_2d(4, 2));

// Create contour which defines square with opposite direction.
boost::geometry::linear_ring<boost::geometry::point_2d> contourInverted = contour;
std::reverse(contourInverted.begin(), contourInverted.end());

// Specify point inside square
boost::geometry::point_2d testPoint(3, 3);

// Perform tests
bool ret1 = boost::geometry::within(testPoint, contour);
bool ret2 = boost::geometry::within(testPoint, contourInverted);

After execution of the code above ret1 and ret2 are both true. But I would have ret1 != ret2.

In general I need to obtain functionaly when ret1 != ret2 for any testPoint (I don't consider border cases here when point is exactly on the border or polygon is degenerated etc...)

I tried different strategies to pass to boost::geometry::within, but I have not obtained what I need.

It seems that functionality which I need or similar is implemented somewhere in the boost::geometry, because the documetation for within has example of polygon with holes. But I have not realised how to use it for my case.

There is also quite simple workaround. I need just write a code to determine orientation of contour. Then I just negate or not result of within function depending on contour orientation. But if boost::geometry has implementation already I don't want to duplicate it.

genpfault
  • 51,148
  • 11
  • 85
  • 139
sergtk
  • 10,714
  • 15
  • 75
  • 130

2 Answers2

2

AFAIK, neither Boost.Geometry nor Boost.Polygon work with "infinite" areas you defined. They do work with polygon with holes and even sets of such polygons.

You might consider adding a big rectangle limiting your universe. Then you can define inverted contour as a hole in such rectangle.

BTW, in many cases one can avoid converting box to a contour. Boost.Geometry provides an adapter "box_view" which allows to use box as if it were a (positively oriented) contour.

As for orientation of an arbitrary contour, probably the easiest way is to compute its area. On the other side, for well-formed ring the orientation is known at compile-time and is provided by meta-functions traits::point_order, see details here

Michael Simbirsky
  • 3,045
  • 1
  • 12
  • 24
0

A few remarks:

  • In Boost.Geometry there is no bg::linear_ring<>, there is bg::model::ring<>.
  • bg::model::ring<> is a model of what in Boost.Geometry is called a Ring which is an areal geometry, a simple Polygon without holes.
  • Ring differs from OGC LinearRing, it's an areal (2d) geometry and it has an orientation. OGC LinearRing is 1d with no orientation.
  • It's possible to set an orientation of bg::model::ring<> in compile-time by passing the 2nd template parameter, see this.
  • a value returned by the area() function for a reversed areal (cartesian) geometry is a negative area (not infinite). But not all functions works for reversed geometries because the library considers them as invalid in general.

In Boost.Geometry the data must reflect the compile-time setup of a geometry, in this case the orientation set for the Ring at compile-time. Otherwise the results may be unexpected. In your case the same value is returned. You can call bg::correct() to automatically correct the orientation and closure before passing the geometry to other functions. You can also call bg::is_valid() to check if everything is ok with your geometry.

So if you want to check if a point overlaps an interior of a geometry you can call within(pt, ring). And if you want to check if a point is on the boundary or overlapping the exterior then !within(pt, ring) should return what you need, which is of course obvious.

If you wanted to take the boundary into account so check if a point overlaps the interior or boundary then you could use covered_by(pt, ring), !disjoint(pt, ring) or intersects(pt, ring). Obviously, the complement in this case could be !covered_by(pt, ring), disjoint(pt, ring) or !intersects(pt, ring).

In the case of Pt/Ring, internally the same code is used to check all of those spatial relations so it shouldn't matter which one is called.

Adam Wulkiewicz
  • 2,068
  • 18
  • 24