Sida 1 av 2
Minsta vinkel, vänster/höger?
Postat: 24 mars 2009, 22:28:12
av larsson
Jag programmerar just nu lite (i C) en snutt där jag behöver ta reda på skillnaden mellan nosens riktning och kompassriktning till ett objekt. Säg att jag står vänd rakt österut, dvs i 90°. I kompassriktning 80° ser jag det observerade objektet, dvs det ligger "tio grader till vänster". Inga problem här, 80-90 = -10.
Om jag istället kikar i riktning 5° och jag har ett objekt 10 grader till vänster så är dess bäring 355°. Nu är det inte så kul längre, 355-10 = 345. Samma elände även om det observerade objektet ligger till höger om mig, problemet ligger förstås i att man "passerar norr" på vägen. Det finns lite trick med att vända på tecknen, räkna kvadranter, och diverse tips jag hittat på nätet. För närvarande löser jag det med en härva if-satser, men jag anar att det finns en elegantare lösning/formel?
Kod: Markera allt
double relativ_baring(double nosriktn, double objektbaring)
{
magic code here ;
return answer;
}
Jag vill göra en funktion som ger svaret -10 oavsett om parametrarna är {90,80} eller {5,355} , eller förstås +10 om observatör och objekt "swappas". Negativa svar betyder vänster och positiva höger.
Hur löser man detta på ett mer sofistikerat sätt än med if-satser?
Re: Minsta vinkel, vänster/höger?
Postat: 24 mars 2009, 22:43:25
av blueint
Kanske ett sätt är att omdefiniera vinkeln från [0,360] till [-180,+180] ..?
Och sedan använda subtraktion på något lämpligt sätt.
Alternativt omdefiniera "nollpunkten" på något sätt.
Solklar och tydlig definition av ingående värden kan också vara bra.
Re: Minsta vinkel, vänster/höger?
Postat: 25 mars 2009, 00:15:15
av larsson
Ja, genom att ha nollan högst upp som en nordpol och sedan två "halvklot" som räknar åt varsitt håll så löser jag räkneproblemen när jag passerar norr. Men då är problemet istället flyttat till "sydpolen" där det blir ett hopp när +180° möter -180°.
Att skriva en snygg funktion (dvs utan if-satser eller loopar) som tar två godtyckliga vinklar och svarar med ± vinkelskillnad (närmsta vägen) var mycket svårare än jag kunde ana, problemet såg så enkelt ut...
If it ain't broken, don't fix it, så jag behåller nog mitt if-sats-härke.
Re: Minsta vinkel, vänster/höger?
Postat: 25 mars 2009, 01:29:07
av limpan4all
Om svaret är mindre än 0, addera 360, sen teckenbyt ger väl det du önskar
Re: Minsta vinkel, vänster/höger?
Postat: 25 mars 2009, 12:59:29
av larsson
Ja det fungerar i exemplet ovan:
5-355 = -350, addera 360 och teckenbyt ==> -10°
Men byt plats på observatören och objektet så faller det:
355-5 = 350. (större än noll, så addera inte 360), teckenbyt ==> -350°
En if-sats till löser förstås problemet :-)
Re: Minsta vinkel, vänster/höger?
Postat: 25 mars 2009, 13:06:13
av limpan4all
Gör ett hopp förbi rutinen om >0 så behövs inget mer.
Re: Minsta vinkel, vänster/höger?
Postat: 25 mars 2009, 13:09:57
av Maalobs
En if-sats, ja...
Re: Minsta vinkel, vänster/höger?
Postat: 25 mars 2009, 14:21:47
av blueint
Kanske om problemet delas upp i fyra delproblem. Dvs 0-180° samt >180-360° för kompassriktning. Samt 0-180° och >180-360° för nosriktning. Det ger fyra fall, vilket borde vara hanterligt?
Det blir if satser, men kanske mer strukturerat?
Ev får ==0 eller ==180° bli två extra fall.
Glöm dock inte att man kan definiera gränser som mindre än 180°. Och lika med 180° och större.
Re: Minsta vinkel, vänster/höger?
Postat: 25 mars 2009, 14:55:47
av Nerre
I exemplet så var A 5 grader och B 355 grader.
Om vi gör så att alla värden över 180 drar vi bort 360 från.
355 - 360 = - 5 grader.
5 - (-)5 = 10 grader är vinkeln mellan dem.
Å andra sidan vet vi redan att vi ska subtrahera. Det blir ju
5 - (355 - 360) = 5 - 355 + 360. Det är då kanske enklare att addera 360 till alla värden som är mindre än 180.
Re: Minsta vinkel, vänster/höger?
Postat: 25 mars 2009, 20:28:05
av larsson
> addera 360 till alla värden som är mindre än 180.
Fungerar ju på exempeltalet. Men om den ena vinkeln är
175° och den andra 185° så blir det pannkaka. Det behövs
en if-sats till. Så här ser koden ut idag, det är en snutt jag hittade
på nätet för ett par veckor sedan:
Kod: Markera allt
offset = bearing - heading ;
if (offset > 180)
offset -= 360;
if (offset < -180)
offset += 360;
Alltså en subtraktion och två if-satser som kan ge upphov till
ytterligare subtraktion eller addition. Fungerar bra med de tal jag
testat. Men det skulle varit mer elegant med nåt i den här
stilen:
angular_diff = sin(angle1) * sqrt(angle2) / arctan2(angle1+angle2 - whatever(pi) ;
Nån sån oneliner verkar inte stå att finna. Allltnog, det funkar som det är och
jag är i grunden en förnöjsam man!
Re: Minsta vinkel, vänster/höger?
Postat: 26 mars 2009, 08:17:40
av Nerre
Trignometriska funktioner drar ju massor med mer kraft än några IF-satser.
Re: Minsta vinkel, vänster/höger?
Postat: 26 mars 2009, 10:39:58
av ToB
En lösning är ju (a ? b : c)
Det blir ju kanske snyggare och kortare kod men jag vet inte hur det påverkar prestandan.
Kod: Markera allt
#include <stdio.h>
int main(){
int nos, obj, diff;
for (nos=0; nos<360; nos+=45){
for (obj=0; obj<360; obj+=45){
diff = obj - nos;
diff = (diff > 180) ? diff-360 : diff;
printf("nos = %3d, objekt = %3d, diff = %4d\n",nos ,obj, diff);
}
}
return 0;
}
Del av utskriften från körningen.
Kod: Markera allt
nos = 0, objekt = 0, diff = 0
nos = 0, objekt = 45, diff = 45
nos = 0, objekt = 90, diff = 90
nos = 0, objekt = 135, diff = 135
nos = 0, objekt = 180, diff = 180
nos = 0, objekt = 225, diff = -135
nos = 0, objekt = 270, diff = -90
nos = 0, objekt = 315, diff = -45
nos = 45, objekt = 0, diff = -45
nos = 45, objekt = 45, diff = 0
nos = 45, objekt = 90, diff = 45
nos = 45, objekt = 135, diff = 90
nos = 45, objekt = 180, diff = 135
nos = 45, objekt = 225, diff = 180
nos = 45, objekt = 270, diff = -135
nos = 45, objekt = 315, diff = -90
...
EDIT:
Kom på att koden ovan inte fungerar riktigt när nosens riktning är större än 180 grader. Det kräver i så fall en sats till.
Principen som jag ville visa borde ändå framgå.
EDIT 2:
Inser just att detta är egentligen samma sak som larsson föreslog.
Re: Minsta vinkel, vänster/höger?
Postat: 26 mars 2009, 10:59:28
av haklu
Om man
vet att argumenten alltid håller sig inom 0 till 360 kan man köra med:
Kod: Markera allt
#include <math.h>
double relativ_baring(double nosriktn, double objektbaring)
{
return fmod(objektbaring - nosriktn + 540.0, 360.0) - 180.0;
}
Är man osäker på argumenten bör man ta det säkra före det osäkra:
Kod: Markera allt
#include <math.h>
double relativ_baring(double nosriktn, double objektbaring)
{
double diff = objektbaring - nosriktn + 180.0;
while (diff < 0)
{
diff += 360.0;
}
return fmod(diff, 360.0) - 180.0;
}
Re: Minsta vinkel, vänster/höger?
Postat: 26 mars 2009, 11:15:35
av Icecap
Och att börja blanda in flytande komma-tal är då verkligen att sänka prestanda.
Re: Minsta vinkel, vänster/höger?
Postat: 26 mars 2009, 11:49:23
av JonasJ
Är det en modern PC programmet körs på lär den knappast ha några problem med varken trigonometriska beräkningar eller flyttal....