2012-11-10 12 views
5

Szukam funkcji gdzieś w Delphi XE2 podobnej do Inc(), która pozwala mi dodawać/odejmować liczbę stopni od aktualnej liczby stopni i doprowadzić do nowych stopni. Na przykład, jeśli mam obecnie punkt o 5 stopni wokół okręgu, a chcę odjąć 10, nie powinienem otrzymać -5 stopni, ale raczej 355 (360 - 5). Taki sam jak dodanie z przeszłości 360 - powinien powrócić do 0, gdy osiągnie 360.Czy istnieje funkcja przesuwania stopni koła po wartości 0?

Czy coś takiego już jest w Delphi, więc nie muszę go ponownie pisać? Być może w jednostce Math?

+3

Dla przypomnienia: Delphi XE3 ma funkcję DegNormalize() w System.Math. – Giel

+3

Chciałbym skomentować, że to pytanie, odpowiedzi i komentarze są kwintesencją tego, dlaczego uwielbiam Stack Overflow. Nauczyłem się dużo o jednej małej funkcji, którą myślałem, że już polizałem. Dobrze grają wszyscy! –

+0

Cała ta wiedza zamknięta w głowach programistów i kodu, a my nie wiemy, czego nie wiemy ... To jest piękno poszerzania naszej wiedzy. –

Odpowiedz

10
uses 
    System.SysUtils,Math; 

Function WrapAngle(angle : Double) : Double; 
Const 
    modAngle : Double = 360.0; 
begin 
    Result := angle - modAngle*Floor(angle/modAngle); 
end; 

begin 
    WriteLn(FloatToStr(WrapAngle(-5))); 
    WriteLn(FloatToStr(WrapAngle(5-720))); 
    WriteLn(FloatToStr(WrapAngle(360))); 
    ReadLn;  
end. 

Produkuje wynik:

355 
5 
0 

Aktualizacja:

Jak znaleźć @Giel w XE3 jest nowa funkcja DegNormalize() który wykonuje th e praca. Nawet o 25% szybciej. Sztuką jest zastąpienie połączenia Floor() z Int(), a jeśli wynik jest ujemny, dodaj modAngle do wyniku.

+0

+1 to jest bardzo eleganckie. –

+0

Dzięki, używam go w wielu aplikacjach.Poprzez podstawienie modAngle na 2 * Pi masz również działającą funkcję dla radianów. –

+0

Rzeczywiście. Lub podaj moduł jako parametr. Moja wersja wydaje się niepotrzebnie skomplikowana. Myślę, że używamy niektórych pomocników w innych procedurach. –

1

ja nie wiem, ale wolałbym, stosując bardziej ogólne rozwiązanie tak ...

Procedure IncOverFlow(var Value:Double;Difference:Double;Limit:Double=360); 
begin 
    Value := Value + Difference; 
    While Value < 0 do Value := Value + Limit; 
    While Value >= Limit do Value := Value -Limit; 
end; 
+0

Biorąc pod uwagę każdą formułę, z której korzystałem, zajmuje radiany, używam 'DegToRad' i' RadToDeg'. – Petesh

+0

@Petesh mi pomóż, nie widzę kontekstu na pytanie. Niektóre stopnie wykorzystania API, na powierzchni są zwykle. – bummi

+0

Nie pukam w twoją odpowiedź; Jest świetny do ogólnej funkcji przyrostowej opartej na float. Po prostu 'RadToDeg (DegToRad (Value + Increment)))) da mniej więcej taką samą odpowiedź (+/- zwykłe błędy konwersji) – Petesh

3

Kod użyć do wykonania tego zadania to:

function PosFrac(x: Double): Double; 
(* PosFrac(1.2)=0.2 and PosFrac(-1.2)=0.8. *) 
begin 
    Result := Frac(x); (* Frac(x)=x-Int(x) *) 
    if Result<0.0 then begin 
    Result := 1.0+Result; 
    end; 
end; 

function ModR(const x, y: Double): Double; 
(* ModR(1.2,1)=0.2 and ModR(-1.2,1)=0.8 *) 
var 
    absy: Double; 
begin 
    if y=0.0 then begin 
    Result := 0.0; 
    end else begin 
    absy := abs(y); 
    Result := PosFrac(x/absy)*absy; 
    end; 
end; 

function Mod360(const x: Double): Double; 
begin 
    Result := ModR(x, 360.0); 
end; 

ten kod wprowadzi wszystkie kąty w zakresie 0 do 360. Na przykład:

Writeln(Round(Mod360(5-10))); 
Writeln(Round(Mod360(5-360))); 
Writeln(Round(Mod360(5-720))); 
Writeln(Round(Mod360(5+720))); 

Wyjścia:

 
355 
5 
5 
5 
+0

+1: Widzę na tym tle Twoją domenę żeglarską :-) –

+0

@Marjan Ten kod działa w OrcaFlex od 25 lat. Niezwykły styl komentarzy jest taki, że kod nie został zmieniony od czasów, gdy kod był Modula-2! –

+0

25 lat, huh? Miły! I nawet nie zauważyłem stylu komentarza. Często używam '(* *)' do kopiowania wklejanych rzeczy, z których pracuję, w celu odróżnienia ich od zwykłych komentarzy i uniknięcia braku zagnieżdżenia komentarzy '{}. –

4
function WrapAngle(Value: Integer): Integer; 
begin 
    Result := Value mod 360; 
    if Result < 0 then 
    Inc(Result, 360); 
end; 
+0

Prawdopodobnie jest to najczystsze z możliwych do wprowadzenia na liczbę całkowitą. –

1
procedure WrapAngle(var Degs: Integer); 
begin 
    Degs := Degs mod 360; 
    if Degs < 0 then 
    Inc(Degs, 360); 
end;