Jednoduché geometrické výpočty

V tomto článku si ukážeme nějaké základní geometrické výpočty v rovině. Kdybyste je někdy potřebovali, tak si je jen okopírujete, anebo vás to může motivovat k psaní vlastních, pokročilejších funkcí :)

Začneme napsáním základních funkcí, které budeme využívat při psaní složitějších. Můžeme je dávat jako statické metody do třídy Geometry.

Vzdálenost dvou bodů

Vzdálenost dvou bodů (v prostoru s eukleidovskou metrikou) spočítáme Pythagorovou větou ($c = \sqrt{a\times a + b \times b}$).

Kód

 
public static function Distance(a:*, b:*):Number
{
   return(Math.sqrt( (b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y-a.y) ));
}

Zda bod leží v obdélníku

Obdélník mějme definovaný dvěma body: levým horním a pravým dolním rohem ("b" a "c"). Ptáme se, jestli bod "a" leží uvnitř obdélníku. a.x musí být mezi b.x a c.x, a.y musí být mezi b.y a c.y.

Kód

public static function isInRect(a:*, b:*, c:*):Boolean
{
   if(a.x >= Math.min(b.x, c.x) && a.x <= Math.max(b.x, c.x)
   && a.y >= Math.min(b.y, c.y) && a.y <= Math.max(b.y, c.y)) 
   return true;
   return false;
}

Průsečík dvou úseček / přímek

Mějme úsečky "a", "b" definované dvěma body (začátky "a1", "b1" a konce "a2", "b2"). Chceme zjistit bod, kde se protínají. Nejdřív najdeme průsečík přímek a, b. Aby to byl průsečík úseček, musí ležet mezi začátky a konci obou úseček.

Při výpočtu průsečíku si přímku převedeme do směrnicového tvaru $y = f\times x + g$, kde "f" je směrnice a "g" je svislý posun.

Kód

public static function GetLineIntersection(a1:*, a2:*, b1:*, b2:*):Point
{
   var f1:Number = -(a2.y - a1.y) / (a1.x - a2.x);
   var f2:Number = -(b2.y - b1.y) / (b1.x - b2.x);
   var g1:Number = a1.y - f1 * a1.x;
   var g2:Number = b1.y - f2 * b1.x;

   // rovnoběžky -> žádný průsečík
   if(f1 == f2) return null;
   
   var inter:Point;
   if       (a1.x == a2.x) inter = new Point(a1.x, f2*a1.x + g2);
   else if  (b1.x == b2.x) inter = new Point(b1.x, f1*b1.x + g1);
   else     
   {
      inter = new Point((g2-g1)/(f1 -f2),0);
      inter.y =  f1 * inter.x + g1;
   }

   if(isInRect(inter, a1, a2) && isInRect(inter, b1, b2)) return inter;
   return null;
}

Střed kružnice opsané

Mějme tři body v rovině (a, b, c). Hledáme kružnici (její střed a poloměr), která prochází těmito třemi body. Tj. hledáme bod (střed kružnice), který má stejnou vzdálenost od a, b, c. Uděláme si osu úsečky a,b (to jsou body se stejnou vzdáleností k "a" a "b"), osu úsečky b,c (body stejně vzdáleny od b, c) a průsečík těchto os je stejně vzdálen od a, b, c.

Kód

public static function GetCircumcenter(a:*, b:*, c:*):Point
{
   // m1 - bod uprostřed (a,b), osa ním prochází
   var f1 = (b.x - a.x) / (a.y - b.y);
   var m1 = new Point((a.x + b.x)/2, (a.y + b.y)/2);
   var g1 = m1.y - f1*m1.x;

   var f2 = (c.x - b.x) / (b.y - c.y);
   var m2 = new Point((b.x + c.x)/2, (b.y + c.y)/2);
   var g2 = m2.y - f2*m2.x;

   // ošetření degenerovaných případů
   // - tři body na přímce
   if     (f1 == f2)   return null;
   // - a, b ve stejné výšce -> směrnice osy |ab| = nekonečno
   else if(a.y == b.y) return new Point(m1.x, f2*m1.x + g2);
   else if(b.y == c.y) return new Point(m2.x, f1*m2.x + g1);

   var x:Number = (g2-g1) / (f1 - f2);
   return new Point(x, f1*x + g1);
}

14 komentářů:

  1. Anonymní ... (21. dubna 2011 v 9:30)

    Vyborne spracovanie. Videl som uz rozne ukazky geometrie ale toto je najlepsie.

    Chysta sa aj pokracovanie?

  2. Anonymní ... (21. dubna 2011 v 9:34)

    Chybka? Ked sa pohybuje lavym-hornym bodom tej cervenej kruznice pomaly hore a dolu tak tam preblikavaju ciary veduce k lavemu hornemu okraju plochy Flash plazera... Je to takto OK?

  3. Anonymní ... (21. dubna 2011 v 9:37)

    Tak jo,, vyzera to na delenie nulou pri vypocte:
    var f1 = (b.x - a.x) / (a.y - b.y);
    a f2.

  4. Ivan ... (22. dubna 2011 v 15:53)

    Ahoj, dobrý postřeh! :) Mohou nastat degenerované stavy (osa přímky svislá -> směrnice nekonečno, s tím nejde moc počítat). Už jsem to opravil.
    Máte zájem o nějaké konkrétní pokračování?

  5. Anonymní ... (23. dubna 2011 v 12:23)

    Convex hull, test bodu v polygone s lubovolnym tvarom, curve fitting - kreslenie ciary rukou a jej nasledne zjednodusenie, cosi uz je hotove - http://www.flashandmath.com/devarticles/index.html.

  6. Anonymní ... (23. dubna 2011 v 13:03)

    Tak, sorry - http://active.tutsplus.com/tutorials/actionscript/euclidean-vectors-in-flash/ - bod v polygone

  7. Anonymní ... (25. dubna 2011 v 3:55)

    Pri teste prisesecnikov ciar - BUG?
    http://img823.imageshack.us/i/priesecnikyciar.png/

  8. Anonymní ... (25. dubna 2011 v 3:57)

    Uvital by som upravene verzie AS3.0. Diky.

  9. Anonymní ... (25. dubna 2011 v 4:04)

    No a snad posledny BUG...
    http://img594.imageshack.us/i/opisanakruznica.png/

  10. Ivan ... (26. dubna 2011 v 11:16)

    Díky za připomínky. Jedná se o stejné degenerované případy - svislé čáry a rovnoběžky. Opravil jsem to.

  11. Anonymní ... (27. dubna 2011 v 6:41)

    Este ta kruznica - http://img7.imageshack.us/i/kruznicabodynajednejpri.png/ ked su body v rovine ALEBO na jednej priamke.

    Bude aj AS3.0 k dispozicii?

  12. Ivan ... (27. dubna 2011 v 11:12)

    Kód je teď v AS3.0 (možná splňuje i AS2). Kružnice je podle mě správně. Jen to flash blbě vykresluje (občas mu dělá problémy, když má kreslit na "velké souřadnice").

  13. Anonymní ... (29. dubna 2011 v 5:24)

    Super stránky.

  14. Ondra ... (19. ledna 2014 v 11:23)

    Velmi pěkně napsané :) . Ale když jsem koukal na tvůj výpočet průsečíků dvou přímek, tak jak řešíš pokud bod a1x a2x leží v rovině? Nevím jaký je to jazyk, zde totiž může nastat dělení nulou. Pak nebude dávat zbytek výpočtu smysl.

Okomentovat