Die Funktion
(ssget ...) ist wohl die komplexeste
Funktion überhaupt in AutoLisp. Nicht, dass sie in irgendeiner
Weise schwer zu begreifen wäre - aber sie kann eine Unmenge
verschiedener Argumente erhalten und durch diese bedingt sich
völlig unterschiedlich verhalten. Die Rückgabe ist auf jeden
Fall ein Auswahlsatz - oder nil, wenn gar nichts gewählt
wurde. Dieser kleine Bug wurde schon an anderer Stelle
besprochen.
Wir kennen Aufrufe von
(ssget) bereits, aber ohne
Argumente. In diesem Fall kann der Benutzer Elemente aus der
Zeichnung auswählen, und zwar ohne jede Einschränkung, also
was und wieviel er will.
(ssget) kann aber auch dazu
benutzt werden, die Zeichnung nach bestimmten Elementen zu
durchsuchen, ohne dass der Benutzer irgendwie involviert
wird. Werfen wir einen Blick auf ein Beispiel:
(ssget "X" '((0 . "LINE")))
Der
(ssget)-Aufruf erhält hier zwei Argumente. Das
Zeichen "X" ist ein Code, der mitteilt, dass keine Anfrage
an den Benutzer stattfinden soll, sondern dass die
Zeichnungsdatenbank durchsucht werden soll. Dieser Code hat
absolut nichts mit Lisp zu tun, er gilt nur für
(ssget)!
Und natürlich gibt es nicht nur diesen einen.
Das zweite Argument ist eine Liste mit Unterlisten. In unserem
Beispiel ist allerdings nur eine Unterliste darin enthalten,
und auch hier sehen wir wieder die bereits bekannten Paarungen
aus DXF-Gruppencode und Wert.
Wie Sie bereits vermuten: Dieser Aufrufvon
(ssget)
gibt uns einen Auswahlsatz zurück, der alle in der Zeichnung
vorkommenden Linien enthält. Linien, die Bestandteile von
Blöcken sind, sind aber nicht enthalten - der Zugriff auf
Unterelemente von Blöcken ist noch einmal eine ganze Ecke
komplizierter.
Die Liste mit den Gruppencodes kann mehr als ein Element
haben. Wir fügen noch ein weiteres Paar hinzu:
(ssget "X" '((0 . "LINE")(8 . "0"))
(ssget) sucht uns jetzt alle Entities aus der Zeichnung
heraus, auf die beide Eigenschaften zutreffen: Wir erhalten
einen Auswahlsatz mit allen Linien, die auf Layer 0 liegen.
Natürlich können wir weitere Bedingungen hinzufügen:
(ssget "X" '((0 . "LINE")(8 . "0")(62 . 256))
Jetzt bekommen wir alle Linien auf Layer 0, die die Farbe
Vonlayer haben (dass wir auch hier wieder die Farbe 256
verwenden können, freut uns - schliesslich hat ja das Entity
eigentlich gar keinen Gruppencode 62. Aber das haben wir schon
im Kapitel über
(entget) geklärt). Je mehr Paarungen
wir allerdings als Suchkriterien verwenden, umso mehr müssen
natürlich aufpassen, dass sie widerspruchsfrei bleiben.
Das nächste Beispiel wird zwar von
(ssget) ohne
Beanstandung angenommen, aber wir werden immer nur ein
nil zurückbekommen:
(ssget "X"
'((0 . "LINE")(8 . "0")(62 . 256)(40 . 10.0)
)
Eine Linie hat nun mal keinen Gruppencode 40 -
(ssget)
wird zwar brav vergleichen, aber nie etwas finden!
Ein paar weitere Beispiele:
(ssget "X" '((62 . 1)(67 . 1)))
; Alle roten Entities im Papierbereich
(ssget "X" '((0 . "3DFACE")(70 . 8)))
; Alle 3D-Flächen, bei denen alle 4
; Kanten als unsichtbar markiert sind
(ssget "X" '((0 . "INSERT")(2 . "Schraube")))
; sucht alle Referenzen des Blocks 'Schraube'
Beim letzten der drei Beispiele drängt sich eine Frage
auf: Wie ist es mit der Gross-/Kleinschreibung? Werden
die Inserts auch gefunden, wenn man 'schraube' oder
'SCHRAUBE' oder sogar 'SCHRaubE' schreibt? Entwarnung!
Sie werden auf jeden Fall gefunden. Auch den Entity-Typ
kann man klein schreiben, wenn auch AutoCAD die Entity-Typen
immer in Grossbuchstaben zurückgibt. Und selbst der
Steuercode wird grosszügig interpretiert: Ein kleines
"x" tut's auch und spart obendrein noch Tinte.
Jeder, der eine Suchmaschine vernünftig betätigen kann,
weiss: Wo ein UND ist, da ist auch ein ODER. Dazu hat sich
AutoDESK weitere Rauchzeichen einfallen lassen. Es wird
jetzt aber nicht das "X" durch ein "Y"
ersetzt - nein, ein bisschen komplizierter ist es schon.
Für eine ODER-Verknüpfung müssen wir die Liste um bestimmte
Paarungen erweitern:
(ssget "X"
'( (-4 . "<OR")
(0 . "LINE")
(62 . 2)
(-4 . "OR>")
)
)
Der
(ssget)-Aufruf wird nun schon so lang, dass
er nicht mehr in eine Zeile passt. Was passiert da?
Der Gruppencode -4 ist eigens für die Funktion
(ssget)
reserviert, d.h. dass er zum Einen niemals in einer DXF-Datei
vorkommen kann, und zum Anderen auch niemals in einer
Datenliste, wie sie
(entget) liefert. Es ist nichts
weiter als ein Steuerzeichen für
(ssget).
Die eigentlichen Steuerzeichen sind natürlich die
Zeichenketten, die mit dem Gruppencode -4 verbunden sind.
"<OR" leitet das ODER ein, "OR>" schliesst es ab.
Diese Steuercodes müssen übrigens immer genau ausgeglichen
sein -
(ssget) gibt immer nil zurück, wenn sie es
nicht sind!
Die Bedeutung von ODER sollte klar sein: Hier wird das
herausgefiltert, was ein Kreis ist ODER gelb ODER beides -
das ODER ist kein Entweder-Oder. Wenn wir das exklusive
oder meinen, dann müssen wir die Steuerzeichen "<XOR"
und "XOR>" verwenden. Ferner gibt es dann
noch "<NOT" und "NOT>" sowie
"<AND" und "AND>". Die beiden
letzten umgeben sozusagen immer implizit die Filterliste,
auch wenn sie nicht mitgeschrieben werden.
Es kann vorkommen, dass in einer Zeichnung verschiedene INSERTs
eines Blocks unterschiedliche Attribute haben. Das entsteht,
wenn der Block zwischendurch neu mit anderen Attributen
definiert wird. Nehmen wir mal an, wir haben es mit einem
Block namens 'Befestigung' zu tun, die neueren Inserts haben
Attribute, die älteren haben keine. Wie können wir die älteren
herausfischen?
(ssget "X"
'( (0 . "insert")
(2 . "Befestigung")
(-4 . "<not")
(70 . 1)
(-4 . "not>")
)
)
Gruppencode 70 hat den Wert 1, wenn ein INSERT Attribute hat.
Diese Bedingung muss hier aber negiert werden, da wir ja nach
den INSERTs suchen, die keine haben.
Aber die Sache kann noch komplizierter werden: Es gibt nicht
nur einen Block 'Befestigung', sondern 'Befestigung001' usw.
(es gibt ja soooo viel zu befestigen). Es kommt uns sehr
entgegen, dass
(ssget) mit den Wildcards der Funktion
(wcmatch) arbeitet. Diese gehen allerdings über die
DOS-Wildcards ? und * weit hinaus - ein Blick in die Hilfe
zu
(wcmatch) lohnt sich also.
Für unser Beispiel reicht allerdings erst einmal ein Sternchen:
(ssget "X"
'( (0 . "insert")
(2 . "Befestigung*")
(-4 . "<not")
(70 . 1)
(-4 . "not>")
)
)
Diese Variante filtert uns also alle Blöcke heraus, deren
Name mit 'Befestigung' beginnt. Oft möchte man auch alle
INSERTs überhaupt finden, aber nicht die anonymen, die von
AutoCAD erzeugt werden (und die nur '*137' usw heissen).
Auch hier hilft das eingebaute
(wcmatch) weiter: Das
nächste Beispiel sucht alle Blöcke, die nicht anonym sind,
keine Attribute haben und auf Layer "0" liegen,
jedoch nicht im Papierbereich, un deren Name vier Zeichen
lang ist:
(ssget "X"
'( (0 . "insert")
(-4 . "<not")
(-4 . "<AND")
(2 . "`**")
(70 . 1)
(67 . 0)
(-4 . "AND>")
(-4 . "not>")
(2 . "????")
)
)
Zwischen "<not" und "not>" darf übrigens immer nur
ein Element stehen: Das automatische UND, was wir für die
ganze Liste haben, gilt hier nicht mehr. Deshalb müssen
mehrere negierte Elemente wie im Beispiel wieder mit
"<and" und "and>" zusammengefasst werden. Das
`
vor den beiden Sternen muss so sein: Der erste Stern soll
als Stern interpretiert werden, der zweite als Wildcard
(siehe Hilfe zu
(wcmatch).
Dies sollte erst einmal genügen als Einstieg in
(ssget),
es gibt aber noch viel mehr Optionen. Das Thema wird jedoch
in einem der nächsten Kapitel fortgesetzt. Und noch ein Hinweis:
Bei der Arbeit mit AutoCAD (damit meine ich das Zeichnen, nicht
das Programmieren) hat sich
(ssget) bestens bewährt!
Ein kleiner eingetippter Aufruf kann mühsame Klickerei vermeiden.
Der neue Befehl QSELECT, der im Eigenschaftsfenster eingebaut
ist, aber auch explizit aufgerufen werden kann, hat gegenüber
(ssget) den Nachteil, dass er wesentlich langsamer ist.
Ich hatte einmal mit einer 150MB-Zeichnung zu tun, bei der
QSELECT fast 20 Minuten brauchte, um bestimmte Objekte zu filtern.
Ein
(ssget)-Aufruf über die Kommandozeile erledigte
genau die gleiche Aufgabe in weniger als 10 Sekunden! Ich habe
keine Ahnung, warum das so ist, aber ich habe das schon öfters
beobachtet.
Übungsaufgaben
-
Welche der folgenden Aussagen sind richtig?
-
Bei der Arbeit mit (ssget) können nur Gruppencodes
verwendet werden, die auch in DXF-Dateien vorkommen.
-
Bei der Code-Zeichenkette "X" muss man nicht darauf
achten, ob man "X" oder "x" schreibt
-
Wenn die Filterung mit (ssget) nichts findet, wird ein
leerer Auswahlsatz zurückgegeben.
-
Wenn keine Angaben gemacht werden, gilt in der
(ssget)-Filterliste ein implizites logisches UND
-
Am Ende der Filterliste müssen die logischen Verknüpfungen
nicht mehr geschlossen werden, wenn Eindeutigkeit besteht.
-
Für die logischen Verknüpfungen in der Filterliste
gibt es sechs verschiedene Werte für den Gruppencode
-4.
-
Wenn ich alle gelben und alle grünen Elemente wählen
möchte, genügt die implizite UND-Verknüpfung
-
Filtern Sie mit (ssget):
-
...alle gelben Kreise und alle Bögen (egal welcher Farbe)
-
...alle Blöcke, die auf Layer 0 liegen, deren Name aber
nicht mit einem 'E' beginnt und die nicht anonym sind
-
...alle Bemassungen, die nicht auf einem Layer liegen, dessen
Name mit 'Bem' anfängt
-
Denken Sie sich weitere solche Aufgaben aus, lösen Sie sie, prüfen
Sie sie noch einmal sorgfältig, und dann mailen Sie sie mir, damit
ich sie hier noch reinsetzen kann!
Lösungen