Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Radiaanit kulmiksi??

Sivun loppuun

kayttaja-3842 [18.07.2008 11:23:14]

#

Terve vaan kaikki..

Eli olen tässä yrittänyt saada muunettua radiaanista kulma.

Eli käsittääkseni se toimisi kaavalla

kulma = (rad / pii) * 180

Eli koodissani

//Tästä saadaan kumminkin tulokseksi -25.6727
 ((cos(90) / 3.14159) * 180)

...eli tuosta saadaan tulokseksi -25.6727 ja se on virheellinen?!?!?!?

Eikös tuloksen pitäs olla nolla?

Lebe80 [18.07.2008 11:27:22]

#

cos(90) ?

Pitäisikö tuon 90:n olla radiaaneissa, eikä siis tuon laskun tuloksen?

eli kutakuinkin näin:
cos( 90 / 180 * 3.14159 )

ja cos (ja sin) antaa tuloksen -1 ja 1 väliltä.

http://fi.wikipedia.org/wiki/Trigonometrinen_funktio#M.C3.A4.C3.A4ritelm.C3.A4t_yksikk.C3.B6ympyr.C3.A4n_avulla

kayttaja-3842 [18.07.2008 11:29:17]

#

Ainiin tosiaanki.

Tuohan se virhe tosiaankin oli....

...Kiitos paljon. :)

Teuro [18.07.2008 11:32:32]

#

Olet ymmärtänyt hiukan väärin. Älä siis muunna cos funktiolla kulma-arvoa, vaan muunna radiaaniarvo tuolla kaavalla asteiksi. esimerkiksi.

radtodeg(float rad){
  float deg = (rad / PI) * 180;

  return deg;
}

Tajusinko oikein? Tuossa olet minusta muunnat 90 astetta kosinin avulla, joka ei ole ollenkaan tarpeellista. Kokeile tuota minun esimerkkiä meneekö oikein.

float rad = PI;

float deg = radtodeg(rad)

std::cout << deg << std::endl;
//180 astetta, joka on siis oikein, koska PI rad == oikokulma == 180astetta

EDIT hidas kun oon...

hunajavohveli [18.07.2008 11:32:37]

#

Tarkoitat varmaan, että haluat muuttaa radiaanit asteiksi. Molemmat ovat kulman yksikköjä. Radiaaneissa 2 * pii vastaa 360 astetta, joten yksi aste on pii / 180 radiaania. Koodissasi yrität tehdä päinvastoin ja muuttaa asteita radiaaneiksi.

kayttaja-3842 [18.07.2008 11:35:20]

#

juu tajusin täysin nytten. :D kiitos paljon teille kaikille :D


Edit1:

Yksi juttu vielä. Eikös math.h cos funktio palauta tuloksen radianttina?

Teuro [18.07.2008 12:55:33]

#

math.h otsikkotiedostossa oleva cos funktio haluaa syötteen radiaaneina. cosini funktion palauttama arvo on ihan sama radiaaneina / asteina. Käytetty kirjasto / laskin / taulukko määrittelee missä muodossa syöte otetaan vastaan.

Koska onhan aivan sama annetaanko funktiolle 90 astetta tai (PI / 2) radiaania kosini edellä olevista on aina 0 ja vastaavat sinille aina 1 tangentilla ei määriteltynä.

Grez [18.07.2008 14:05:53]

#

Pääsääntöisesti matematiikassa käytetään aina radiaaneja koska ne on ominaisuuksiltaan luonnollisempia. Asteet on sitten ihmisrajapintaan tarkoitettu keksintö.

Teuro [18.07.2008 14:11:30]

#

Onhan helpompi käsittää luku 45 astetta kuin PI / 4 rad eikös vain? Mateatiikassa toki helpompi käyttää radiaaneja. Maanmittareilla on sitten vielä omat gooninsa ja armeijalla piirunsa, joten onhan näitä kulmayksiköitä olemassa.

jormi [18.07.2008 14:16:57]

#

Kotisivuillani olevassa esimerkkiohjelmassa on funktiot Radtodeg ja Degtorad, jotka käsittelevät tätä ongelmaa. JVM
http://pp.kpnet.fi/jvm/jvm/pallokolmio.htm

Grez [18.07.2008 14:56:28]

#

Teuro kirjoitti:

Onhan helpompi käsittää luku 45 astetta kuin PI / 4 rad eikös vain?

Niin, no siksi sanoinkin, että ne asteet on ihmisrajapintaa varten keksitty. Ja ei se 1/4π ole yhtään vaikeampaa käsittää jos on niihin tottunut. Toki jos ei ole koskaan kerrottu kuin asteista, niin sitten on vaikeaa ymmärtää radiaaneja (ja päinvastoin).

Noi piirutkin on kyllä mahtava keksintö, varsinkin kun suomen armeijassakin ollaan siirtymässä 6000 piirun systeemistä 6400 piirun systeemiin. Milloinhan saadaan ensimmäinen oma uhri harjoituksissa sen takia että mennään noissa sekaisin.

