Bueno, aquí va otra solución del problema.
Es el método más sencillo que se me ha ocurrido. Se basa en que para entrar el polígono tenemos que atravesar un numero impar de paredes.
-Trazamos una linea horizontal infinita a la altura del punto.
-Calculamos todos los puntos de corte de las rectas que componen el polígono con la recta trazada.
-Contamos el numero de paredes atravesadas hasta encontrar el punto.
-Si el número de paredes atravesadas es IMPAR el punto esta DENTRO del polígono.
-Si el número de paredes atravesadas es PAR el punto esta FUERA del poligono.
No he probado el algoritmo con otros polígonos, pero creo que debe funcionar(aunque sea modificandolo un poco) con cualquier polígono.
Creo que los casos en los que el algoritmo puede fallar son estos:
El punto esta a la altura de un vertice del polígono.
El punto esta a la altura de una linea horizontal del polígono.
El punto esta sobre un lado del polígono.
int algoritmo( const Poligono plgn, const Punto pnt ){
// Implementacion del algoritmo. Resultado = DENTRO/FUERA
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
#define TOCA ( min(plgn.lineas[i].P0.Y,plgn.lineas[i].P1.Y) <= lineaH.P0.Y && lineaH.P0.Y <= max(plgn.lineas[i].P0.Y,plgn.lineas[i].P1.Y) )
int resultado = 0;
int i;
int izq, drch;
Punto cortes[LINEAS_POR_POLIGONO];
Linea lineaH;
// Traza una linea horizontal mas larga que el poligono a la altura del punto.
lineaH.P0.X = pnt.X;
lineaH.P0.Y = pnt.Y;
lineaH.P1.X = pnt.X;
lineaH.P1.Y = pnt.Y;
for( i = 0 ; i < plgn.size ; i++ ){
if( lineaH.P0.X > plgn.lineas[i].P0.X ){
lineaH.P0.X = plgn.lineas[i].P0.X;
}
if( lineaH.P1.X < plgn.lineas[i].P0.X ){
lineaH.P1.X = plgn.lineas[i].P0.X;
}
}
lineaH.P0.X--;
lineaH.P1.X++;
// Comprueba todos los puntos de corte de con la linea trazada
for( i = 0 ; i < plgn.size ; i++ ){
if( TOCA ){
float xa = plgn.lineas[i].P0.X,
ya = plgn.lineas[i].P0.Y,
xb = plgn.lineas[i].P1.X,
yb = plgn.lineas[i].P1.Y;
if( 0 != (xb-xa) ){
float m, b;
m = (yb-ya)/(xb-xa);
b = ((ya*xb)-(yb*xa))/(xb-xa);
if( 0 != m ){
cortes[i].X = (lineaH.P0.Y-b)/m;
cortes[i].Y = lineaH.P0.Y;
}else{
// La linea plgn.lineas[i] es horizontal.
cortes[i].X = pnt.X;
cortes[i].Y = lineaH.P0.Y;
}
}else{
// La linea plgn.lineas[i] es vertical.
cortes[i].X = plgn.lineas[i].P0.X;
cortes[i].Y = lineaH.P0.Y;
}
}else{
cortes[i].X = pnt.X;
cortes[i].Y = pnt.Y+1; // Punto de corte NO valido. No afecta al resultado
}
if( cortes[i].X == plgn.lineas[i].P1.X && cortes[i].Y == plgn.lineas[i].P1.Y ){
if( (plgn.lineas[i].P0.Y < lineaH.P0.Y && plgn.lineas[(i+1)%plgn.size].P1.Y > lineaH.P1.Y)
|| (plgn.lineas[i].P0.Y > lineaH.P0.Y && plgn.lineas[(i+1)%plgn.size].P1.Y < lineaH.P1.Y) ){
i++;
cortes[i].X = pnt.X;
cortes[i].Y = pnt.Y+1;
}
}
}
// Cuenta los puntos de corte a la izq y a la drch del punto
for( i = 0, izq = 0, drch = 0 ; i < plgn.size ; i++ ){
if( cortes[i].Y == pnt.Y ){
if( cortes[i].X < pnt.X ){
izq++;
}
if( cortes[i].X > pnt.X ){
drch++;
}
}
}
// Si hay numero impar de cortes a algun lado del punto, este se encuentra dentro.
if( izq%2 || drch%2 ){
resultado = DENTRO;
}else{
resultado = FUERA;
}
return resultado;
}