Fórum Root.cz

Ostatní => Odkladiště => Téma založeno: Michal Štrba 02. 04. 2013, 14:52:46

Název: Matematický problém s úhly
Přispěvatel: Michal Štrba 02. 04. 2013, 14:52:46
Zdravim!

Neviem ci som uplne blby, ale nijakovsky sa mi nedari vyriesit problem, ktory musim vyriesit aby som mohol pokracovat vo vyvoji mojej hry.
Problem je asi takyto:
Uhly idu do jedneho smeru kladne a do druheho zaporne. To znameno, ze uhol -180 a +180 je ten isty a tiez uhly ako -200 a 160 su rovnake. -350 je to iste ako 10 a naopak.
Problem je tento: mam zadany pociatocny uhol (moze byt aj 23281) a chcem zistit najmenej o kolko stupnov sa musim otocit aby som sa otocil na zadany uhol.
Priklad: pociatocny uhol je 170 a mam sa otocit na uhol -170. Musim sa otocit o +20 stupnov pretoze 170+20=190 je to iste ako -170 (nebudem sa otocit o -340).

Bol by som velmi vdacny tomu, kto by mi to algoritmicky vyriesil, samozrejme na rieseni budem dalej pracovat sam.
Název: Re:Matematicky problem s uhlami
Přispěvatel: student 02. 04. 2013, 15:04:35
To staci vhodne odcitat, vymodulit a pridat k tomu 1 if a mame vysledok skor ako napiseme na forum prvu vetu. Alebo mi nieco nedochadza?
Název: Re:Matematicky problem s uhlami
Přispěvatel: Sten 02. 04. 2013, 15:05:58
Těch -170 má být +10, ne +20 ;-)

Jinak ten algoritmus je velmi snadný: (uhel + 180) % 360 - 180
Název: Re:Matematicky problem s uhlami
Přispěvatel: Sten 02. 04. 2013, 15:10:10
Těch -170 má být +10, ne +20 ;-)

Hmm, špatně jsem pochopil, co se tam počítá, těch +20 je správně. Ten algoritmus pak stačí vhodně upravit:

(koncovy - pocatecni + 180) % 360 - 180
Název: Re:Matematicky problem s uhlami
Přispěvatel: prezek 02. 04. 2013, 15:13:27
Citace
(uhel + 180) % 360 - 180)
pro -500 je výsledek -500, takže takhle asi ne.
Název: Re:Matematicky problem s uhlami
Přispěvatel: prezek 02. 04. 2013, 15:27:27
zkus třeba něco takového:
Kód: [Vybrat]
float delta = -10;
for (delta = -500; delta < 500; delta += 20)
    printf("%f %f\n", delta, delta - floor((delta + 180) / 360)*360);
, jestli to bude vyhovovat...
Název: Re:Matematicky problem s uhlami
Přispěvatel: Goheeca 02. 04. 2013, 15:28:44
Citace
(uhel + 180) % 360 - 180)
pro -500 je výsledek -500, takže takhle asi ne.
To také asi záleží na jazyku v Common Lispu a Python vypadne -140.
Název: Re:Matematicky problem s uhlami
Přispěvatel: prezek 02. 04. 2013, 15:47:56
To také asi záleží na jazyku v Common Lispu a Python vypadne -140.
Python mi také vrátí 140, ale C mi vrací ve Win i v Linuxu -500, stejně jako C# a bash
Název: Re:Matematicky problem s uhlami
Přispěvatel: PotatoJesus 02. 04. 2013, 15:57:26
/*
za správnost neručim, pokud tam je něco čemu nerozumíš tak to ber jako zdělávání  :-* :-* :-*
*/

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
   int uhelMam,uhelVstup,rozdil;
   int doblba=1;
   while(doblba)
      {
      printf("zadej mujUhel a uhelNaVstupu!!!!!!!!!\n")   ;
      scanf("%d",&uhelMam);
      scanf("%d",&uhelVstup);
      if(uhelMam<0)uhelMam=360-(abs(uhelMam)%360);
      uhelMam=uhelMam%360;
      if(uhelVstup<0)uhelVstup=360-(abs(uhelVstup)%360);
      uhelVstup=uhelVstup%360;
   rozdil=uhelVstup-uhelMam;
   if(rozdil<0)
      {if(rozdil<-180)rozdil+=360;}
   else if(rozdil>180)rozdil-=360;
   printf("Mam uhel: %d uhelVstup: %d otoceni: %d\n",uhelMam,uhelVstup,rozdil);
   
   printf("pokracovat doblba?????\n");
   scanf("%d",&doblba);
      }
   
   
   return 0;
}
Název: Re:Matematicky problem s uhlami
Přispěvatel: Sten 02. 04. 2013, 16:03:13
Citace
(uhel + 180) % 360 - 180)
pro -500 je výsledek -500, takže takhle asi ne.

