Er et punkt inne i et polygon?

Vi tar utgangspunkt i følgende definisjon:
"En polygon eller en mangekant er en lukket kurve i planet, bestående av rette linjestykker. Kurven skjærer ikke seg selv."

Vi tar utgangspunkt i at dataene er beskrevet slik:

// punktene
var Poly=new Array();
// et punkt
function Punkt(x,y){
  this.x=x;  this.y=y;
};

Vi må ha en strategi som er generell. Vi kan ikke forutsette spesielle egenskaper ved polygonet, ut over den definisjonen som er gitt over. Og husk at polygoner kan være konvekse eller konkave. Det er mange måter å angripe dette problemet på, men det er en innfallsvinkel som forenkler problemstillingen:

Anta at punktet vi skal teste er P. Vi tenker en horisontal linje som starter "langt til venstre" og ender "langt til høyre". Så forsøker vi å finne eventuelle skjæringer mellom denne linja og kantene i polygonet. Dersom antall skjæringer til venstre for P er et oddetall så er P inne i polygonet. Siden testlinja er horisontal blir beregning og kontroll av skjæringspunktene forenklet.

Koden for å finne om et punkt er inne i et polygon kan bli slik:

//----------------------
// Sjekk om et punkt p er 
// inne i polygonet Pol
// returnerer true eller false
function Inside(Pol,p)
{
  if(Pol.length<3)
    return false;
  //lukk polygonet midlertidig
  Pol.push(Pol[0]);
  // tell skjæringer til venstre for p
  var antallS=0;
  // sjekk alle polygonets kanter
  for(var pix=0;pix< Pol.length-1;pix++)
  {
    var ps=KryssPunkt(Pol[pix],Pol[pix+1],p.y);
    // ligger det i så fall venstre for p?
    if((ps!=null)&&(ps.x < p.x ))
      antallS++;
  }
  // reset polygonet
  Pol.pop();
  // fant vi et odde antal skjæringer
  // til venstre for testpunktet ?
  return antallS % 2 > 0;
} 

Det som da gjenstår er å lage funksjonen KryssPunkt(), altså den funksjonen som skal finne ut om, og eventuelt hvor, to linjer skjærer hverandre. En av linjene er mellom to vilkårlige punkter og den andre er paralell med x-aksen

Vi kan sette opp uttrykket for to linjer (p1-p2) og (p3-p4) slik:

Siden den ene linja er vannrett ( p4.x=p3.x ) kan vi forenkle beskrivelsen. Vi dropper brøken i den andre ligninga og kaller brøken i den første ligninga for R

R1=(p2.y-p1.y)/(p2.x-p1.x)

Da sitte vi igjen med følgende ligningssystem som skal løses med hensyn på x;

y=R1(x-p1.x)+p1.y-p1.y
y=p3.y

Funksjonen nedenfor benytter dette for å finne en eventuell skjæring.

// Skjæring mellom et linjestykke 
// p1-p2(kanten)og en vannrett linje. 
// returnerer null hvis ingen skjæring
// returnerer skjæringspunktet ellers
function KryssPunkt(p1,p2,y)
{
  if(p1.x == p2.x) 
    return null;

  var R1=(p2.y-p1.y)/(p2.x-p1.x);
  var x=(y+R1*p1.x-p1.y)/R1;
  
  if( (x < Math.min(p1.x,p2.x)) || 
      (x > Math.max(p1.x,p2.x)))
        return false;
  return new pnt(x,y);
}

Du kan teste ved å klikke inne i og utenfor polygonet nedenfor.
Grønn prikk for innenfor og Rød når utenfor.