#!/usr/bin/perl

# punkt_wewnatrz_wielokata ( $x, $y, @xy )
#
#    Parametry to punkt ($x,$y) oraz wielokat ($x0, $y0, $x1, $y1, ...) w @xy.
#    Procedura zwraca 1 dla punktow znajdujacych sie wewnatrz wielokata
#    i 0 dla punktow poza wielokatem. W przypadku punktow granicznych sytuacja
#    jest bardziej skomplikowana, a jej omowienie wykraczaloby poza tematyke
#    tej ksiazki. Punkty graniczne sa jednak ustalane jednoznacznie;
#    jesli plaszczyzna zostanie podzielona na wiele wielokatow, to kazdy punkt
#    znajdzie sie dokladnie w jednym wielokacie.
#
#    Procedura wywodzi sie z dokumentu FAQ dla grupy dyskusyjnej
#    comp.graphics.algorithms i zostala udostepniona przez Wm. Randolpha Franklina.
#
sub punkt_wewnatrz_wielokata {
    my ( $x, $y, @xy ) = @_;

    my $n = @xy / 2;                      # Liczba punktow wielokata.
    my @i = map { 2 * $_ } 0 .. (@xy/2);  # Parzyste indeksy @xy.
    my @x = map { $xy[ $_ ]     } @i;     # Parzyste indeksy: wspolrzedne x.
    my @y = map { $xy[ $_ + 1 ] } @i;     # Nieparzyste indeksy: wspolrzedne y.

    my ( $i, $j );                        # Indeksy.

    my $polozenie = 0;                    # 0 = na zewnatrz, 1 = wewnatrz.

    for ( $i = 0, $j = $n - 1 ; $i < $n; $j = $i++ ) {
        if (
            (

             # Jesli y znajduje sie w granicach (y-)...
             ( ( $y[ $i ] <= $y ) && ( $y < $y[ $j ] ) ) ||
             ( ( $y[ $j ] <= $y ) && ( $y < $y[ $i ] ) )
            )
            and
            # ... i prosta poprowadzona od punktu (x,y) do nieskonczonosci
            # przecina krawedz pomiedzy i-tym i j-tym punktem...
            ($x
             <
             ( $x[ $j ] - $x[ $i ] ) *
             ( $y - $y[ $i ] ) / ( $y[ $j ] - $y[ $i ] ) + $x[ $i ] )) {
          $polozenie = not $polozenie; # Zmiana polozenia.
      }
    }

    return $polozenie ? 1 : 0;
}

@wielokat = ( 1, 1,  3, 5,  6, 2,  9, 6,  10, 0,  4,2,  5, -2);
print "( 3, 4): ", punkt_wewnatrz_wielokata( 3, 4, @wielokat ), "\n";
print "( 3, 1): ", punkt_wewnatrz_wielokata( 3, 1, @wielokat ), "\n";
print "( 3,-2): ", punkt_wewnatrz_wielokata( 3,-2, @wielokat ), "\n";
print "( 5, 4): ", punkt_wewnatrz_wielokata( 5, 4, @wielokat ), "\n";
print "( 5, 1): ", punkt_wewnatrz_wielokata( 5, 1, @wielokat ), "\n";
print "( 5,-2): ", punkt_wewnatrz_wielokata( 5,-2, @wielokat ), "\n";
print "( 7, 4): ", punkt_wewnatrz_wielokata( 7, 4, @wielokat ), "\n";
print "( 7, 1): ", punkt_wewnatrz_wielokata( 7, 1, @wielokat ), "\n";
print "( 7,-2): ", punkt_wewnatrz_wielokata( 7,-2, @wielokat ), "\n";