Hmm, zkoušel jsem to v Pythonu, nenapadlo mě, že to v C bude fungovat jinak. OK, jde to celkem snadno opravit:

Kód: [Vybrat]
int posun = uhel >= 0 ? 180 : -180;
return (uhel + posun) % 360 - posun;
Název: Re:Matematicky problem s uhlami
Přispěvatel: Blaazen 02. 04. 2013, 16:41:13
Citace
Jinak ten algoritmus je velmi snadný: (uhel + 180) % 360 - 180
Jazyk, který by mi pro -500 vrátil cokoli jiného než -500 bych rovnou smazal z disku.
Název: Re:Matematicky problem s uhlami
Přispěvatel: Jarek 02. 04. 2013, 17:09:57
Kód: [Vybrat]
asin(sin(uhel))
Netvrdím, že je to optimální, nicméně je to elegantní ;)
Název: Re:Matematicky problem s uhlami
Přispěvatel: Jarek 02. 04. 2013, 17:21:12
Teď mi došlo, že by to nefungovalo kvůli 0 a 180 stupnu. Tak jinak:
Kód: [Vybrat]
sin(u1) == sin(u2) && cos(u1) == cos(u2)
To uz neni tak elegantni ;)
Název: Re:Matematicky problem s uhlami
Přispěvatel: Jarek 02. 04. 2013, 17:29:54
Jinak moc nerozumím tomu, proč plýtvat energií na normalizaci úhlu otočení? Jestli se otočím o +10 nebo +370 stupňů musí být ve výsledku jedno, protože v konečné fázi ten úhel při výpočtu čehokoliv stejně skončí v nějaké goniometrické funkci, která to spočítá správně, tak proč se s tím otravovat předem?
Název: Re:Matematicky problem s uhlami
Přispěvatel: Michal Štrba 02. 04. 2013, 17:37:12
Jinak moc nerozumím tomu, proč plýtvat energií na normalizaci úhlu otočení? Jestli se otočím o +10 nebo +370 stupňů musí být ve výsledku jedno, protože v konečné fázi ten úhel při výpočtu čehokoliv stejně skončí v nějaké goniometrické funkci, která to spočítá správně, tak proč se s tím otravovat předem?

No ono v mojom pripade to naozaj je dolezite, pretoze nie je jedno, ci sa otocit 150x okolo svojej osi a stale budes otoceny smerom k obrazovke alebo sa nepohnes vobec a bude otoceny tym istym smerom. Jedna sa totiz o hru, v ktorej otocenie zaberie aj nejaky cas.
Název: Re:Matematicky problem s uhlami
Přispěvatel: Michal Štrba 02. 04. 2013, 17:37:45
Těch -170 má být +10, ne +20 ;-)

Hmm, špatně jsem pochopil, co se tam počítá, těch +20 je správně. Ten algoritmus pak stačí vhodně upravit:

(koncovy - pocatecni + 180) % 360 - 180

