Modifizieren von sehr großen Koordinatendateien

Direkt zum Seiteninhalt

Modifizieren von sehr großen Koordinatendateien

LISP-Programmierung für AutoCAD und BricsCAD
Veröffentlicht von Jörn Bosse in LISP-Codes · 29 Januar 2009
Aus einer Koordinatendatei sollen alle xy-Werte um den Vektor 3500000,5900000 verbessert werden.
  • Original: 66351.948013 45680.018997 13.291000
  • Verbessert: 3566351.948013 5945680.018997 13.291000

Als weiteres Problem kommt hinzu, daß es sich um sehr große Dateien handelt (bis zu 12 Millionen Zeilen). Zu Beginn nehme ich aber eine kleine Koordinatendatei mit 10 Zeilen, um die Funktionalitäten der grundlegenden Funktionen zu testen.
66351.948013 45680.018997 13.291000
66362.434006 45682.344986 13.271988
66347.912003 45623.077011 13.060013
66362.258011 45599.085007 13.082993
66362.336990 45599.043991 13.081985
66359.931992 45599.594009 13.065994
66362.173996 45599.115005 13.081009
66362.095993 45599.155991 13.081985
66363.448990 45597.930008 13.084000
66363.268997 45597.977005 13.081985

Mit folgender Funktion werden die Koordinaten in eine Liste eingelesen:
(defun JB_Koord:Read (dateiname / zeile datei zeilen_liste)
(if(setq datei (open dateiname "r"))
(progn
(while (setq zeile (read-line datei))
(setq zeilen_liste (cons zeile zeilen_liste)))
 (close datei)))
(reverse zeilen_liste))

Für jede Koordinatenzeile existiert jetzt ein Gesamtstring, z.B.
„66363.268997 45597.977005 13.081985“

Es müssen die einzelnen Werte mit der Funktion READ aus dem String in eine Liste gebracht werden, dazu verwende ich ein MAPCAR-Schleife.
(defun JB_Koord:String:Read (zeilen_liste / A)
(mapcar ‘(lambda(A)
(read(strcat “(” A “)”)))zeilen_liste))

Daraus ergibt sich ein Liste mit REAL-Zahlen, z.B.
(66363.268997 45597.977005 13.081985)
Auf den X-Wert soll jetzt 3500000 und auf den Y-Wert 5900000 addiert werden, wieder in einer MAPCAR-Schleife:
(defun JB_Koord:Real:Verb (liste / A)
(mapcar ‘(lambda(A)
(mapcar ‘+ A’(3500000.0 5900000.0 0.0)))liste))

Daraus ergibt sich ein Liste mit REAL-Zahlen, z.B.
(3566363.268997 5945597.977005 13.081985)
Jetzt müssen die neuen Daten wieder in die Koordinatendatei geschrieben werden:
(defun JB_Koord:Write (dateiname liste / )
(setq datei (open dateiname “w”))
(setvar “DIMZIN” 3);;;Damit nachführenden Nullen geschrieben werden
(mapcar ‘(lambda(A)
(write-line
(strcat
(rtos (car A)2 6)” “
(rtos (cadr A) 2 6)” “
(rtos (caddr A) 2 6))datei))liste)
(close datei))

Das war es schon, in einer aufrufenden Funktion zusammen geschrieben würde es folgendermaßen aussehen:
(defun c:JB_Koord ( / dateiname)
(setq dateiname “c:\temp\test.kor”)
(JB_Koord:Write dateiname
(JB_Koord:Real:Verb
(JB_Koord:String:Read
(JB_Koord:Read dateiname)))))

Als Ergebnis würde die Koordinatendatei wie folgt aussehen:
3566351.948013 5945680.018997 13.291000
3566362.434006 5945682.344986 13.271988
3566347.912003 5945623.077011 13.060013
3566362.258011 5945599.085007 13.082993
3566362.336990 5945599.043991 13.081985
3566359.931992 5945599.594009 13.065994
3566362.173996 5945599.115005 13.081009
3566362.095993 5945599.155991 13.081985
3566363.448990 5945597.930008 13.084000
3566363.268997 5945597.977005 13.081985

