Ein paar Worte vorabHome   Letzte MeldungenNews   Index der Kapitel und der besprochenen FunktionenIndex   Wer ich bin, warum ich diese Seiten mache, KontaktImpressum   Ich freue mich über jeden Eintrag im Gästebuch!Gästebuch   Einige Links zu anderen AutoLisp-SeitenLinks   Copyrights und DisclaimerRechts
Hier können die kompletten Seiten als ZIP-File heruntergeladen werden!

Funktionen für komfortables Arbeiten mit Zeichenketten String-Tango
Noch mehr Funktionen für komfortableres Arbeiten mit Zeichenketten Kettenhunde
strtok zerlegt Zeichenketten anhand eines Trennzeichens Tock-Tock
Arbeiten mit Datum und Zeit in AutoLisp Zeitlos...
Dotted pairs - wie man den Programmabbruch verhindert Gepunktet?
Neue Funktionen für die Listenbearbeitung Strukturtapete
Weitere neue Funktionen für die Listenbearbeitung Listen to me!
Lambda expressions - dasSalz in der Suppe Lambada
Lambda expressions anhand eines Praxisbeispiels Unter der Erde
Where und whereever erleichtern den Umgang mit Listen Quo vadis?
Rekursion - Funktionen, die sich selbst aufrufen Katzenschwanz
Ein äusserst wichtiger Prototyp für Funktionen Nix passiert
Wo das lineare mapcar am Ende ist Tiefer rein!
Über Effekte und Neben(Seiten-)Effekte von Funktionen Seitensprünge
Die Namensräume (Sichtbarkeit) von Variablen Raumwunder
Let dient zur Schaffung kleinerer Namensräume Lass mal...
Sukzessive Verarbeitung von Listenresten mit mapcdr Der Bruder
Was in AutoLisp einfach nicht machbar ist (Teil I) Beschränkt
Was in AutoLisp einfach nicht machbar ist (Teil II) Limited Edition
Nicht mit Effekten arbeiten, sondern direkter Daten-Änderung Destruktiv
Sequenzielles vs. paralleles Abarbeiten von Argumenten Parallelwelten
Über den Umgang mit Funktionsschablonen Erwachet!
Ein Praxiskapitel über Auswahlsätze, Attribute, wcmatch und mehr Durch die Brust
Die Farben des AutoCAD Color Index und ihre RGB-Werte Alles so schön
Hier laufen die Fäden zusammen: Viele Konzepte vereint Lapsus Lispuli
Ein Spiel als Beispiel für lernfähige Funktionen Zug um Zug
Errorhandling in AutoLisp - Teil 1 Alles valsch!
Errorhandling in AutoLisp - Teil 2 Und foll Feler!


Zum Einsteiger-Tutorial

Zu den ActiveX-Seiten

Meine Private HP mit Fotos, Gedichten, Musik und Postkartenversand

Mein Online-Lexikon der Fotografie

Mein völlig abgedrehtes Reisebüro










Manche Dinge beim Programmieren in AutoCAD mit AutoLisp können über Kurz oder Lang doch recht langweilig werden. Dazu gehört z.B. der Zugriff auf Gruppencodes in Elementdaten. Nicht nur, dass man die DXF-Codes im Kopf haben muss! Es ist auch die immerwiederkehrende Anwendung der Kombination (cdr(assoc dxfcode ...)), die uns langweilig wird.

Da liegt also Automatisierungsbedarf vor. Funktionen zu schreiben, die den Code ein bisschen straffen, ist kein Kunststück. Der Code ist alles andere als komplex, wir brauchen nur eine Zeile. Die nachfolgende Funktion extrahiert z.B. den Layer aus einer Datenliste:
(defun get-layer(data / )
  (cdr(assoc 8 data))
)
                  
Ein wenig komfortabler wird das Ganze, wenn wir das zu übergebende Argument etwas 'aufweichen' - schliesslich brauchen wir so eine Funktion manchmal für einen Elementnamen, manchmal für eine Datenliste, die wir schon haben. Wir fügen also noch eine Zeile ein:
(defun get-layer(data / )
  (if(=(type data)'ENAME)(setq data(entget data)))
  (cdr(assoc 8 data))
)
                  
Jetzt können wir die Funktion so oder so aufrufen, das macht sie ungleich praktischer in der Anwendung:
(get-layer(car(entsel)))  => "0"

(get-layer(entget(entlast))) => "0"
                  
Schön und gut, jetzt haben wir eine Funktion, die uns den Layer extrahiert. Es bedarf wenig Fantasie, um zu erkennen, dass weitere Funktionen für die anderen Gruppencodes fast genauso aussehen würden - lediglich der Name und der Gruppencode wären anders. Ein Muster für diese Funktions-Familie könnte so aussehen:
(defun <funktionsname>(data / )
  (if(=(type data)'ENAME)(setq data(entget data)))
  (cdr(assoc <gruppencode> data))
)
                  
Jetzt wäre es ganz einfach, z.B. mit einem Texteditor die spitzen Klammern durch die entsprechenden Inhalte zu ersetzen. Aber das kriegen wir doch auch mit Lisp hin! Was wir brauchen, ist eine Funktion, die diese Schablone benutzt und ausserdem eine Liste mit den Namen sowie Gruppencodes als Argument erhält, und die dann unsere gewünschten Funktionen sozusagen in Nullzeit produziert.

Die spitzen Klammern sind übrigens in Symbolnamen in AutoLisp durchaus erlaubt. Irgendeine Form von besonderer Bedeutung habe sie da nicht. Wir verwenden sie hier einzig und allein der Optik wegen!

Die Sache ist ganz einfach zu realisieren, wenn wir auf die Funktion (mapin ...) zurückgreifen, der hier ein eigenes Kapitel gewidmet ist. Wer dieses Kapitel noch nicht kennt, sollte dies wohl zuerst einmal nachholen. mapin durchsucht jedenfalls beliebig tief verschachtelte Listen und wendet einen lambda-ausdruck auf jedes Atom in der Liste an. Das ist genau das, was wir brauchen, um die Platzhalter durch Inhalte zu ersetzen. So sieht unser Funktionsgenerator für eine Funktion zunächst aus:
(defun mk-dxf-ass-func(name gruppencode / )
  (eval
    (mapin
     '(lambda(ein-atom / )
        (cond
          ( (= ein-atom '<funktionsname>)
            (read(strcat "get-" name))
          )
          ( (= ein-atom '<gruppencode>)gruppencode)
          (1 ein-atom)
        )
      )
     '(defun <funktionsname>(data / )
        (if(=(type data)'ENAME)
          (setq data(entget data))
        )
        (cdr(assoc <gruppencode> data))
      )
    )
  )
)
                  
Wenn wir ihn mit den entsprechenden Argumenten aufrufen, produziert dieser Generator die entsprechenden Funktionen:
(mk-dxf-ass-func "layer" 8) => (get-layer)
(get-layer(entlast)) => "0"

(mapcar
 '(lambda(defpaar / )
    (apply 'mk-dxf-ass-func defpaar)
  )
 '( (6  . "Linientyp")
    (8  . "Layer")
    (62 . "Farbe")
    (48 . "LTFaktor")
    (60 . "Unsichtbar")
    (67 . "Bereich")
  )
)
                  
Die letzte Anwendung von mapcar produziert gleich Funktionen in Serie, und wir können alle diese Funktionen sofort benutzen.

Jetzt haben wir also die Funktionen zum Auslesen von Gruppencodes im Griff. Manchmal brauchen wir aber auch solche, die mit (entmod) einen bestimmten Guppencode verändern - ein roter Kreis soll z.B. grün werden! Wir gehen jetzt noch einen Schritt weiter und schreiben eine ganz allgemeine Funktion, die eine Schablone sowie die einzusetzenden Inhalte als Argumente erhält:
(defun subst-in-template(template val-pairs / )
  (mapin
    '(lambda(atm / )
      (if(assoc atm val-pairs)
        (cdr(assoc atm val-pairs))
        atm
      )
    )
    template
  )
)
                  
Die Arbeitsweise ist hier anders: Diese Funktion ersetzt nur in beliebigen Schablonen und kann eine generierte neue Funktionsdefinition zurückgeben, aber auch eine Datenliste! Evaluiert wird nichts. Unser Layer-Beispiel:
(subst-in-template
 '(defun <funktionsname>(data / )
    (if(=(type data)'ENAME)(setq data(entget data)))
    (cdr(assoc <gruppencode> data))
  )
 '( (<funktionsname> . get-layer)
    (<gruppencode> . 8)
  )
)

    => (DEFUN GET-LAYER (DATA /) (IF (= (TYPE DATA)
       (QUOTE ENAME)) (SETQ DATA (ENTGET DATA)))
       (CDR (ASSOC 8 DATA)))
                  
In diesem Beispiel wird also nur der Code für get-layer geliefert, wollen wir die Funktion benutzen, müssen wir noch ein (eval ...) drumherumsetzen. Die Funktion subst-in-template ist aber ungleich flexibler als unsere bisherigen Ansätze. Für die gewünschten Funktionen zum Ändern mit (entmod ...) setzen wir einfach eine andere Schablone ein, die wir im nächsten Beispiel zur Abwechslung einmal vorab extern definieren:
(setq set-template
 '(defun <funktionsname>(data / )
    (if(=(type data)'ENAME)(setq data(entget data)))
    (entmod
      (if(assoc <gruppencode> data)
        (subst
          (cons <gruppencode> val)
          (assoc <gruppencode> data)
          data
        )
        (append
          (list(cons <gruppencode> val))
          data
        )
      )
    )
  )
)
                  
Nun wenden wir eine eine etwas komplexere lambda-expression an, um in einem Rutsch gleich mehrere entmod-Funktionen zu erzeugen und auch sofort benutzbar zu machen. Ein Hinweis: Der Name mit abschliessendem Ausrufungszeichen soll darauf hinweisen, dass es sich hier um reine Nebeneffekt-Funktionen, also destruktive Funktionen handelt. Zurückgegeben wird das Ergebnis von (entmod ...), das evtl. zur Überprüfung verwendet werden kann.
(defun mk-dxf-set-funcs( / )
  (mapcar
   '(lambda(funcdata / )
      (eval
        (subst-in-template set-template funcdata)
      )
    )
   '( ( (<funktionsname> . set-layer!)
        (<gruppencode> . 8)
      )
      ( (<funktionsname> . set-linientyp!)
        (<gruppencode> . 6)
      )
      ( (<funktionsname> . set-farbe!)
        (<gruppencode> . 62)
      )
    )
  )
)
                  
Wie man sieht, ist es gar nicht so schwer, Funktionen automatisch zu generieren. Durch die Verwendung solcher templates können wir uns in Zukunft einfach eine Menge Code einsparen.