Super, dakujem :D toto funguje absolutne dokonale!
Název: Re:Matematicky problem s uhlami
Přispěvatel: Jarek 02. 04. 2013, 17:44:59
Nevím přesne, co děláš, ale možná na to jdeš špatně. Zkus se podívat quaternion, tak se to obvykle řeší ve hrách:
http://kengine.sourceforge.net/tutorial/vc/quaternion.htm
http://en.wikipedia.org/wiki/Quaternion
Název: Re:Matematicky problem s uhlami
Přispěvatel: Sten 02. 04. 2013, 18:15:00
Těch -170 má být +10, ne +20 ;-)

Hmm, špatně jsem pochopil, co se tam počítá, těch +20 je správně. Ten algoritmus pak stačí vhodně upravit:

(koncovy - pocatecni + 180) % 360 - 180

Super, dakujem :D toto funguje absolutne dokonale!

Jak výše někdo podotkl, je tam chyba, pro zápornou hodnotu koncovy - pocatecni je potřeba otočit znaménka u těch 180.
Název: Re:Matematicky problem s uhlami
Přispěvatel: Michal Štrba 02. 04. 2013, 18:22:58
Těch -170 má být +10, ne +20 ;-)

Hmm, špatně jsem pochopil, co se tam počítá, těch +20 je správně. Ten algoritmus pak stačí vhodně upravit:

(koncovy - pocatecni + 180) % 360 - 180

Super, dakujem :D toto funguje absolutne dokonale!

Jak výše někdo podotkl, je tam chyba, pro zápornou hodnotu koncovy - pocatecni je potřeba otočit znaménka u těch 180.

Nie je to treba. Funguje to perfektne pre vsetky pripady. Otestoval som priamo v hre.
Název: Re:Matematický problém s úhly
Přispěvatel: Karel Karlik 02. 04. 2013, 18:46:41
A funguje to i kdyz je koncovy = -180 a pocatecni = 180?
Protoze pak je to (alespon v C) (-180-180+180)%360-180=-180-180=-360 misto 0 (protoze % na zaporne cislo vraci zaporne cislo - on je to ve skutecnosti operator "zbytek po celociselnem deleni" definovany pro A % B jako "nejmensi cele cislo C takove, ze C*B <= A", nebo podle c99 "(A/B) * B + A%B = A" (kde "/" je celociselne deleni, ktere zaokrouhluje smerem k nule)) - to prave zalezi na pouzitem jazyku, jestli % definuje pres zbytek po deleni, nebo jinak.

Ja bych tam navrhnul ((koncovy-pocatecni)%360+360+180)%360-180 // 360+180 dopocita kompilatorpri prekladu, do zdrojaku to napisu rozdelene aby bylo jasnejsi odkud se ktere cislo bere
Pokud mam zaruceno ze oba vstupni uhly jsou mezi -180 a +180, tak si muzu vystacit s (koncovy-pocatecni+360+180)%360-180
Název: Re:Matematický problém s úhly
Přispěvatel: Sten 02. 04. 2013, 19:49:47
A funguje to i kdyz je koncovy = -180 a pocatecni = 180?
Protoze pak je to (alespon v C) (-180-180+180)%360-180=-180-180=-360 misto 0 (protoze % na zaporne cislo vraci zaporne cislo - on je to ve skutecnosti operator "zbytek po celociselnem deleni" definovany pro A % B jako "nejmensi cele cislo C takove, ze C*B <= A", nebo podle c99 "(A/B) * B + A%B = A" (kde "/" je celociselne deleni, ktere zaokrouhluje smerem k nule)) - to prave zalezi na pouzitem jazyku, jestli % definuje pres zbytek po deleni, nebo jinak.

Ja bych tam navrhnul ((koncovy-pocatecni)%360+360+180)%360-180 // 360+180 dopocita kompilatorpri prekladu, do zdrojaku to napisu rozdelene aby bylo jasnejsi odkud se ktere cislo bere
Pokud mam zaruceno ze oba vstupni uhly jsou mezi -180 a +180, tak si muzu vystacit s (koncovy-pocatecni+360+180)%360-180