(Die folgenden Zeitangaben beziehen sich auf folgenden Rechner: CIntel® Core™2 Duo CPU, T7700 @ 2.40GHz, 2.39GHz, 2.00 GB RAM)

Soweit so gut, keine Probleme, was passiert jetzt aber wenn wir eine Koordinatendatei mit 12 Millionen Datenzeilen verbessern wollen? Die Funktion „JB_Koord:Read“ schafft es noch, es dauert ca. 1.5 Minuten, dann sind die Zeilenstrings in einer Liste, fertig für die Weiterverarbeitung.

Der Blick in den Taskmanager zeigt, die Auslagerungsdatei hat um ca. 1GB zugenommen, bei modernen Rechnern aber noch kein Problem.

Sobald aber die Funktion „JB_Koord:String:Read“ aufgerufen wird ist spätestens bei der 4.5-millionsten Datenzeile Schluß. AutoCAD lagert scheinbar alle in der MAPCAR befindlichen Daten aus, im Taskmanager hat die Auslagerungsdatei bereits eine Größe von ca. 2.5GB erreicht und der Rechner ist am dampfen. Sicherlich kann man über die Windows-Systemsteuerung die Größe der Auslagerungsdatei noch optimieren, aber so einige Versuche haben gezeigt, dass es maximal ca. 400.000 Datenzeilen mehr bringt, die in der MAPCAR-Schleife verarbeitet werden können.

Also, jetzt suche ich die Lösung nicht in der Windows-Umgebung, sondern ich ändere den LISP-Code so, dass nicht alle 12 Millionen Datenzeilen auf einmal verarbeitet werden, sondern in Häppchen von jeweils 2 Millionen Datenzeilen.

Folgende Grundüberlegung: Eine MAPCAR-Schleife läuft immer eine gesamte Liste durch, daher werde ich 2 WHILE-Schleifen verwenden. Die innere WHILE-Schleife läuft solange, bis der 2-millionste Durchlauf erreicht ist oder die Zeilen_Liste leer ist, gezählt wird mit der Variablen J. Die äußere While-Schleife wird solange durchlaufen bis die Zeilen_Liste leer ist, gezählt wird mit der Variablen I. Beim Schreiben der Datei wird das Argument „w“ beim ersten Durchlauf, bei allen folgenden Durchläufen das Argument „a“ für Anhängen (append) an vorhandene Datei verwendet.

(defun JB_Koord:WriteWithWhile (dateiname /
A DATEI I J K L WRITE_LISTE ZEILEN_LISTE)
(setq zeilen_liste (JB_Koord:Read dateiname)
j 1 ;;;Zähler 1. WHILE-Schleife
i 1.0 ;;;Zähler 2. WHILE-Schleife
)
(princ
(strcat
“: “
(menucmd “M=$(edtime,$(getvar,date),DD.MO.YYYY HH:MM:SS)”)))
(setvar “DIMZIN” 3);;;Damit nachführenden Nullen geschrieben werden
(while zeilen_liste
(while (and (<= (/ j i)2000000.0) zeilen_liste)
(setq write_liste (cons
(read (strcat”(” (car zeilen_liste)”)”))
write_liste)
j (+ j 1)
zeilen_liste (cdr zeilen_liste))
)
(princ
(strcat
“”
(itoa j)
” verarbeitet: “
(menucmd “M=$(edtime,$(getvar,date),DD.MO.YYYY HH:MM:SS)”)))
(setq datei (open dateiname (if (= i 1)”w” “a”))
write_liste (reverse write_liste))
(mapcar ‘(lambda(A)
(write-line
(strcat (rtos(+(car A)3500000.0)2 6)” “
(rtos(+(cadr A)5900000.0)2 6)” “
(rtos(caddr A)2 6))datei)
)write_liste)
(princ
(strcat
“”
(itoa j)
” geschrieben: “
(menucmd “M=$(edtime,$(getvar,date),DD.MO.YYYY HH:MM:SS)”)))
(setq i (+ i 1.0)
write_liste nil)))
Die aufrufende Funktion könnte folgendermaßen aussehen:
(defun c:JB_Koord1 ( / dateiname)
(princ
(strcat
“: “
(menucmd “M=$(edtime,$(getvar,date),DD.MO.YYYY HH:MM:SS)”)))
(setq dateiname “c:\temp\test.kor”)
(JB_Koord:WriteWithWhile dateiname)
(princ
(strcat
“: “
(menucmd “M=$(edtime,$(getvar,date),DD.MO.YYYY HH:MM:SS)”)))
)

