Modifizieren von sehr großen Koordinatendateien - Bosse-engineering Blog - LISP-Programmierung für AutoCAD und BricsCAD

RSS-Feed für Bosse-engineering Blog
Direkt zum Seiteninhalt

Hauptmenü:

Modifizieren von sehr großen Koordinatendateien

LISP-Programmierung für AutoCAD und BricsCAD
Herausgegeben von in LISP-Codes ·

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







Kein Kommentar


letzte Posts
Zurück zum Seiteninhalt | Zurück zum Hauptmenü