Jednodušší je otočit znaménka u těch 180 (obou), pokud je koncovy - pocatecni menší než 0, ušetříte tak jedno dělení:
Kód: [Vybrat]
int uhel = koncovy - pocatecni;
int posun = uhel >= 0 ? 180 : -180;
return (uhel + posun) % 360 - posun;
Název: Re:Matematický problém s úhly
Přispěvatel: Blaazen 02. 04. 2013, 20:25:44
To jsem nevěřil vlastním očím, když jsem tohle viděl na wiki:
Citace
The case of general integers

If a and d are integers, with d non-zero, then a remainder is an integer r such that a = qd + r for some integer q, and with |r| < |d|.

When defined this way, there are two possible remainders. For example, the division of −42 by −5 can be expressed as either
−42 = 9×(−5) + 3

as is usual for mathematicians,[citation needed] or
−42 = 8×(−5) + (−2).

So the remainder is then either 3 or −2.
Je to odsud: http://en.wikipedia.org/wiki/Remainder (http://en.wikipedia.org/wiki/Remainder)

V diskuzi je to zkritizováno, aby taky ne.
-42 div 9 = -5 ?
Název: Re:Matematický problém s úhly
Přispěvatel: Michal Štrba 02. 04. 2013, 20:43:40
A funguje to i kdyz je koncovy = -180 a pocatecni = 180?
Protoze pak je to (alespon v C) (-180-180+180)%360-180=-180-180=-360 misto 0 (protoze % na zaporne cislo vraci zaporne cislo - on je to ve skutecnosti operator "zbytek po celociselnem deleni" definovany pro A % B jako "nejmensi cele cislo C takove, ze C*B <= A", nebo podle c99 "(A/B) * B + A%B = A" (kde "/" je celociselne deleni, ktere zaokrouhluje smerem k nule)) - to prave zalezi na pouzitem jazyku, jestli % definuje pres zbytek po deleni, nebo jinak.

Ja bych tam navrhnul ((koncovy-pocatecni)%360+360+180)%360-180 // 360+180 dopocita kompilatorpri prekladu, do zdrojaku to napisu rozdelene aby bylo jasnejsi odkud se ktere cislo bere
Pokud mam zaruceno ze oba vstupni uhly jsou mezi -180 a +180, tak si muzu vystacit s (koncovy-pocatecni+360+180)%360-180

No v Pythone som to napisal priblizne takto:

def posun(pociatocny, koncovy):
  return (koncovy - pociatocny + 180) % 360 - 180


A nech je to akokolvek divne tak: posun(180, -180) je 0 aj posun(-180, 180) je 0. Takze mne takato funkcia funguje velmi dobre.
Název: Re:Matematický problém s úhly
Přispěvatel: Jarek 02. 04. 2013, 20:56:04
Já teda nevím, ale mám pocit, že se tady znovuobjevuje kolo. Jako všechno, co tu bylo napsáno, asi pro určité případy funguje, ale proč to neudělat obecně a správně? Udělat z úhlu jednotkový 2D vektor je snadné a výpočet úhlu mezi vektory je matematiky dobře zvládnutá a zdokumentovaná úloha :). Tady je několik způsobů, jak na to:
http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/
a v pythonu:
http://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python
Název: Re:Matematický problém s úhly
Přispěvatel: prezek 02. 04. 2013, 21:22:55
A nech je to akokolvek divne tak: posun(180, -180) je 0 aj posun(-180, 180) je 0. Takze mne takato funkcia funguje velmi dobre.

