Es ist ein Kreuz mit... - Skalierung leicht erzeugt

Ö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..


Jost Jahn



Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]