Daten in einer Zeichnung mit VBA suchen und auswerten, Teil 6 – einfache komplexe Elemente auswerten


Neben den Einzelelementen wie Linien, Kreise, Texte usw., die wir in den vorigen Teilen untersucht haben, können auch komplexere Strukturen vorhanden sein, für die wir weitere Funktionen benötigen, um an die Detailinformation zu gelangen.

Beginnen wollen wir einmal mit Textknoten. Textknoten bilden ein interessante Möglichkeit Daten in einer Zeichnung zu platzieren, denn durch die Textknotennummer kann gezielt auf Text ohne Kenntnis der genauen Position der Textknoten zugegriffen werden. Textknoten selber haben Texte als Inhalt, wobei Textknoten auch leer sein können, oder aus eine Textzeile oder mehreren bestehen.
Eine wesentliche Funktion beim Zugriff auf die Texte eines Knotens bitet uns die Methode .GetSubElements.
Dies liefert uns eine Auswahl an Elementen, die genauso aufgebaut sind wie die, die wir bereits bereits kennengelernt haben bei der Erstellung von Auswahlgruppen mit dem ElementEnumerator.

Also bei der Auswertung von Elementen können wir jederzeit auf komplexe Elemente stossen, die wir wiederum in einzelne Elemente zerlegen können usw.. Dies werden wir im nächsten Teil bei der Auswertung von Gruppen oder Zellen noch deutlicher sehen, es kommt dann eine beliebige Verschachtelungstiefe dazu.

Bei den Textknoten haben wir keine weitere Verschachtelung, d.h. ein Textknoten besteht aus einer Anzahl 0 bis n Texten. 

Als Grundlage für die Auswertung von Textknoten dient das vorige Beispiel zum Auswerten von Texten, jedoch kommt aussen herum noch eine weitere While Schleife, die die Textknoten zerlegt.
Eine einfache Routine zum Auswerten von Textknoten könnte so aussehen, die Ausgabe in Datei übernehme ich wieder aus dem vorigen Beispiel:

Sub elementinfo()
Dim ele As Element
Dim ee As ElementEnumerator
Dim eeSub As ElementEnumerator
Dim startpunkt, endpunkt As Point3d
Dim kopfZeile, Zeile As String
Dim datei As String
If ActiveWorkspace.IsConfigurationVariableDefined("MeineAusgabeDatei") Then
datei = ActiveWorkspace.ConfigurationVariableValue("MeineAusgabeDatei")
Else
MsgBox "Die Variable MeineAusgabeDatei ist nicht definiert, Verarbeitung abgebrochen", vbCritical
Exit Sub
End If
Open datei For Append As #1
Set ee = ActiveModelReference.GraphicalElementCache.Scan()
Do While ee.MoveNext
If ee.Current.IsTextNodeElement Then
Set eeSub = ee.Current.AsTextNodeElement.GetSubElements
Do While eeSub.MoveNext
Set ele = eeSub.Current
Zeile = "Textknoten#: " & ee.Current.AsTextNodeElement.NodeNumber & ";"
If ele.Type = msdElementTypeText Then
Zeile = Zeile & ele.Type & ";Ursprung (xy) = " & ele.AsTextElement.Origin.X & "," & ele.AsTextElement.Origin.Y & ";"
Zeile = Zeile & "Hoehe: " & ele.AsTextElement.TextStyle.Height & ";"
Zeile = Zeile & "Text: " & ele.AsTextElement.Text
Print #1, Zeile
End If
Loop
End If
Loop
Close #1
End Sub

Die Textausgabe ist wie vorher, es ist nur zusätzlich am Anfang die Knotennummer des Textknotens hinzu gekommen.

Ich habe über den Befehl Text platzieren einen zweizeiligen Text 3x plaztziert. In der Ausgabe ist zu sehen, dass die Textknoten dabei automatisch durchnummeriert werden. Sobald ein neuer Textknoten platziert wird, bekommt dieser die nächst höhere verfügbare Knotennummer