jormi [18.07.2008 17:18:37]

#

Merenkulun kirjallisuudessa tapaa perinteistä johtuen monenlaisia tiedon esitystapoja, aika tavallinen näyttää olevan kokonaiset asteet + minuutit yhdellä desimaalilla. Tämän vuoksi katsoin omassa ohjelmassani kätevimmäksi tavaksi tallettaa kaikki yksiköt doublena. Laskenta tapahtuu radiaaneilla, siksi tarvitaan muunnosfunktiot molempiin suuntiin. JVM

kayttaja-3842 [19.07.2008 13:57:40]

#

ok, sitten olisi vielä yksi juddu. Elikkäs olen yrittänyt laskea XY koordinaateista kulmaa. Eli jotta pelaaja katoisi aina hiiren suuntaan, pitää sille laskea kulma, joka osoittaa hiireen.

...joten, käsittääkseni tämä tulisi toimia seuraavalla tekniikalla.

pelaajaX = 10
hiiriX = 220

pelaajaY = 20
hiiriY = 240

arctan((240 - 20) / (220 - 10))

eli koodissa

double pelaajaX = 10, pelaajaY = 20;
double hiiriX = 220, hiiriY = 240;

 atan((hiiriY - pelaajaY) / (hiiriX - pelaajaX))

 //Tulos pitäisi saada asteina...

Onko laskukaava oikea ja annetaanko tulos radiaaneina vai miksi tulos on kovin pieni

Metabolix [19.07.2008 14:19:56]

#

Tietenkin tulos annetaan radiaaneina. Matematiikassa käytetään käytännössä aina radiaaneja, koska niillä monet laskukaavat toimivat nätisti (esimerkiksi sinin ja kosinin laskeminen sarjakehitelmänä). Toki aina voisi kirjoittaa kulman paikalle asteet/180*pii, mutta tämä mutkistaisi kaavoja melkoisesti.

Suosittelen kulman säilyttämistä radiaaneina myös ohjelmassa, ellet keksi erittäin hyvää syytä asteiden käyttöön.

Arkustangenttifunktiosta vielä sen verran, että kuten voit helposti itsekin kuvista ja järkeilemällä havaita, se antaa vain puolet vastauksista. Tämä johtuu aivan siitä, että 1/2 = (-1)/(-2). Funktio ei siis tiedä, onko suunta yläoikealle vai alavasemmalle, koska tangentti on sama. Jos kuitenkin käytät atan2-funktiota, joka ottaa parametrina itse luvut eikä niiden osamäärää, funktio huomioi etumerkit ja palauttaa oikean kulman.

Grez [19.07.2008 14:45:40]

#

Juu, lisäksi kayttaja-3842n alkuperäinen koodi heittää "division by zero" virheen jos hiiriX==pelaajaX. Atan2:lla tuostakin ongelmasta pääsee. Ainoa poikkeustilanne, joka täytyy Atan2:lla huomioida on sekä hiiren että pelaajan oleminen samassa koordinaatissa, jolloin kulmaa ei tietenkään voi määritellä.

User137 [20.07.2008 13:07:43]

#

Eikö ketjussa vielä oltu vakioita mainittu? Noh.. nopein tapa muuttaa radiaanit asteiksi ja päinvastoin on käyttää kerrointa:

const
  ToRad = 0.0174532925199432;  //  PI / 180 = Deg To Rad
  ToDeg = 57.295779513082320;  //  180 / PI = Rad To Deg

Ei siinä muuta kun jos funktion teet niin se aiheuttaa aina työtä ohjelmalle jo pelkästään sillä että se on funktio. Yksi kertolasku ei paljoa maksa :p

Siks vaan esitin kun kulmien muunnon yhteydessä usein tarvitaan äärimmäistä tehokkuutta.

Metabolix [20.07.2008 13:49:41]

#

User137 kirjoitti:

Ei siinä muuta kun jos funktion teet niin se aiheuttaa aina työtä ohjelmalle jo pelkästään sillä että se on funktio.

Toki näin, jos kääntäjä ei optimoi tilannetta. Kunnon kääntäjä kuitenkin optimoi koodia niin, että lopputulos on sama, jos vain funktion runko on kussakin kooditiedostossa saatavilla eli jos funktio määritellään vaikkapa jossain otsikossa inline-sanan kanssa. Myös makroja voi C:ssä (C++:ssa) käyttää:

#define DEG(x) ((x) / PI * 180)

Jos makrot tekevät muunnoksen molempiin suuntiin, on vaarana kompastua omaan nokkeluuteensa tuossa, kun jossain kohti unohtaakin, oliko tallennetun kulman yksikkönä radiaani vai aste. Lisäksi hyvin harvassa asiassa tarvitaan asteita, mieleen tulevat lähinnä käyttäjän kanssa kommunikointi ja OpenGL:n glRotate-funktio. Kummassakaan tilanteessa muunnoksen ei pitäisi tulla pullonkaulaksi, vaikka kutsuttaisiinkin ylimääräisiä muunnosfunktioita. Radiaaneja taas käytetään läpi matematiikkakirjaston, joten edelleenkin olen niiden kannalla.