Už jsme se o tom minimálně ve 3 příspěvcích zmínili, že Python počítá modulo záporných čísel jinak, než třeba C. Při takovémto řešení ale podstupuješ riziko, že v jiné implementaci Pythonu změní názor a budou počítat modulo tak, jako C, C#, Bash, Javascript ... Já bych se bál takové řešení použít. Buď bych po přepočtu zkontroloval, zda je číslo v rozsahu -180 až 180 a příslušně upravil +-360, nebo bych použil ten vzorec, co jsem už psal.
Kód: [Vybrat]
float delta=beta-alfa;
delta-=floor((delta + 180) / 360)*360;
Název: Re:Matematicky problem s uhlami
Přispěvatel: Goheeca 03. 04. 2013, 21:22:24
Citace
Jinak ten algoritmus je velmi snadný: (uhel + 180) % 360 - 180
Jazyk, který by mi pro -500 vrátil cokoli jiného než -500 bych rovnou smazal z disku.
Proto taky v CL je na výběr mezi mod a rem (http://www.lispworks.com/documentation/lw50/CLHS/Body/f_mod_r.htm).
Název: Re:Matematický problém s úhly
Přispěvatel: PotatoJesus 04. 04. 2013, 13:32:17
Já teda nevím, ale mám pocit, že se tady znovuobjevuje kolo. Jako všechno, co tu bylo napsáno, asi pro určité případy funguje, ale proč to neudělat obecně a správně? Udělat z úhlu jednotkový 2D vektor je snadné a výpočet úhlu mezi vektory je matematiky dobře zvládnutá a zdokumentovaná úloha :). Tady je několik způsobů, jak na to:
http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/
a v pythonu:
http://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python

Nazdar!

Ještě takovou jednu doplňující otázku. Co bude šlapat rychleji, ty modula nebo tadleta matika?
Díky
Název: Re:Matematický problém s úhly
Přispěvatel: Jarek 04. 04. 2013, 14:01:14
Ještě takovou jednu doplňující otázku. Co bude šlapat rychleji, ty modula nebo tadleta matika?
To je špatně položená otázka ;). Ty modula jsou rychlejší, ale jen z toho důvodu, že autor původního dotazu zvolil špatný matematický aparát pro popis problému. Používat úhly k popisu orientace je ve hrách neobvyklé, mnohem praktičtejší je směrový vektor nebo quaternion. Vektory mají tu výhodu, že fungují stejně pro N-dimenzionální prostor (2D i 3D), matematika kolem toho je pořád ta stejná. Kdyby použil směrový vektor nebo quaternion, nemusí vůbec řešit normalizaci úhlu. Navíc při výpočtech s rotačními úhly narazí v 3D prostoru na tohle: http://en.wikipedia.org/wiki/Gimbal_lock (http://en.wikipedia.org/wiki/Gimbal_lock), což se mu s quaternionem nestane.
Název: Re:Matematický problém s úhly
Přispěvatel: Michal Štrba 05. 04. 2013, 10:05:41
Jarek: pouzivam fyzikalnu kniznicu PyMunk a v nej GearJoint pre vytvorenie klbu medzi dvoma objektami. GearJoint urcuje UHOL, ktory maju dane objekty zvierat. Preto nemozem pouzit vektory ani nic podobne ale uhly (samozrejme v radianoch).
Název: Re:Matematický problém s úhly
Přispěvatel: Jarek 05. 04. 2013, 10:48:34
Jarek: pouzivam fyzikalnu kniznicu PyMunk a v nej GearJoint pre vytvorenie klbu medzi dvoma objektami. GearJoint urcuje UHOL, ktory maju dane objekty zvierat. Preto nemozem pouzit vektory ani nic podobne ale uhly (samozrejme v radianoch).
Aha to je 2D, tak pro 2D je quaternion trochu overkill, ale stejně bych pro svoje interní výpočty použil směrový vektor a teprve až když by bylo potřeba zavolat tu knihovnu, tak bych spočítal úhel směrového vektoru. Nemusíš řešit normalizaci úhlu a je to obecnější řešení.
Název: Re:Matematický problém s úhly
Přispěvatel: Karel Tejnora 05. 04. 2013, 10:54:01
Jestli te zajima vykon, tak nejvykonejsi to je pres quarternion. Ten resi daleko vetsi problemy: nekonecno, ruzne krajni pripady. A to tak ze nemusis pouzivat if else if else. Jo a taky to za tebe spocita GPU http://glm.g-truc.net/
To se zacne hodit v pripade ze se otacis v animaci.
Název: Re:Matematický problém s úhly
Přispěvatel: PotatoJesus 06. 04. 2013, 15:08:48
Jarek: pouzivam fyzikalnu kniznicu PyMunk a v nej GearJoint pre vytvorenie klbu medzi dvoma objektami. GearJoint urcuje UHOL, ktory maju dane objekty zvierat. Preto nemozem pouzit vektory ani nic podobne ale uhly (samozrejme v radianoch).