Anmerkung:
Bei der Verarbeitung von so großen Dateien ist es sinnvoll, sich über PRINC-Anweisungen den Fortschritt anzeigen zu lassen. Im Beispiel habe ich die Zeiten ausgegeben, wenn ein Arbeitsschritt abgearbeitet worden ist.

Man könnte ja auch einen Zähler einbauen, so dass der Bearbeiter sofort sieht, die wievielte Zeile gerade aktuell geschrieben oder gespeichert wird, z.B.
(princ (strcat “Datei schreiben: ” ” (“(itoa (setq m (+ m 1)))”/” (itoa k)”)”))

Aber Achtung:
bei so großen Datenmengen ist ein solcher Zähler wirklich hinderlich. Er wirkt sich nicht nur sehr negativ auf die Performance aus, in diesem Fall, bei einer Beispiel-Datei mit über 12-Millionen Zeilen, hängt sich AutoCAD auf und muss über den Task-Manager beendet werden.
Folgende Ergebnisse sind bei einer Datei mit 12.266.233 Zeilen herausgekommen:

Start: 29.01.2009 14:56:06
Eingelesen: 29.01.2009 14:57:02
2000001 verarbeitet: 29.01.2009 14:57:41
2000001 geschrieben: 29.01.2009 14:59:18
4000001 verarbeitet: 29.01.2009 14:59:51
4000001 geschrieben: 29.01.2009 15:01:26
6000001 verarbeitet: 29.01.2009 15:02:02
6000001 geschrieben: 29.01.2009 15:03:31
8000001 verarbeitet: 29.01.2009 15:04:11
8000001 geschrieben: 29.01.2009 15:05:31
10000001 verarbeitet: 29.01.2009 15:06:07
10000001 geschrieben: 29.01.2009 15:07:25
12000001 verarbeitet: 29.01.2009 15:07:58
12000001 geschrieben: 29.01.2009 15:09:12
12266233 verarbeitet: 29.01.2009 15:09:17
12266233 geschrieben: 29.01.2009 15:09:25
Fertigstellung: 29.01.2009 15:09:25″
Zeit ca. 13 Minuten
Computer:
Intel® Core™2 Duo CPU
T7700 @ 2.40GHz
2.39GHz, 2.00 GB RAM

Start: 29.01.2009 15:49:09
Eingelesen: 29.01.2009 15:55:52
2000001 verarbeitet: 29.01.2009 16:03:17
2000001 geschrieben: 29.01.2009 16:10:26
4000001 verarbeitet: 29.01.2009 16:16:38
4000001 geschrieben: 29.01.2009 16:23:39
6000001 verarbeitet: 29.01.2009 16:29:59
6000001 geschrieben: 29.01.2009 16:37:05
8000001 verarbeitet: 29.01.2009 16:42:40
8000001 geschrieben: 29.01.2009 16:49:09
10000001 verarbeitet: 29.01.2009 16:54:01
10000001 geschrieben: 29.01.2009 17:00:05
12000001 verarbeitet: 29.01.2009 17:03:38
12000001 geschrieben: 29.01.2009 17:08:38
12266233 verarbeitet: 29.01.2009 17:09:01
12266233 geschrieben: 29.01.2009 17:09:36
Fertigstellung: 29.01.2009 17:09:36
Zeit: ca. 1 Stunde und 20 Minuten
Computer:
AMD Athlon™ XP 3000+
600 MHz, 1.25 GB RAM




0
Rezensionen

Zurück zum Seiteninhalt