Tämäkin on yksi mahdollisuus, jonka kääntäjä osaa optimoida (muista -O-lippu):

class kulma {
	static const double pii;
	double x;
public:
	kulma() : x(0) {}
	kulma(const double _x) : x(_x) {}
	void deg(const double _x) {
		x = pii / 180 * _x;
	}
	double deg() const {
		return 180 / pii * x;
	}
	void rad(const double _x) {
		x = _x;
	}
	double rad() const {
		return x;
	}
};
const double kulma::pii = 3.14159265358979323846;

#include <iostream>
#include <cmath>

void tulosta(const kulma &k)
{
	std::cout
		<< k.deg() << " astetta = "
		<< k.rad() << " radiaania."
		<< std::endl;
}

int main()
{
	kulma a;
	a.rad(1); // a = 1 radiaani;
	tulosta(a);
	a.deg(150); // a = 150 astetta;
	tulosta(a);
	std::cout << "cos(a) = " << std::cos(a.rad()) << std::endl;
	return 0;
}

jormi [20.07.2008 14:27:28]

#

Pelkkä muunnoskaava asteista radiaaneiksi ei aina riitä, koska tehtävän lähtöarvoissa voi olla asteita, minuutteja tai sekunteja desimali-, tai kokonaislukuina. JVM

Metabolix [20.07.2008 14:35:59]

#

jormi kirjoitti:

— — lähtöarvoissa voi olla asteita, minuutteja tai sekunteja desimali-, tai kokonaislukuina.

Tuo on syötteen lukuun liittyvä asia. Tässä taas puhutaan ohjelman sisäisestä toiminnasta, kun toiset funktiot tarvitsevat arvon asteina ja toiset radiaaneina. Missään tapauksessa ei kannata ohjelman aikana pyöritellä arvoja useampiosaisina tietueina, jos tähän ei ole erittäin hyvää syytä. Mainitsemassasi tapauksessa syötteenlukufunktion (hae_kulma) kuuluu huolehtia siitä, että syöte ymmärretään ja muutetaan ohjelman sisäiseen esitysmuotoon, esimerkiksi double-tyyppisiksi radiaaneiksi. Vastaavasti tulostusfunktio (tulosta_kulma) muuttaa tällaisen arvon taas haluttuun muotoon, vaikka sitten asteiksi, minuuteiksi ja sekunneiksi.

kayttaja-3842 [22.07.2008 12:15:35]

#

Sellasta vielä pitäneepi kysyä, että kun SDL rotozoomilla kuva ei pyöri oikein vaan ns. palikkamaisesti.

Noh sain kyllä toimimaan sen, että kuvakääntyy oikein keskipisteestä.

x -= (alkuperainen_kuva->w - kaanetty_kuva->w)
y -= (alkuperainen_kuva->h - kaanetty_kuva->h)

...mutta jos kuva pitääkin kääntää jostain muusta kohdasta. Miten tämä luonnistuu? Kokeilin muuttaa ehtoja esim.

x -= ((alkuperainen_kuva->w - kaanetty_kuva->w) -10)
y -= (alkuperainen_kuva->h - kaanetty_kuva->h)

..mutta nytten kuva taas ei käänny oikein..

Metabolix [22.07.2008 12:47:32]

#

Kuva pyörii joka tapauksessa samalla tavalla. Uuden piirtokohdan taas joudut laskemaan itse. Suosittelen nyt matematiikan opettelua.

Ota lähtökohdasesi, että lasket asiat suhteessa kuvan keskipisteeseen. Pidä piirtokohtanakin muistissa kuvan keskikohta, jolloin piirto onnistuu pyörityksestä ja skaalauksesta riippumatta oikein. Oikea kulmapiste on aina (x - w/2, y - h/2), missä (x, y) on kuvan keskipisteen piirtokohta ja (w/2, h/2) kuvan suhteellinen keskipiste. Voit liittää kuvaan lisäksi tiedon kiintopisteestä (xk, yk) suhteessa kuvan keskipisteeseen, jotta voit laskea uuden "keskipisteen" piirtoa varten. Kuvaa käännettäessä pitää pyörittää myös pistettä (xk, yk) vastaavalla tavalla, jotta tämä piirtokeskipiste pysyisi oikeassa kohti kuvaa. Pyörityskaavan voit johtaa itse (tai etsiä Wikipediasta, jos ei onnistu).

Jos välttämättä haluat, voit kiinnittää koordinaatistosi myös kuvan kulmaan, mutta sitä vaihtoehtoa en missään tapauksessa suosittele — kaavat saat keksiä itse.

kayttaja-3842 [22.07.2008 13:47:49]

#

Hups kirjotin vahingossa kiireessä väärin tuon keskipisteen laskemis kaavan..

Siis ite teen sen

  x -= kaanetty_kuva->w>>1
  y -= kaanetty_kuva->h>>1

...sitten vielä sellasta, että sain toimimaan tuon hakemani jutun. :)


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta