Ennakkoon ampuminen

Voit pyytää apua ohjelmointiongelmiin täältä.
Post Reply
User avatar
Pate5
Artist
Artist
Posts: 551
Joined: Tue Aug 28, 2007 4:53 pm
Location: Vantaa

Ennakkoon ampuminen

Post by Pate5 » Tue Oct 02, 2012 4:55 pm

Hei,

minulla on eräässä projektissani ongelmana ennakon ottaminen ampuessa ja päätin tuoda ongelman foorumin matikkaguruille.

Minulla on kohteen 3-ulotteinen paikkavektori ja 3-ulotteinen nopeusvektori. Haluan saada selville, mihin suuntaan ammus täytyy ampua origosta, kun sen nopeus tiedetään.

A on kohteen paikkavektori
B on kohteen nopeusvektori
t on kohtaamiseen kuluva aika
C on ammuksen nopeusvektori, |C| tiedetään

t ja C ovat tuntemattomia.

Yritin ratkaista yhtälöä mutta en onnistunut kun en keksinyt, miten pystyn hyödyntämään |C|:tä. :(
Attachments
ennakointi.png
ennakointi.png (9.49 KiB) Viewed 4264 times
CoolBasic henkilökuntaa
Graafikko

User avatar
legend
Advanced Member
Posts: 371
Joined: Wed Nov 18, 2009 9:06 pm

Re: Ennakkoon ampuminen

Post by legend » Tue Oct 02, 2012 5:32 pm

Minun on ei pitäisi kysyä mitään, sillä en osaa kuitenkaaa vastata, mutta ihan uteliaisuuttani kysyn...
Tarkoitatko, että ampujalla A on kohde B. B:n sijainti, suunta ja nopeus tiedetään.
Pitäisi laskea kuinka paljon pitäisi ampua eteenpäin, jotta ammus osuisi B:tä.

User avatar
Jonez
Devoted Member
Posts: 575
Joined: Mon Aug 27, 2007 8:37 pm

Re: Ennakkoon ampuminen

Post by Jonez » Tue Oct 02, 2012 5:38 pm

legend, luulen että tässä tarkoitetaan että ampuja on origossa O, eli kohteen sijainti on A, eli O+A, ja kohteen tuleva sijainti seuraavassa updatessa on A+B.

En ole vektoreita pitkään aikaan laskenut, mutta... Jos törmäyskohta on piste D, niin eikö D = A + rB ja D = tC, tai jotain vastaavaa... :) Tuostahan saisi yhtälöryhmällä t:n ja r:n, eikö...?

Edit. ainii eiku C:tä ei tiedetty... No jos teet siitä yksikkövektorin tai jotain... En tiiä :D
-Vuoden 2008 aloittelijan ystävä -palkinnon voittaja-
Image <- protestipelikilpailun voittaja.
Space War

User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

Re: Ennakkoon ampuminen

Post by axu » Tue Oct 02, 2012 6:16 pm

Jonez wrote:legend, luulen että tässä tarkoitetaan että ampuja on origossa O, eli kohteen sijainti on A, eli O+A, ja kohteen tuleva sijainti seuraavassa updatessa on A+B.

En ole vektoreita pitkään aikaan laskenut, mutta... Jos törmäyskohta on piste D, niin eikö D = A + rB ja D = tC, tai jotain vastaavaa... :) Tuostahan saisi yhtälöryhmällä t:n ja r:n, eikö...?
Tuota... mistäs tuo r pöllähti tuonne? B:llähän on tietenkin sama kerroin kuin C:llä, eli aika ampumisesta osumiseen (kuten Pate5:n kuvassa olikin). Tästä seuraa, että A + tB = tC. Vielä en keksinyt, miten C:n pituuden tietäminen auttaa, mutta selvästi se on ratkaisevassa roolissa.
Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
koodaaja
Moderator
Moderator
Posts: 1583
Joined: Mon Aug 27, 2007 11:24 pm
Location: Otaniemi - Mikkeli -pendelöinti

Re: Ennakkoon ampuminen

Post by koodaaja » Tue Oct 02, 2012 11:55 pm

Ongelma on varsin mielenkiintoinen, mutta lähestymistapa ei ehkä se kaikista helpoin. Kuten kaavastasi näkee, t|C| muodostaa origokeskisen pallon, jonka voi lausua myös seuraavasti: sqrt(x²+y²+z²) = r <=> x²+y²+z² = r² <=> (ax+bx*t)²+(ay+by*t)²+(az+bz*t)² = t²|C|² <=> ax²+ax*bx*t+bx²t²+ay²+ay*by*t+by²t²+az²+az*bz*t+bz²t² - t²|C|² = 0 <=> t²(bx²+by²+bz²-|C|²)+t(ax*bx+ay*by+az*bz)+ax²+ay²+az², joka on toisen asteen yhtälö muotoa at²+bt+c=0, jossa a,b ja c ovat kaikki vakiollisia, joten sen menee suoraan t = (-b(+-)sqrt(b²-4ac))/2a, mihin kannattaa ohjelmoidessa käyttää jopa välimuuttujia. Neliöjuuren sisäinen diskriminantti (kiitos cce:lle terminologiamuistutuksesta!) b²-4ac kertoo törmäyksistä, sen ollessa negatiivinen ei ammus ehdi enää mitenkään osumaan, sen ollessa 0 se ehtii juuri yhteen pisteeseen ja diskriminantin positiivisilla arvoilla mahdollisia törmäyskohtia on kaksi. Kannattanee myös tarkistaa, että osuminen tapahtuu varmasti tulevaisuudessa, muuten kaava voi antaa t:lle negatiivisenkin arvon. Parhaan tuloksen takaamiseksi kannattanee myös kahden mahdollisuuden tapauksessa valita aiempi vielä tulevaisuudessa oleva jotta osuma tapahtuu mahdollisimman pian. Ajan laskemisen jälkeen tunnetaankin etäisyys (a+b*t) ja aika (t), joten ammuksen nopeusvektori saadaan yksinkertaisesti näistä jakolaskulla (s = vt <=> v = s/t). Esimerkki seuraa.

Code: Select all

SCREEN 640, 480

Type pari
    Field tx#
    Field ty#
    Field tz#
    Field txv#
    Field tyv#
    Field tzv#
    
    Field px#
    Field py#
    Field pz#
    Field pxv#
    Field pyv#
    Field pzv#
    
    Field t0#
    Field ct#
EndType

start = Timer()

Repeat
    
    ft# = (Timer()-start)*.001
    
    If Timer()>t
        p.pari = New(pari)
        
        p\tx = Rnd(-80,-40)
        p\ty = Rnd(-10, 10)
        p\tz = Rnd(-10, 10)
        p\txv = Rnd(5, 10)
        p\tyv = Rnd(-2, 2)
        p\tzv = Rnd(-2, 2)
        
        p\px = Rnd(-5, 5)
        p\py = Rnd(-16,-15)
        p\pz = Rnd(-15,-13)
        
        ax# = p\tx-p\px
        ay# = p\ty-p\py
        az# = p\tz-p\pz
        bx# = p\txv
        by# = p\tyv
        bz# = p\tzv
        
        s# = Rnd(8,20) // projectile speed
        
        a# = bx*bx+by*by+bz*bz-s*s
        b# = ax*bx+ay*by+az*bz
        c# = ax*ax+ay*ay+az*az
        d# = b*b-4*a*c
        
        If d<.0 Then
            Delete p // no hits, don't shoot
        Else
            If d>.0 Then
                ct1# = (-b-Sqrt(d))/(2*a)
                ct2# = (-b+Sqrt(d))/(2*a)
                If ct1>.0 Then
                    p\ct = ct1
                    If ct2>.0 And ct2<ct1 Then p\ct = ct2
                Else
                    p\ct = ct2
                EndIf
            ElseIf d = .0 Then
                p\ct = -b/(2*a)
            EndIf
            p\pxv = (p\tx+p\txv*p\ct-p\px)/p\ct
            p\pyv = (p\ty+p\tyv*p\ct-p\py)/p\ct
            p\pzv = (p\tz+p\tzv*p\ct-p\pz)/p\ct
            p\t0 = ft
            SetWindow Str(p\ct)
            If p\ct < .0 Then Delete p // no point in shooting
        EndIf
        
        t = Timer()+1000
    EndIf
    k = 0
    For p.pari = Each pari
        pt# = ft-p\t0
        s1# = 50.0/(20.0+p\tz+p\tzv*pt)
        s2# = 50.0/(20.0+p\pz+p\pzv*pt)
        Circle 320+s1*(p\tx+p\txv*pt-3), 240-s1*(p\ty+p\tyv*pt-3), 6*s1
        Circle 320+s2*(p\px+p\pxv*pt-3), 240-s2*(p\py+p\pyv*pt-3), 6*s2
        If pt>p\ct Then Delete p
        k = k + 1
    Next p
    DrawScreen
Forever

User avatar
naputtelija
Devoted Member
Posts: 718
Joined: Wed Nov 03, 2010 8:56 pm
Location: Joku piste pohjoisessa.

Re: Ennakkoon ampuminen

Post by naputtelija » Wed Oct 03, 2012 12:04 am

koodaaja wrote:Ongelma on varsin mielenkiintoinen, mutta lähestymistapa ei ehkä se kaikista helpoin. Kuten kaavastasi näkee, t|C| muodostaa origokeskisen ympyrän, jonka voi lausua myös seuraavasti: sqrt(x²+y²+z²) = r <=> x²+y²+z² = r² <=> (ax+bx*t)²+(ay+by*t)²+(az+bz*t)² = t²|C|² <=> ax²+ax*bx*t+bx²t²+ay²+ay*by*t+by²t²+az²+az*bz*t+bz²t² - t²|C|² = 0 <=> t²(bx²+by²+bz²-|C|²)+t(ax*bx+ay*by+az*bz)+ax²+ay²+az², joka on toisen asteen yhtälö muotoa at²+bt+c=0, jossa a,b ja c ovat kaikki vakiollisia, joten sen menee suoraan t = (-b(+-)sqrt(b²-4ac))/2a, mihin kannattaa ohjelmoidessa käyttää jopa välimuuttujia. Neliöjuuren sisäinen diskriminantti (kiitos cce:lle terminologiamuistutuksesta!) b²-4ac kertoo törmäyksistä, sen ollessa negatiivinen ei ammus ehdi enää mitenkään osumaan, sen ollessa 0 se ehtii juuri yhteen pisteeseen ja diskriminantin positiivisilla arvoilla mahdollisia törmäyskohtia on kaksi. Kannattanee myös tarkistaa, että osuminen tapahtuu varmasti tulevaisuudessa, muuten kaava voi antaa t:lle negatiivisenkin arvon. Parhaan tuloksen takaamiseksi kannattanee myös kahden mahdollisuuden tapauksessa valita aiempi vielä tulevaisuudessa oleva jotta osuma tapahtuu mahdollisimman pian. Esimerkki seuraa.

Code: Select all

SCREEN 640, 480

Type pari
    Field tx#
    Field ty#
    Field tz#
    Field txv#
    Field tyv#
    Field tzv#
    
    Field px#
    Field py#
    Field pz#
    Field pxv#
    Field pyv#
    Field pzv#
    
    Field t0#
    Field ct#
EndType

start = Timer()

Repeat
    
    ft# = (Timer()-start)*.001
    
    If Timer()>t
        p.pari = New(pari)
        
        p\tx = Rnd(-80,-40)
        p\ty = Rnd(-10, 10)
        p\tz = Rnd(-10, 10)
        p\txv = Rnd(5, 10)
        p\tyv = Rnd(-2, 2)
        p\tzv = Rnd(-2, 2)
        
        p\px = Rnd(-5, 5)
        p\py = Rnd(-16,-15)
        p\pz = Rnd(-15,-13)
        
        ax# = p\tx-p\px
        ay# = p\ty-p\py
        az# = p\tz-p\pz
        bx# = p\txv
        by# = p\tyv
        bz# = p\tzv
        
        s# = Rnd(8,20) // projectile speed
        
        a# = bx*bx+by*by+bz*bz-s*s
        b# = ax*bx+ay*by+az*bz
        c# = ax*ax+ay*ay+az*az
        d# = b*b-4*a*c
        
        If d<.0 Then
            Delete p // no hits, don't shoot
        Else
            If d>.0 Then
                ct1# = (-b-Sqrt(d))/(2*a)
                ct2# = (-b+Sqrt(d))/(2*a)
                If ct1>.0 Then
                    p\ct = ct1
                    If ct2>.0 And ct2<ct1 Then p\ct = ct2
                Else
                    p\ct = ct2
                EndIf
            ElseIf d = .0 Then
                p\ct = -b/(2*a)
            EndIf
            p\pxv = (p\tx+p\txv*p\ct-p\px)/p\ct
            p\pyv = (p\ty+p\tyv*p\ct-p\py)/p\ct
            p\pzv = (p\tz+p\tzv*p\ct-p\pz)/p\ct
            p\t0 = ft
            SetWindow Str(p\ct)
            If p\ct < .0 Then Delete p // no point in shooting
        EndIf
        
        t = Timer()+1000
    EndIf
    k = 0
    For p.pari = Each pari
        pt# = ft-p\t0
        s1# = 50.0/(20.0+p\tz+p\tzv*pt)
        s2# = 50.0/(20.0+p\pz+p\pzv*pt)
        Circle 320+s1*(p\tx+p\txv*pt-3), 240-s1*(p\ty+p\tyv*pt-3), 6*s1
        Circle 320+s2*(p\px+p\pxv*pt-3), 240-s2*(p\py+p\pyv*pt-3), 6*s2
        If pt>p\ct Then Delete p
        k = k + 1
    Next p
    DrawScreen
Forever
Epic solve, dear koodaaja. Epic solve indeed. :D
<Ize> Pitäs tehä allekirjotus..
<Ize> Vois keksiä jonkin nasahtavan sanonnan..
<Ize> Siitä tulis upea legenda ja kaikki vaihtaisivat allekirjoituksensa siihen.
<Ize> Ehkä ei kuitenkaa...

User avatar
valscion
Moderator
Moderator
Posts: 1587
Joined: Thu Dec 06, 2007 8:46 pm
Location: Espoo
Contact:

Re: Ennakkoon ampuminen

Post by valscion » Wed Oct 03, 2012 2:34 pm

koodaaja wrote:Ongelma on varsin mielenkiintoinen, mutta lähestymistapa ei ehkä se kaikista helpoin. Kuten kaavastasi näkee, t|C| muodostaa origokeskisen pallon, jonka voi lausua myös seuraavasti: sqrt(x²+y²+z²) = r <=> x²+y²+z² = r² <=> (ax+bx*t)²+(ay+by*t)²+(az+bz*t)² = t²|C|² <=> ax²+ax*bx*t+bx²t²+ay²+ay*by*t+by²t²+az²+az*bz*t+bz²t² - t²|C|² = 0 <=> t²(bx²+by²+bz²-|C|²)+t(ax*bx+ay*by+az*bz)+ax²+ay²+az², joka on toisen asteen yhtälö muotoa at²+bt+c=0, jossa a,b ja c ovat kaikki vakiollisia, joten sen menee suoraan t = (-b(+-)sqrt(b²-4ac))/2a, mihin kannattaa ohjelmoidessa käyttää jopa välimuuttujia. Neliöjuuren sisäinen diskriminantti (kiitos cce:lle terminologiamuistutuksesta!) b²-4ac kertoo törmäyksistä, sen ollessa negatiivinen ei ammus ehdi enää mitenkään osumaan, sen ollessa 0 se ehtii juuri yhteen pisteeseen ja diskriminantin positiivisilla arvoilla mahdollisia törmäyskohtia on kaksi. Kannattanee myös tarkistaa, että osuminen tapahtuu varmasti tulevaisuudessa, muuten kaava voi antaa t:lle negatiivisenkin arvon. Parhaan tuloksen takaamiseksi kannattanee myös kahden mahdollisuuden tapauksessa valita aiempi vielä tulevaisuudessa oleva jotta osuma tapahtuu mahdollisimman pian. Ajan laskemisen jälkeen tunnetaankin etäisyys (a+b*t) ja aika (t), joten ammuksen nopeusvektori saadaan yksinkertaisesti näistä jakolaskulla (s = vt <=> v = s/t). Esimerkki seuraa.

Code: Select all

... koodia ...
Mietinkin että ongelmalle olisi varmasti jokin helposti ymmärrettävä ratkaisu ja olin oikeassa :) olen iloinen kun kerrankin ymmärsin kaiken selityksestä alusta loppuun asti. Lihavoin ja suurensin muuten koodaaja yhtä kohtaa laskuistasi, jossa olit vielä kerran unohtanut merkitä lausekkeen olevan yhtäsuuri nollan kanssa.
cbEnchanted, uudelleenkirjoitettu runtime. Uusin versio: 0.4.1 — Nyt myös sorsat GitHubissa!
NetMatch - se kunnon nettimättö-deathmatch! Avoimella lähdekoodilla varustettu
vesalaakso.com

User avatar
Pate5
Artist
Artist
Posts: 551
Joined: Tue Aug 28, 2007 4:53 pm
Location: Vantaa

Re: Ennakkoon ampuminen

Post by Pate5 » Wed Oct 03, 2012 3:56 pm

Kiitos loistavasta vastauksesta koodaaja!
CoolBasic henkilökuntaa
Graafikko

User avatar
koodaaja
Moderator
Moderator
Posts: 1583
Joined: Mon Aug 27, 2007 11:24 pm
Location: Otaniemi - Mikkeli -pendelöinti

Re: Ennakkoon ampuminen

Post by koodaaja » Wed Oct 03, 2012 7:09 pm

Haa, tiesihän sen että joku virhe sinne jää! Hatunnosto VesQlle siitä, että ylipäänsä luit kaavan johtamisen noin tarkasti. Huomionarvoista on myös, että kun pallon säde pidetään vakiona, ei tapahdu muuta kuin että -|C|² hyppää t²-termistä vakiotermiin, ja saadaan pallon ja säteen törmäyksen kaava, jonka tajusin lopullisen kaavan saatuani myös johtaneeni muutamaan kertaan raytrace-juttuja viritellessäni, joten ongelma oli ainakin alitajuisesti tuttu.

Mutta kuten sanottua, ongelma on usein helpoin ratkaista muuttamalla sitä!

Post Reply