Vector2? searchHoleEntrance( Vertices polygon, Vector2? lastHoleEntrance )
{
if( polygon == null )
throw new ArgumentNullException( "'polygon' can't be null." );
if( polygon.Count < 3 )
throw new ArgumentException( "'polygon.MainPolygon.Count' can't be less then 3." );
List<float> xCoords;
Vector2? entrance;
int startY;
int endY;
int lastSolid = 0;
bool foundSolid;
bool foundTransparent;
// Set start y coordinate.
if( lastHoleEntrance.HasValue )
{
// We need the y coordinate only.
startY = (int)lastHoleEntrance.Value.Y;
}
else
{
// Start from the top of the polygon if last entrance == null.
startY = (int)getTopMostCoord( polygon );
}
// Set the end y coordinate.
endY = (int)getBottomMostCoord( polygon );
if( startY > 0 && startY < _height && endY > 0 && endY < _height )
{
// go from top to bottom of the polygon
for( int y = startY; y <= endY; y++ )
{
// get x-coord of every polygon edge which crosses y
xCoords = searchCrossingEdges( polygon, y );
// We need an even number of crossing edges.
// It's always a pair of start and end edge: nothing | polygon | hole | polygon | nothing ...
// If it's not then don't bother, it's probably a peak ...
// ...which should be filtered out by SearchCrossingEdges() anyway.
if( xCoords.Count > 1 && xCoords.Count % 2 == 0 )
{
// Ok, this is short, but probably a little bit confusing.
// This part searches from left to right between the edges inside the polygon.
// The problem: We are using the polygon data to search in the texture data.
// That's simply not accurate, but necessary because of performance.
for( int i = 0; i < xCoords.Count; i += 2 )
{
foundSolid = false;
foundTransparent = false;
// We search between the edges inside the polygon.
for( int x = (int)xCoords[i]; x <= (int)xCoords[i + 1]; x++ )
{
// First pass: IsSolid might return false.
// In that case the polygon edge doesn't lie on the texture's solid pixel, because of the hull tolearance.
// If the edge lies before the first solid pixel then we need to skip our transparent pixel finds.
// The algorithm starts to search for a relevant transparent pixel (which indicates a possible hole)
// after it has found a solid pixel.
// After we've found a solid and a transparent pixel (a hole's left edge)
// we search for a solid pixel again (a hole's right edge).
// When found the distance of that coodrinate has to be greater then the hull tolerance.
if( isSolid( ref x, ref y ) )
{
if( !foundTransparent )
{
foundSolid = true;
lastSolid = x;
}
if( foundSolid && foundTransparent )
{
entrance = new Vector2( lastSolid, y );
if( distanceToHullAcceptable( polygon, entrance.Value, true ) )
return entrance;
entrance = null;
break;
}
}
else
{
if( foundSolid )
foundTransparent = true;
}
}
}
}
else
{
if( xCoords.Count % 2 == 0 )
Debug.WriteLine( "SearchCrossingEdges() % 2 != 0" );
}
}
}
return null;
}