Der Funktion yIntervallLOG() unten kannst du den minimalen Y Wert und den maximalen Y Werte deiner darzustellenden Zahlenpaare übergeben. (miny, maxy : Extended) - (Negative Werte sind auch OK.)
Du kannst wählen, in wie viele Teile (anzint_min bis anzint_max) die Y Achse ungefähr eingeteilt werden soll. (anzint_min, anzint_max : integer)
Du kannst der Funktion übergeben, welche Zahlentypen du erlauben willst. (Parameter erlaubt: TExtendedArray)
Falls aufgrund der übergebenen Parameter kein Resultat gefunden wird:
Über andereschrittweitenerlaubt:boolean steuerst du, ob zusätzlich getestet werden soll, ob Schrittweiten vom Typ f*10^p, f=1,2,3,4,5,6,7,8,9 möglich sind.
Falls die Funktion keine mögliche Unterteilung findet, dann wird geprüft, ob's mit anzint_min := anzint_min-1 klappt.
Delphi-Quellcode:
uses math;
type TExtendedArray =
array of extended;
function yIntervallLOG( miny, maxy : extended; anzint_min, anzint_max : integer;
erlaubt: TExtendedArray; andereschrittweitenerlaubt : boolean = false ) : TExtendedArray;
var fak_min, fak_max,
delta, int_min, int_max : extended;
potmin, potmax, len, i : integer;
potenz10 : integer;
label nocheinmal;
procedure check( pot: integer; f : extended );
// prüfe, ob f*10^pot im Intervall I liegt und damit eine mögliche schrittweite ist
var wert : extended;
begin
wert := f*power(10,pot);
if ( int_min <= wert )
and ( wert <= int_max )
then
begin
SetLength( Result, length(Result)+1 );
Result[length(Result)-1] := wert;
end;
end;
procedure pot_fak( z : extended;
var pot : integer;
var f : extended );
// Berechne die Zerlegung von z: z = f*10^pot
// IN z - OUT f, pot
begin
if ( abs(z) >= 1 )
then
begin
pot := trunc(log10( abs(z) ));
f := z/power(10,pot);
end
else
begin
pot := trunc(log10( abs(z) ))-1;
f := z/power(10,pot);
end;
end;
begin
delta := maxy - miny;
assert( delta > 0 , '
Maximum ' + floattostr(maxy) + '
nicht grösser als Minimum ' + floattostr(miny) );
nocheinmal:
// Schrittweite liegt aufgrund der Parameter zwischen int_min und int_max:
// I:= Intervall [int_min..int_max]
int_min := delta/anzint_max;
int_max := delta/anzint_min;
// Zerlegungen in_min = fak_min*10^potmin, in_max = fak_max*10^potmax bestimmen:
pot_fak( int_min, potmin, fak_min );
pot_fak( int_max, potmax, fak_max );
len := length(erlaubt);
// Prüfen, ob die erlaubten Vorgaben im Intervall [int_min..int_max] liegen
for i := 0
to len-1
do
for potenz10 := potmin
to potmax
do
check( potenz10, erlaubt[i] );
// keine Werte gefunden?
if ( length(Result) = 0 )
then
begin
// falls andere schrittweiten erlaubt:
// Prüfe, ob n*10^potenz10, für n=1,2,3,4,5,6,7,8,9 möglich ist
// Prüfe also zum Beispiel auf 300er, 70er, 0.4, 0.07 etc. Schritte...
if andereschrittweitenerlaubt
then
begin
for I := 1
to 9
do
for potenz10 := potmin
to potmax
do
check( potenz10, i );
end;
// Wenn immer noch keine Resultate gefunden sind, dann erlauben wir ein tieferes anzint_min:
if ( length(Result) = 0 )
then
if anzint_min > 1
then
begin
dec( anzint_min );
goto nocheinmal;
end;
end;
end;
So rufst du die Funktion auf:
Delphi-Quellcode:
procedure TForm92.Button2Click(Sender: TObject);
var erlaubt, res : TExtendedArray;
min, max : extended;
hs : string;
i : integer;
begin
setlength( erlaubt, 5 );
erlaubt[0] := 1;
erlaubt[1] := 5;
erlaubt[2] := 2;
erlaubt[3] := 2.5;
erlaubt[4] := 7.5;
min := 0;
max := 543;
res := yIntervallLOG( min, max, 8, 16, erlaubt );
hs := 'min=' + min.ToString + #13#10 +
'max=' + max.ToString + #13#10;
hs := hs + 'Mögliche Intervalle:' + #13#10;
for i := 0 to length(res)-1 do hs := hs + floattostr(res[i]) + #13#10;
Showmessage( hs);
end;
Beispiel (Code oben):
Du willst y Werte zwischen 0 und 543 darstellen, die y-Achse soll in 8-16 Teile geteilt werden, erlaubt sind Schrittweiten vom Typ 1*10^p, 5*10^p, 2*10^p, 2.5*10^p und 7.5*10^p.
Resultat: 50 (ist vom erlaubten Typ 5*10^5)
Die Funktion gibt jeweils alle möglichen Schrittweiten (Unterteilungen) aus. Zuerst werden Zahlen vom Typ erlaubt[0] ausgegeben, dann vom Typ erlaubt[1], usw..
Beispiel 2:
Wenn du im Beispiel statt 8-16 Teile nun 4-16 Teile erlaubst, dann gibt dir die Funktion die drei möglichen Unterteilungen 100, 50, 75 zurück. (100 zuerst, weil erlaubt[0]=1, dann 50, weil erlaubt[1]=5 und schliesslich noch 75, weil du mit erlaubt[4]=7.5 auch nach Unterteilungen vom Typ 7.5*10^p suchen lässt.)
Beispiel 3:
res := yIntervallLOG( min, max, 5, 16, NIL, true );
sucht nach Unterteilungen der y-Achse vom Typ n*10^p n=1..9.