A somewhat intermittent issue with supposedly Rect.Contains(Point)
method. To be exact, it only happened once and I haven't been able to reproduce it ever since.
There's a block of code that among other things finds an upper bound of a group of points such that the first point in group and the upper boundary point are within a rect of a certain size.
List<Point> points = ...; // a list of points order by X
double groupSize = 10000.0;
while (points.Any())
{
double left = points[0].X;
Rect searchBound = new Rect(left, points[0].Y - groupSize, groupSize, 2.0 * groupSize);
double top = points
.Where(o => searchBound.Contains(o))
.Min(o => o.Y);
...
}
The problem is Min()
throwing an InvalidOperationException: the sequence contains no elements. But the searchBound
at least should contain the first point in sequence that is located exactly on the left boundary. Am I missing something?
I've run a series of tests with random points generator but never been able to reproduce the exception. The Rect.Contains(Point)
docs also do not state anything about the boundary points.
The method of
/// <summary>
/// ContainsInternal - Performs just the "point inside" logic
/// </summary>
/// <returns>
/// bool - true if the point is inside the rect
/// </returns>
/// <param name="x"> The x-coord of the point to test </param>
/// <param name="y"> The y-coord of the point to test </param>
private bool ContainsInternal(double x, double y)
{
// We include points on the edge as "contained".
// We do "x - _width <= _x" instead of "x <= _x + _width"
// so that this check works when _width is PositiveInfinity
// and _x is NegativeInfinity.
return ((x >= _x) && (x - _width <= _x) &&
(y >= _y) && (y - _height <= _y));
}
is being called from Contains
at:
/// <summary>
/// Contains - Returns true if the Point represented by x,y is within the rectangle inclusive of the edges.
/// Returns false otherwise.
/// </summary>
/// <param name="x"> X coordinate of the point which is being tested </param>
/// <param name="y"> Y coordinate of the point which is being tested </param>
/// <returns>
/// Returns true if the Point represented by x,y is within the rectangle.
/// Returns false otherwise.
/// </returns>
public bool Contains(double x, double y)
{
if (IsEmpty)
{
return false;
}
return ContainsInternal(x,y);
}
We can see that it receives a double
for x
and one for y
and it really does the comparison we would expect in ContainsInternal
and Contains
, the method you are calling calls ContainsInternal
as long as IsEmpty
is false. IsEmpty
is
/// <summary>
/// IsEmpty - this returns true if this rect is the Empty rectangle.
/// Note: If width or height are 0 this Rectangle still contains a 0 or 1 dimensional set
/// of points, so this method should not be used to check for 0 area.
/// </summary>
public bool IsEmpty
{
get
{
// The funny width and height tests are to handle NaNs
Debug.Assert((!(_width < 0) && !(_height < 0)) || (this == Empty));
return _width < 0;
}
}
We see that the size of _width
is being checked for being positive, but the _height
is not being checked for.
So, the possible causes for your problem seem to be:
_x
or _y
might have had some strange valuesSo, you would need to make sure that you test your rect with all kinds of values, among which:
if all your tests are passed, then it's perfectly valid to consider this as a non-issue unless it reoccurs at some point.