Die  Auswertung vieler Zeichnungen hat gezeigt, dass es meistens notwendig ist, bei der Auswertung von Texten in Zeichnungen immer davon auszugehen, dass sowohl Texte als auch Textknoten vorhanden sein können. Textknoten können schon ungewollt auftreten, wenn bei der Eingabe des Textes noch ein Return mitgegeben wird, so dass der vermeintlich platzierte Text eigentlich ein Textknoten mit 2 Textzeilen besteht, wobei die zweite Zeile leer ist, optisch macht dies in der Zeichnung keinen Unterschied. 

Die Methode .GetSubElements haben wir hier als ein wichtiges Mittel zum Extrahieren verschachtelter Datenstrukturen kennen gelernt, beginnend bei der Auswertung vonTextknoten, dies geht weiter in beliebig verschachtelten Strukturen wie Gruppen, Zellen oder Pseudozellen.

Bevor wir dies weiter vertiefen, zunächst ein Blick auf andere komplexe Datenstrukturen, für die es direkte Zugriffsmöglichkeiten gibt.
Dazu habe ich einmal folgende Elemente gezeichnet: eine rote Linie (Typ 3), einen blauen Linestring (Typ 4)  und ein grünes Shape (Typ 6):

Welche Unterschiede oder Gemeinsamkeiten haben diese Elemente und wie kann ich die Geometriedaten, also die Eckpunkte dieser Elemente auslesen.
Vergelichbar mit der vorher kennengelernten Methode .GetSubElements für ganze Elemente gibt es bei diesen Datenstrukturen den Befehl .GetVertices zum Ausleesen der Endpunkte, Stützpunkte oder wie man allgemein sagt Vertices.
Die Linie ist nur ein Sonderfall des Linestrings, und zwar hat ein Linestring viele Vertices und eine Linie genau 2.
Und ein Shape ist auch nur ein Linestring, jedoch mit der Besonderheit, dass dass das erste und letzte Vertex dieselben Koordinaten haben und damit den Linestring schliessen.

Um die Vertices auszulesen, definiere ich ein Array mit Punkten:

Dim l() As Point3d

Mit der Abfrage:

If ee.Current.IsLineElement Then ....

kann ich sowohl die Linie als auch den Linestring identifizieren. Damit ich auch das Shape identifizieren kann, füge ich eine weitere Option ein:

    If ee.Current.IsLineElement Or ee.Current.IsShapeElement Then ...

Die folgende Auswertung soll darin bestehen, die Vertices der identifitzierten Elemente in eine Datei zu schreiben.
Da jedoch die Anzahl der Vertices pro Element vorher unklar ist, verwende ich für die Ausgabe eine Zeile pro Vertex.
Die Auswertung könnte also etwa so aussehen:

Sub elementinfo()
Dim ele As Element
Dim ee As ElementEnumerator
Dim startpunkt, endpunkt As Point3d
Dim kopfZeile, Zeile As String
Dim l() As Point3d
Dim datei As String
If ActiveWorkspace.IsConfigurationVariableDefined("MeineAusgabeDatei") Then
datei = ActiveWorkspace.ConfigurationVariableValue("MeineAusgabeDatei")
Else
MsgBox "Die Variable MeineAusgabeDatei ist nicht definiert, Verarbeitung abgebrochen", vbCritical
Exit Sub
End If
Open datei For Append As #1
Set ee = ActiveModelReference.GraphicalElementCache.Scan()
Do While ee.MoveNext
If ee.Current.IsLineElement Or ee.Current.IsShapeElement Then
l = ee.Current.AsVertexList.GetVertices
Zeile = "Typ: " & ee.Current.Type & " mit " & UBound(l) - LBound(l) + 1 & " Vertices"
Print #1, Zeile
For i = LBound(l) To UBound(l)
Zeile = "Vertex # " & i + 1 & "(xyz);"
Zeile = Zeile & l(i).X & ";" & l(i).Y & ";" & l(i).Z
Print #1, Zeile
Next
End If
Loop
Close #1
End Sub

Mein Beispiel mit den 3 verschiedenen Elementen hat folgende Ausgabe generiert:

Anhand der Koordinaten kann man auch bei dem letzten Element sehen, dass es sich um ein geschlossenes Element handelt, also im Prinzip ist Typ 6 auch nur ein Spezialfall vom Typ 4, ebenso wie dies bei Typ 3 der Fall ist.

Im nächsten Teil betrachten wir komplexe Strukturen wie  Zellen.