; ; FLEXPROJECTOR (RECORDERCODE) X-SPLINEVERSION ; ============================================ ; ; Name: Flexprojector (Recordercode), X-Splineversion ; Quelle: Jenny, Bernhard, Zürich. Idee von Tom Patterson. ; Interactive design of small-scale map projections. ; Unpublished, B. Jenny, Zürich. ; Richtung: Direkt-Transformation ; Aus Robinson-Projektion, Originalvariante mit 5-Grad-Tabelle entwickelt. ; ; Der Flexprojector ist ein von B. Jenny, Zürich entwickeltes und in Java implementiertes ; Programm, das weitgehend beliebige Kartennetzentwürfe approximiieren kann. Das Grundprinzip ; des Flexprojectors ist Interpolation eines Kartennetzes anhand von tabellierten Koeffizienten. ; Bei dem Verfahren handelt es sich um eine Weiterentwicklung der Robinson-Projektion. ; ; Es gibt 4 Tabellen: RX (Length of Parallels), RY (Distance of Parallels), ; RB (Bending) und RM (Meridians Distribution). RX, RY und RB sind Funktionen der ; geographische Breite Phi, RM der geographische Länge Lambda. Weiterhin gibt es ; einen "Global Scale" Rs und "Proportions" Rk. ; ; RX und RY stammen von Robinson, RB und RM hat Jenny hinzugefügt. ; ; Die Tabellen können durch das Programm Flex Projector erzeugt werden. ; ; RECORDERCODE. Import der Koeffizienten über sog. FLEXPROJECTOR INTERFACE wie folgt: ; ; 1. Export aus Flex Projector (Menü "File"/"Save as") in eine Textdatei. ; 2. Umnennen dieser Datei in "flexi.dat" und Abspeichern im aktuellen Verzeichnis. ; 3. Nun wird die Datei "flexi.dat" in das Array flexi eingelesen (read-Befehl). ; ; ! RECORDERCODE. Der Recordercode gleicht dem Mastercode, d. h. er ist die weitgehend ; ! originalgetreue Implementation des Flexprojectors, insbesondere mit Import der ; ! Koeffizienten über das Flexprojector Interface. Die Koeffizienten werden aber nicht nur ; ! importiert, sie werden auch im Ausgabetext und in einer Datei flexrec.txt aufgezeichnet. ; ; ! Mit dieser Aufzeichnung kann dann Fixcode erzeugt werden. Hier wird nichts Variables ; ! mehr importiert, sondern die Koeffizienten stehen als Konstanten fest im Code. ; ! Der Fixcode rechnet also immer einen einzelnen bestimmten festen unveränderlichen Netzentwurf. ; ; ! X-SPLINEVERSION: Die Standard-Recorderversion interpoliert mit Inlinecode mit aufsteigenden Newton- ; ! differenzen. Die X-Newtonversion rechnet genauso, hat aber den Interpolationscode in ein Unter- ; ! programm ausgelagert. Die X-Splineversion interpoliert mit kubischen Splines in dem Unterprogramm. ; ; Das Programm übernimmt die Koordinaten eines Punktes (x/y) und transformiert diese in einen ; Punkt (x'/y'). ; ; x/y sind ebene Zielpunktkoordinaten, x'/y' geben die geogr. Breite und Länge ; der Position auf der Quell-Erdkugel, auf der der Zielpunkt gelesen werden ; kann. ; Literatur: ; Jenny, B.; Patterson, T.; Hurni, L.: Flex Projector – Interactive Software for ; Designing World Map Projections. Cartographic Perspectives, No. 59, Winter 2008 ; (zit. n. www.flexprojector.com). ; Jenny, B., Patterson, T., Hurni, L.: Interactive Design of Small-scale Map Projections. ; Unpublished. Zürich 2008. ; Evenden (2005) 5.2.31, S. 66. ; Eric M. Delmelle: Map Projection Properties. Considerations for Small-scale GIS Applications. ; GISaCC, Dept. of Geogr., Sept. 2001, S. 63. ; www.flexprojector.com (Zugriff 14.10.2008) ; Stand: ; Begonnen mit Flex Projector 0.43 alpha, Test mit 0.100 beta. In der Datei flexi.dat müssen ; Windows-Zeilenumbrüche und Deizimalpunkte stehen. Das ist ab 0.100 beta gewährleistet. In ; älteren Versionen ist dies "zu Fuß" zu ändern. ; 10.10.2008 RB -- Initial mit Flex projector 0.43 alpha ; 15.10.2008 RB -- Mail von B. Jenny vom 17.10.2008. Unveröffentlicht: Der 15°-Faktor ("dm") muss durch 2 geteilt werden! ; 19.10.2008 RB -- quadratic [Bendinng] in cubic. ; 29.10.2008 RB -- Test mit Flexprojector 0.100 beta. ; 03.11.2008 RB -- X-Splineversion ; (C) Dr.-Ing. Rolf Böhm 2005, 2007, 2008 ; Benutzte Variablen ; ================== ; ; Hauptvariablen ; _name Flexprojector~(Recordercode)~[X-Splineversion] _var phi ; Geographische Breite _var lambda ; Geographische Länge _var lambda0 ; Geogr. Länge des Bildmittelpunktes _var scale ; Kartenmaßstabszahl (also 1000000, nicht 1/1000000) _var sign ; Vorzeichen ; ; Die 4 Koeffizienten ; _var rx ; Robinson-X-Koeffizient, bei Jenny l-phi ("Length") _var ry ; Robinson-Y-Koeffizient, bei Jenny d-phi ("Distance") _var rb ; Der 3. Koeffizient Jennys, "Bending", b-phi _var rm ; Der 4. Koeffizient Jennys "Meridians Distribution", m-lambda ; ; Importfeld Flexprojector Interface ; _dim flexi 100 ; ; Zielvariablen des Flexprojector Interfaces ; ; Alle Variablen, die über die Flexprojector-Schnittstelle "hereinkommen" beginnen ; mit einem großen R wie Robinson ... ; _var Rs ; Jennys: Global Scale / s _var Rk ; Jenny: Proportions / k _dim RX 21 ; Length of Parallels (Robinsons X) _dim RY 21 ; Distance of Parallels form Equator (Robinsons Y) _dim RB 21 ; Bending _dim RM 15 ; Meridians Distribution ; ; Sonstige Variablen aus dem Jenny-Manuskript ; _var jskPi ; Jennys Factor s*k*Pi (Robinsons Y-Factor) _var jBlp ; Jennys b-lambda-phi bei der Bending-Einrechnung; ; ; Interne Variablen der Unterprogramme ; _var .return ; Rücksprungadresse 2. Ordnung _var .fix- ; 0. Tafelwert, ganzzahlig _var .fix ; 1. Tafelwert, ganzzahlig _var .fix' ; 2. Tafelwert, ganzzahlig _var .fix'' ; 3. Tafelwert, ganzzahlig _var .frac ; Gebrochener Teil _var .x- ; Tafelwert Stelle -1 _var .x0 ; Tafelwert Stelle 0 _var .x1 ; Tafelwert Stelle 1 _var .x2 ; Tafelwert Stelle 2 _var .d0 ; Differential Stelle 0 _var .d1 ; Differential Stelle 1 _var .A ; Konstanter Koeffizient _var .B ; Linearer Koeffizient _var .C ; Quadratisher Koeffizient _var .D ; Kubischer Koeffizient ; ; Sonstiges ; _var oldphi ; Alte geographische Breite _var pi³ _var 15° _var return ; Globale Rücksprungadresse _var initial ; True: Progrmm ist initialisiert ; ; x, y, x', y', Cx', Cy', °(, (°, pi, pi/2 etc. sind vordefinierte globale Konstanten ; ; ; Initialisierung ; =============== ; tstne initial 077$ pause Hinweis:~Dieses~Programm~rechnet~eine~Vorwärtstransformation.\¶ Es~muss~mit~einer~direkt~arbeitenden~Projection~engine~abgearbeitet~werden.\\¶ Die~Flexprojector-Koeffizienten~werden~in~einer~Datei~»flexi.dat«~erwartet.~¶ Sie~werden~in~der~Datei~»flexrec.txt«~aufgezeichnet.¶ ; Konstanten berechnen mov pi³ pi mul pi³ pi mul pi³ pi mov 15° 15 mul 15° °( div 15° 2 ; MAIL B. JENNY 17.10.2008 ; Daten lesen mov return 051$ jump $$tab_read 051$: ; Daten importieren (zurechtsortieren) mov return 053$ jump $$tab_import 053$: ; Aus dem Flexprojektor Interface resultierende Konstanten berechnen mov jskPi Rk ; s mul jskPi Rs ; s*k mul jskPi pi ; s*k*pi ; Dialog input scale Maßstabszahl input lambda0 Mittelpunktslänge~in~Grad ; Eingegebene Werte auf Min/Max bringen clip scale 1 1E12 clip lambda0 -180 180 ; Programm ist initialisiert mov initial 1 077$: ; ; SIMD-Laufbereich ; ================ ; ; Eigentlicher Entwurf, dieser direkt! ; ------------------------------------ ; mov lambda x ; Geographische Länge mov phi y ; Geographische Breite sub lambda lambda0 cmpgt lambda -180 10$ add lambda 360 10$: cmpgt lambda -180 30$ add lambda 360 30$: cmplt lambda 180 40$ sub lambda 360 40$: cmplt lambda 180 50$ sub lambda 360 50$: ; x, y haben eine Zweifachbedeutung: ; - einmal die verdefinierten RTA-Input-Koordinaten, also eigentlich Phi und Lambda, ; - dann aber auch die ebenen Kartenkoordinaten, die errechnet werden, ; ; Umrechnung in Bogenmaß ; ---------------------- ; mul phi °( mul lambda °( mov sign phi sgn sign tstlt sign 89$ mov sign 1 ; Am Äquator muss sign 1 sein statt 0 89$: abs phi ; ; Flexprojector-Koeffizienten holen (In der Tabelle interpolieren) ; ---------------------------------------------------------------- ; cmpeq phi oldphi 91$ ; Nur wenn sich phi geändert hat: mov return 91$ jump $$tab_interpol_xyb ; X-Wert rx, Y-Wert ry und Bending-Wert rb an der Stelle phi holen 91$: mov oldphi phi mov return 93$ jump $$tab_interpol_m ; Immer: Meridian-Dist-Wert rm an der Stelle lambda holen 93$: ; ; Jennys b-lambda-phi jBlp berechnen ; ---------------------------------- ; mov r0 lambda sgn r0 mov r1 lambda mul r1 lambda mul r1 lambda abs r1 div r1 pi³ tstgt rb 96$ mov r0 1 sub r0 r1 mul r0 rb add r0 1 mov jBlp r0 jump 97$ 96$: mul r1 rb mov r0 1 sub r0 r1 mov jBlp r0 97$: ; ; Eigentlicher Entwurf ; -------------------- ; mov x lambda sgn x mul x rm ; Jenny: m-lambda mul x 15° ; jenny: d-m add x lambda ; (lambda + sgn(lambda)*rm*15°) mul x rx ; rx ... Jennys l-phi mul x Rs ; Jenny Global Scale / s / Robinsons X-Faktor 0.8487 mov y ry mul y jskPi ; Jannys s*k*Pi = Robinsons Y-Faktor 1.3523 mul y jBlp ; Bending: mit jBlp = Jennys b-lambda-phi multiplizieren mul y sign ; Nur y braucht noch das Vorzeichen von phi ; ; Maßstab, Kartenmittelpunkt etc. einrechnen ; ------------------------------------------ ; mul x Rx' ; Erdradius div x scale ; Kartenmaßstab add x Cx' ; mul y Ry' div y scale add y Cy' ; ; Schlussarbeiten ; --------------- ; 111$: mov x' x mov y' y exit ; --------------------------------------------------------------------------------------------------------------- ; ; Unterprogramm $$tab_interpol_xyb: Koeffizient aus Tabelle interpolieren ; ======================================================================= ; ; Die zu einer geographischen Breite phi zugehörigen Robinson-Jenny-Koeffizienten ; rx, ry und rb werden ermittelt. ; ; Definitionsbereich 0 ... 90 und noch etwas weiter. ; ; Die Parameter werden global übergeben. Das Unterprogramm erwartet: ; ; phi geographische Breite im Bogenmaß ; RX X-Tabelle als Feld mit den Elementen RX(0) ... RX(95) ; RY Y-Tabelle als Feld mit den Elementen RY(0) ... RY(95) ; RB B-(Bending)-Tabelle als Feld mit den Elementen RB(0) ... RB(95) ; return Rücksprungadresse ; ; Das Unterprogramm liefert: ; ; rx Robinson-Koeffizient x ; ry Robinson-Koeffizient Y ; rb Bending Koeffizient ; $$tab_interpol_xyb: ; ; phi in Vorkomma- und Nachkommateil zerlegen ; mov r0 phi mul r0 (° ; in Gradmaß div r0 5 ; in 5-Grad-Schritten clip r0 0 18 ; ; Interpolations-Unterprogramm für RX-Tabelle -> rx rufen ; mov .TA RX mov .return 293$ jump $$tab_int_xspline ; Interpoliert in Tabelle .TA an Stelle r0 und gibt Wert auf r1 zurück. 293$: mov rx r1 ; ; Interpolations-Unterprogramm für RY-Tabelle -> ry rufen ; mov .TA RY mov .return 295$ jump $$tab_int_xspline ; Interpoliert in Tabelle .TA an Stelle r0 und gibt Wert auf r1 zurück. 295$: mov ry r1 ; ; Interpolations-Unterprogramm für RB-Tabelle -> rb rufen ; mov .TA RB mov .return 297$ jump $$tab_int_xspline ; Interpoliert in Tabelle .TA an Stelle r0 und gibt Wert auf r1 zurück. 297$: mov rb r1 jump return ; --------------------------------------------------------------------------------------------------------------- ; ; Unterprogramm $$tab_interpol_m: Meridian-Distribution Koeffizient aus Tabelle interpolieren ; =========================================================================================== ; ; Der zu einer geographischen Länge lambda zugehörigen Koeffizient rm wird berechnet. ; ; Definitionsbereich 0 ... 180 Gradund noch etwas weiter. ; ; Die Parameter werden global übergeben. Das Unterprogramm erwartet: ; ; phi geographische Breite im Bogenmaß ; RM Y-Tabelle als Feld mit den Elementen RM(0) ... RM(95) ; return Rücksprungadresse ; ; Das Unterprogramm liefert: ; ; rm Meridian-Distribution-Wert an der Stelle lambda ; $$tab_interpol_m: ; ; lambda in Vorkomma- und Nachkommateil zerlegen ; mov r0 lambda abs r0 mul r0 (° ; in Gradmaß div r0 15 ; in 15-Grad-Schritten clip r0 0 12 ; ; Interpolations-Unterprogramm rufen ; mov .TA RM mov .return 303$ jump $$tab_int_xspline ; Interpoliert in Tabelle .TA an Stelle r0 und gibt Wert auf r1 zurück. 303$: mov rm r1 ; Verbesserung 2. Ordnung ; ; Ende Unterprogramm tab_interpol_m ; jump return ; --------------------------------------------------------------------------------------------------------------- ; ; Unterprogramm $$tab_read: Tabelle mit Flexprojektor-Koeffizienten lesen ; ======================================================================= ; ; Das Unterprogramm liest die Datei "flexi.dat" in das Feld flexi. ; ; Die Parameter werden global übergeben. Das Unterprogramm erwartet: ; ; "flexi.dat" eine Datei mit den Flexprojector-Daten im aktuellen Verzeichnis. ; flexi eine leeres Feld mit den Elementen flexi(0) ... flexi(90) ; return Rücksprungadresse ; $$tab_read: mode 0 ; Andere Modi führen bei unrichtigen Datei/Feldlängen zu einer Unterbrechung read flexi 90 ; Datei lesen adrof flexi flexi(0) ; Feldpointer einstellen jump return ; --------------------------------------------------------------------------------------------------------------- ; ; Unterprogramm $$tab_import: Das Flexprojektor-Interface-Feld flexi zurechtsortieren ; =================================================================================== ; ; Es werden vier Tabellen mit Flexprojector-Koeffizienten x, y, Bending und Meridian dist gefüllt. ; ; Die Parameter werden global übergeben. Das Unterprogramm erwartet: ; ; flexi ein gefülltes Feld mit den Elementen flexi(0) ... ca. flexi(90) ; RX eine leeres Feld mit den Elementen RX(0) ... RX(21) ; RY eine leeres Feld mit den Elementen RY(0) ... RY(21) ; RB eine leeres Feld mit den Elementen RB(0) ... RB(21) ; RM eine leeres Feld mit den Elementen RM(0) ... RM(15) ; return Rücksprungadresse ; ; ... und noch einige andere Globals wie jGlobSc, jskPI etc. ; $$tab_import: cls ; Recordercode: Clean screen ; ; Proportions k ; mov Rk flexi(1) prints nop\ prints nop~~~~~~###~Roher~Recodercode~~~~~~~~~~~~~~~~~~~~~~###\ prints nop~~~~~~###~Muss~noch~manuell~überarbeitet~werden~~###\ prints nop~~~~~~###~Steht~auch~in~der~Datei~flexrec.txt~~~~###\ prints nop\ prints mov~Rk~ ; Recordercode printn flexi(1) 1 6 prints \ ; ; Global Scale s ; mov Rs flexi(3) prints mov~Rs~ ; Recordercode printn flexi(3) 1 6 prints \ ; ; X-Koeffizienten nach RX schaffen ; mov r1 5 mov r2 0 mov r7 19 $$tab1: get r0 flexi r1 put RX r2 r0 prints mov~RX( ; Recordercode printn r2 2 0 prints )~ printn r0 1 6 prints \ inc r1 inc r2 dec r7 tstgt r7 $$tab1 mov RX(19) RX(18) ; Hinten linear extrapolieren mov RX(20) RX(18) mov r5 RX(18) sub r5 RX(17) add RX(19) r5 add RX(20) r5 add RX(20) r5 ; prints mov~RX(19)~ ; Recordercode printn RX(19) 1 6 prints \ prints mov~RX(20)~ ; Recordercode printn RX(20) 1 6 prints \ ; ; Y-Koeffizienten nach RY schaffen ; mov r1 31 mov r2 0 mov r7 19 $$tab2: get r0 flexi r1 put RY r2 r0 prints mov~RY( ; Recordercode printn r2 2 0 prints )~ printn r0 1 6 prints \ inc r1 inc r2 dec r7 tstgt r7 $$tab2 mov RY(19) RY(18) ; Hinten linear extrapolieren mov RY(20) RY(18) mov r5 RY(18) sub r5 RY(17) add RY(19) r5 add RY(20) r5 add RY(20) r5 ; prints mov~RY(19)~ ; Recordercode printn RY(19) 1 6 prints \ prints mov~RY(20)~ ; Recordercode printn RY(20) 1 6 prints \ ; ; Bending-Koeffizienten nach RB schaffen ; mov r1 52 mov r2 0 mov r7 19 $$tab3: get r0 flexi r1 put RB r2 r0 prints mov~RB( ; Recordercode printn r2 2 0 prints )~ printn r0 1 6 prints \ inc r1 inc r2 dec r7 tstgt r7 $$tab3 ; mov RB(19) RB(18) ; Hinten linear extrapolieren mov RB(20) RB(18) mov r5 RB(18) sub r5 RB(17) add RB(19) r5 add RB(20) r5 add RB(20) r5 ; prints mov~RB(19)~ ; Recordercode printn RB(19) 1 6 prints \ prints mov~RB(20)~ ; Recordercode printn RB(20) 1 6 prints \ ; ; Meridians-Distribution-Koeffizienten nach RM schaffen ; mov r1 72 mov r2 0 mov r7 13 $$tab4: get r0 flexi r1 put RM r2 r0 prints mov~RM( ; Recordercode printn r2 2 0 prints )~ printn r0 1 6 prints \ inc r1 inc r2 dec r7 tstgt r7 $$tab4 mov RM(13) RM(12) ; Hinten linear extrapolieren mov RM(14) RM(12) mov r5 RM(12) sub r5 RM(11) add RM(13) r5 add RM(14) r5 add RM(14) r5 ; prints mov~RM(13)~ ; Recordercode printn RM(13) 1 6 prints \ prints mov~RM(14)~ ; Recordercode printn RM(14) 1 6 prints \ ; save flexrec ; Recordercode in Datei schreiben jump return ; --------------------------------------------------------------------------------------------------------------- ; ; Unterprogramm $$tab_int_xspline: Kubische Splineversion ; ======================================================= ; ; Es wird ein Wert r1 an der Stelle r0 in einer Tabelle .TA mit kubischen Splines ; interpoliert. Das Unterprogramm erwartet: ; ; r0 Zu interpolierender Wert. Achtung: Keine Wertebereichsüberprüfung!! ; .TA Tabellenadresse ; .return Rücksprungadresse (Aufruf 2. Ordnung, auf return steht bereits die Rücksprungadresse 1. O.) ; ; Das Unterprogramm liefert: ; ; r1 Interpolierter Wert ; r0 ... bleibt erhalten und kann für weitere Rufe benutzt werden ; ; $$tab_int_xspline: ; get r7 .TA -1 ; Feldpointer retten get r6 .TA 1 ; Feldelement 1 ... put .TA -1 r6 ; auf den Feldpointer (!) - so wird die Ableitung in Punkt 0 Null! ; ; lambda in Vorkomma- und Nachkommateil zerlegen ; mov .fix r0 mov .frac r0 fix .fix ; erste Stützstelle mov .fix' .fix inc .fix' ; zweite Stützstelle mov .fix'' .fix' inc .fix'' ; dritte Stützstelle mov .fix- .fix dec .fix- ; nullte Stützstelle frac .frac ; Nachkommastellen ; ; Tabellenwerte holen ; get .x- .TA .fix- ; Tafelwert -1 get .x0 .TA .fix ; Tafelwert 0 get .x1 .TA .fix' ; Tafelwert 1 get .x2 .TA .fix'' ; Tafelwert 2 ; ; Differentiale berechnen ; mov .d0 .x1 sub .d0 .x- div .d0 2 ; Ableitung an der Stelle 0 mov .d1 .x2 sub .d1 .x0 div .d1 2 ; Ableitung an der Stelle 1 ; ; Koeffizienten berechnen ; mov .A .x0 ; Siehe http://mathworld.wolfram.com/CubicSpline.html mov .B .d0 mov .C .x1 sub .C .x0 mul .C 3 sub .C .d0 sub .C .d0 sub .C .d1 mov .D .x0 sub .D .x1 mul .D 2 add .D .d0 add .D .d1 ; ; Polynom ; mov r3 1 mov r1 .A ; mul r3 .frac mov r2 .B mul r2 r3 add r1 r2 ; mul r3 .frac mov r2 .C mul r2 r3 add r1 r2 ; mul r3 .frac mov r2 .D mul r2 r3 add r1 r2 ; ; Ende Unterprogramm $$tab_int_xspline ; put .TA -1 r7 ; Feldpointer wiederherstellen! jump .return ; --------------------------------------------------------------------------------------------------------------- _end