OK, díky.



Název: Re:Matematický problém s úhly
Přispěvatel: Biktop 06. 04. 2013, 22:21:17
To jsem nevěřil vlastním očím, když jsem tohle viděl na wiki:
Citace
The case of general integers

If a and d are integers, with d non-zero, then a remainder is an integer r such that a = qd + r for some integer q, and with |r| < |d|.

When defined this way, there are two possible remainders. For example, the division of −42 by −5 can be expressed as either
−42 = 9×(−5) + 3

as is usual for mathematicians,[citation needed] or
−42 = 8×(−5) + (−2).

So the remainder is then either 3 or −2.
Je to odsud: http://en.wikipedia.org/wiki/Remainder (http://en.wikipedia.org/wiki/Remainder)

V diskuzi je to zkritizováno, aby taky ne.
-42 div 9 = -5 ?

Tak nematematik si o tom může myslet co chce, může proti tomu klidně protestovat, může to dokonce kritizovat v diskusích, ale to je vše, co proti tomu může dělat. :) Správná je varianta "-42 div 9 = -5", a to v důsledku Eukleidovy věty o celočíselném dělení.
Ovšem nutno poznamenat, že symetrická varianta se za špatnou taky nedá označit. A pokud jde o implementaci v programovacích jazycích, tak varianty operace modulo a z ní plynoucího výsledku celočíselného dělení jsou v podstatě 4:
1. zbytek je vždy nezáporné číslo (Eukleidovská implementace, "nejsprávnější", leč nejojedinělejší)
2. zbytek má znaménko dělence
3. zbytek má znaménko dělitele
4. zbytek má takové znaménko, aby byl co nejblíže nule.
Název: Re:Matematický problém s úhly
Přispěvatel: Blaazen 07. 04. 2013, 00:10:37
@ Biktop
Tvoje vysvětlení je správné, ale nelíbí se mi, není intuitivní (tvůj bod 1.). Vždycky jsem vnímal zápornou osu jako zrcadlově převrácenou kladnou, tak proč by pro ní měla platit jiná pravidla? Dělenec, dělitel i podíl můžou být kladná i záporná čísla, jen zbytek po dělení si vynutíme kladný nějakou matematickou větou.
Název: Re:Matematický problém s úhly
Přispěvatel: JS 07. 04. 2013, 12:59:06
Vždycky jsem vnímal zápornou osu jako zrcadlově převrácenou kladnou, tak proč by pro ní měla platit jiná pravidla?

Tak to jsi vnimal dost spatne, protoze existuji funkce sude (zaporna osa je zrcadlove prevracena), funkce liche (zaporna osa je zrcadlove prevracena v obou osach) a pak jeste velke mnozstvi funkci, pro ktere neplati ani jedno.
Název: Re:Matematický problém s úhly
Přispěvatel: Blaazen 07. 04. 2013, 13:42:16
Sudé a liché funkce http://cs.wikipedia.org/wiki/Sudé_a_liché_funkce (http://cs.wikipedia.org/wiki/Sudé_a_liché_funkce) znám (čestně, jsem už dýl ze škol, takže jsem se musel podívat na wiki, abych si to připomněl), ale nevidím tam souvislost se zbytkem po celočíselném dělení. No ale to neznamená, že tam není  :)