Öfters werden Achsenkreuze für diverse Plots gebraucht. Ein kleines Unterprogramm in OMIKRON-Basic geschrieben bietet eine universelle Hilfe beim Programmieren solcher Skalierungen. Es sollte ohne größere Mühen in jedes andere Basic und mit einigen Mühen auch in andere Programmiersprachen übertragbar sein. Zwei Unterroutinen werden dazu zusätzlich benötigt:
Function Blanksweg$: : Beseitigt alle Blanks vor und nach einem String
Function Wandle$: : Erzeugt einen String mit gegebener Stellenanzahl vor und nach dem Komma.
Procedure Achse: : Eigentliche Skalierungsroutine einer Achse Procedure Achskreuz:
Anwendung für ein Achsenkreuz Das Hauptprogramm zu Beginn zeigt einige Demoaufrufe.
Wichtig bei einer Skalierung ist, daß der Aufruf unabhängig für x und y erfolgen kann und die Unterscheidung erst in der Routine erfolgt. Man muß nur die Pixelkoordinaten ‘Von’ und ‘Bis’ in der Ordinate eingeben, die man benutzen will. Der Rest müßte aus den Kommentaren hervorgehen.
Im wesentlichen zur Problemlösung folgendes:
Unt! und Ob! sind die wahren x/y-Werte unten und oben, die nicht verändert werden, damit man nachher z.B. in ein solches Achsenkreuz Funktionswerte einzeichnen kann. Eine Skalierung muß nun die Achsenwerte so auftragen, daß sie in der üblichen ‘Norm’ bleiben, d.h. also Reihenfolge 1,2,3,4.. am Zahlenanfang bzw. 10, 15,20,25 oderO, 2,4,6,8... oder 25,50,75 usw., ohne aber die untere und obere Grenze zu ändern. Für einwandfreie Auswahl der unteren und oberen Grenze ist also der Benutzer verantwortlich.
Um das einwandfrei machen zu können, wird zuerst die Dimension der Größen gecheckt und die längste mögliche Stellenanzahl ermittelt, nach der sich die Skalierung richten muß, damit es keine krummen Zahlenwerte oder/und übereinandergeschriebene Werte gibt. Dazu wird die hochauflösende Norm mit 8* 16-Pixelbuchstaben benutzt! Anschließend wird die Teilungsanzahl (die auf der 10er-Potenz beruht) in Einzelschritten solange geändert, bis eine sinnvolle und ausreichende Anzahl erreicht ist, so daß die Werte auf der Skala in ausreichendem Abstand zueinander stehen. Die feine Teilung erfolgt dann in 10* feineren Schritten (Huepf! im Ggs. zu Teil!).
Für die eigentliche Plotroutine (For P!= usw.) habe ich zur Geschwindigkeitssteigerung Hilfsgrößen vereinbart, da sie sonst doch arg langsam wird. Wichtig bei der Plotroutine ist, daß die Werte, die auf die kleinste Skaleneinheit normiert wurden (teilbar ohne Rest...), sich aber immer auf die unterste WIRKLICHE Grenze (Unt!) beziehen, da ansonsten die Skala schön, aber nicht richtig wäre!. Im Programm prüft man dann auf Teilbarkeit ohne Rest auf die großen Distanzen für die Werteschreibung.
Das Problem am ganzen Programm ist. daß mit Benutzung des Logarithmus immer kleinste Rechenreste hinzukommen. Daher darf man auch nicht auf Modulrest 0 genau prüfen, sondern muß immer auf <= einem absoluten Minimalbetrag checken, oder die Werte entsprechend vorher verringern oder vergrößern - um einen kleinen Minimalbetrag, der immer kleiner als 1 Promille bleiben muß (Auflösung des Schirms). Dieses sind die kleinen 1E-5, die hier und dort im Programm auftauchen. Ansonsten kommt es dann und wann zu unerwünschten Skalierungen, die nicht 'schön' sind. Das Programm in dieser Form ist durch Anklicken auf OM-BAS-R.PRGj lauffähig und die Routine aus dem LST-File nach Löschen des Hauptprogrammes und entsprechendem Umnumerieren mergefähig. Wichtig ist, daß Achse die Funktionen Blanksweg$ und WandleSi benötigt, die es aufruft. Mehr zur Funktionsweise zu sagen, würde Bände füllen. Ein wenig Vertiefung in das eigentlich gut kommentierte Programm dürfte auch Klarheit schaffen.
' --> Demoprogramm für die Skalen (hohe Auflösung)
CLS ' Schirm löschen
TEXT 50,28,"Demo reines Achsenkreuz mit einfachem Raster" ' 1.Demo
Achskreuz(50,590,370,70,-30,80,20,60,0,1)
' Einfaches Achskreuz WAIT *10 ' 10 Sekunden zeigen
CLS ' Schirm löschen
TEXT 50,28,"Demo Achsenkreuzkasten mit doppeltem Raster" ' 2.Demo
Achskreuz(50,590,370,70,-30,80,20,60,1,2)
' Einfaches Achskreuz
WAIT 10 ' 10 Sekunden zeigen
CLS ' Schirm löschen
TEXT 50,28,"Demo für: verschiedene x-Skalierungen bei gleicher Länge" ' 3.Demo
FOR I=40 TO 370 STEP 30 ' Skalenschleife x
Achse(40,600,I,I,0,(I/190)^5.3,-2,0) ' Skala in x
NEXT I
WAIT 10 ' 10. Sekunden zeigen
CLS ' Schirm löschen
TEXT 50,28,"Demo für verschiedene y-Skalierungen bei gleicher Länge" ' 4.Demo
FOR 1=70 TO 620 STEP 50 ' Skalenschleife y
Achse(50,370,I,I,0, (I/177)^4.3,2,0) ' Skala in y
NEXT I
WAIT 10 ' 10 Sekunden zeigen
CLS ' Schirm löschen
TEXT 50,28,"Demo für verschiedene Skalierung und Raster" ' 5. Demo Achse(60,580,366,60,-30,30,-2,2) ' x-Achse unren
Achse(60, 580, 60, 366,1210,1250,-1,0) ' x-Achse eben
Achse(60,366,60,580,-.05,01,2,3) ' y-Achse links
Achse(60,366,580,60,35,40,1,0) ' y-Achse rechts
WAIT 10 ' 10 Sekunden zeigen
CLS ' Schirm löschen
TEXT 50,28,"Demo für gleiche Skalierung und Richtungsumkehr mit Mischraster"
Achse(550,60,360,60,-20,60,-2,3) ' x-Achse unten
Achse(60,550,60,360,-20,60,-1,2) ' x-Achse eben
Achse(360,60,60,550,-.4,.1,2,4) ' y-Achse lunxs
Achse(60,360,550,60,4,.1,1,3) ' y-Achse rechts
WAIT 60 ' 10 Sekunden zeigen
END
' #####################
' # Achsenkreuzkasten #
' #####################
DEF PROC Achskreuz (Links,Rechts, Unten, Oben, Xmin!,
Xmax!,Ymin!,Ymax i,Wie,Raster)
' Links - Pixelwert linke Kante Rechts - Pixelwert rechte Kante
' Unten - Pixelwert untere Kante Oben - Pixelwert obere Kante
' Xmini, Xmax! - Skalenwerte x
' Ymin!, Ymax! - Skalenwerte y
' Wie: 0 Nur Achsenkreuz, 1 Achskasten
' Raster: Rasterbreite in 4er-Pixel (0 kein Raster)
Achse(Links,Rechts,Unten,Oben, Xmin!,Xmax!, -2,Raster)
IF Wie=1 THEN Achse(Links,Rechts,Iben,Unten,Xmin!, Xmax!,-1,0)
Achse(Unten,Oben,Links,Rechts, Ymin!, Ymax!, 2, Raster)
IF Wie=1 THEN Achse (Unten, Oben, Rechts, Links, Ymin!, Ymax!,1,0)
RETURN
' #####################
' # Skalierung Achsen #
' #####################
DEF PROC Achse(Von,Bis,Wo,Hier,Unt!,Ob!,Was,Rast)
' Von - Startpunkt der Achse, Bis - Zielpunkt der Achse I
' Wo - Andere Ordinate Achse selbst, Hier - Andere Ordinate für Raster
' Unt! - Realer unterster Wert, Ob! - Realer oberster Wert
' Was - Ausrichtung (>0 y-Achse, <0 x-Achse, 1 dann rechts, 2 links,
' -2 unterhalb und -1 oberhalb der Achse)
' Rast - Raster zeichnen. (0 nein, x ja im Abstand 4er-Punkte)
' Umkehr der Werterichtung: Bis und Von vertauschen;
LOCAL Unten_Dim,Oben_pim,Stellen,P!,Da,K,Huepf!,
Wieoft,St ' Lokale Variablen
LOCAL Stel, Dist!, Teil! ,Teil_Dim,Teil,Unten!,Oben!, Teilmax ' Lokale Variablen
LOCAL Hilf1,Hilf1!,Hilf2,Hilf3,Hilf4,Hilf5,Hilf6, Merken ' Zur Beschleunigung
Rast= ABS(Rast) ' Nur positives Raster
Dist!= ABS(Ob!-Unt!) ' Differenz Skalenenden
Ob!=Ob!+Dist!*1E-5 ' Oben bi_chen mehr
Unt!=Unt!-Dist!*1E-5 ' Unten bi_chen weniger
Unten!=Unt!:Oben!=Ob!' Skalenenden
Unten_Dim= LOG(10, ABS(Unten!)+1E-5) ' Dimension untere Grenze
Oben_Dim= LOG(10, ABS(Oben!)+1E-5) ' Dimension obere Grenze
St= MAX (Oben_Dim, Unten_Dim) ' Optimale Stellenanzahl
' —-- Ermittlung der maximalen Stellenzahl
Stel= ABS(St)+2-2*(St<=1) - (Un! <0) ' Maximale Stellenzahl merken
IF Was>0 THEN ' y-Achse
DRAW Wo,Von TO Wo,Bis ' y-Achse zeichnen
Hoehe= ABS(Bis-Von) ' Pixelhöhe der Achse
Teilmax= INT(Hoehe/22) ' max. Zahleinteilung
ELSE ' x-Achse
DRAW Von,Wo TO Bis,Wo ' x-Achse zeichnen
Breite= ABS(Bis-Von) ' Pixellänge der Achse
Teilmax= INT(Breite/10/Stel) ' max. Zahleinteilung
ENDIF
' — Ermittlung der groben Teilung (Zahlenwerte)
Stellen=St ' Zuweisung der Stellen
REPEAT ' Bei engen Werten solange...
Stellen=Stellen-1 ' ... erniedrigen, bis ...
Huepf!=10^Stellen ' ... Schrittweite OK.
Oben!=( INT(Ob!/Huepf!))*(Huepf!) ' Grenze oben drunter setzen
Unten!*( INT(Unt!/Huepf!)+1)* (Huepf!)' Grenze unten drüber setzen
UNTIL ABS((Oben!-Unten!)/(Huepf!))>Teilmax
' Feinstriche md. sooft wie Teilung
Teil!=Huepf!*10 ' Variable grobe Teilung
Teil_Dim= INT ( LOG(10,Teil!)) ' Dimension des Teils
Teil=(Oben!-Unten!)/Teil! ' Ganzanteil
Merken=0 ' Merkvariable für .25 Teilung
IF(Teil*5)<=Teilmax THEN Teil!=Teil!/5:Teil=Teil*5 ' Skalenteile zu wenig
IF(Teil*2)<=Teilmax THEN Teil!=Teil!/2:Teil*Teil*2 ' Skalenteile zu wenig
IF(Teil*5)<=Teilmax THEN Teil!=Teil!/5:Teil*Teil*5 ' Immer noch zu eng
IF(Teil*2)<=Teilmax THEN Teil!=Teil!/2:Teil=Teil*2: Merken=1 ' ,25-Teilung!
' — Ermittlung der feinen Teilung (Striche)
Huepf!=Teil!/10
Oben!=( INT(Ob!/Huepf!))*(Huepf!)' Grenze oben drunter setzen
Unten!=( INT (Unt! /Huepf!) +1) * (Huepf!) ' Grenze unten drüber setzen
Dist!=Oben!-Unten! ' Differenz Skalenenden
Wieoft=Dist!/Huepf! ' ..neue Anzahl der Schritte
Vorher=Stel+2 ' Stellen vor dem Komma
Grenze!=Huepf!/10 ' Limitdefinition
Hilf1!= INT ( LOG(10,Teil!)+1D-8)' Hilfsgrö_e
Nachher=MAX(0,-Hilf1!)+Merken ' Nachkommastellen
Hilf1! =(Bis-Von)/(Ob!-Unt!) ' 1. Hilfsgrö_e zur Beschleunigung
Hilf1=(1.5-Was)*4' 2. Hilfsgrö_e zur Beschleunigung
Hilf2=Rast*3* SGN(Hier-Wo) ' 3. Hilfsgrö_e zur Beschleunigung
Hilf3=(1.5+Was)*4’ 4. Hilfsgrö__e zur Beschleunigung
Hilf4=10*(Was=1):Hilf5=8*(Was=2) ' 5.+6. Hilfsgrö_e
Hilf6=-24*(Was=-2)+9*(Was=-1) ' 7. Hilfsgrö_e
FOR P!=Unten! TO Oben!+Dist!*1E-5 STEP Huepf! ' Schleife
P$=FN Wandle$(P!»Vorher,Nachher)' String bilden
P$=FN Blanksweg$(P$) ' Blanks weg
Da=Von+(P!-Unt!)*Hilfl!' Ort ermitteln(wahrer Ort!)
Pmodul!= ABS ( INT((P!+Grenze!)/Teil!)*Teil!-P!)
' Wertentscheidungsvariable
IF Was>0 THEN ' y-Achse
DRAW Wo,Da TO Wo+Hilf1,Da ' Zeichnen des feinen Striches
IF Pmodul!<Grenze! THEN ' Platz für Text
DRAW Wo,Da TO Wo+Hilf1*2.5,Da ' Grober Strich
TEXT Wo-Hilf4+(1+ LEN(P$))*Hilf5,Da+7,P$
' Zahl schreiben
IF Rast>0 THEN
FOR K=Wo TO Hier STEP Hilf2: DRAW K,Da: NEXT K ' Raster
ENDIF
ENDIF
ELSE ' x-Achse
DRAW Da,Wo TO Da,Wo-Hilf3 ' zeichnen des feinen Striches
IF Pmodul!<Grenze! THEN ' Platz für Text
DRAW Da,Wo TO Da,Wo-Hilf3*2.5 ' Grober Strich
TEXT Da- LEN(P$)*4,Wo+Hilf6, P$ ' Zahl schreiben
IF Rast>0 THEN
FOR K=Wo TO Hier STEP Hilf2: DRAW Da,K: NEXT K ' Raster
ENDIF
ENDIF
ENDIF
NEXT P!
RETURN
' ##################################
' # Löscht Blanks vorne und hinten #
' ##################################
DEF FN Blanksweg$(Was$)
LOCAL Vorne,Hinten' Lokale Variablen
FOR Vorne=1 TO LEN(Was$)' 1. Buchstaben ungleich Blank
IF MID$(Was$,Vorne, 1)<>" " THEN EXIT
NEXT Vorne
FOR Hinten= LEN(Was$) TO 1 STEP -1 ' Letzten Buchstaben ungleich
IF MID$(Was$,Hinten,1)<>" " THEN EXIT
NEXT Hinten
IF Vorne<1 THEN Vorne=1 ' Probleme korrigieren
IF(Hinten-Vorne)<1 THEN Hinten=Vorne+1 ' Bei Problemen korrigieren
RETURN MID$(Was$,Vorne,Hinten-Vorne+1)' Blankfrei zurückgeben
' ##########################################
' # String bilden mit Vor und Nach-Stellen #
' ##########################################
DEF FN Wandle$(Wert!,Vor,Nach)
LOCAL Total,Wie$,Wxu$ ' Lokale Variablen
IF Nach<0 THEN Nach=0 ' Nach Minimum 0
IF Vor<1 THEN Vor=1 ' Vor Minimum 1
Total=Vor+Nach+1+(Nach=0)' Totallänge
Wie$="#"*Vor' Vorstellen
IF Nach>0 THEN Wie$*Wie$+"."+"#"*Nach'Nachstellen
USING Wie$' So gebrauchen
Wxu$= STR$(Wert!)' Wert zuweisen
USING ' Wieder Normalgebrauch
RETURN Wxu$' und Wert zurück..