Iteration über Objekte
Aus CINEMA 4D Wiki
Inhaltsverzeichnis |
Einführung
Es kommt häufig vor, dass man über alle Objekte in einer Szene iterieren muss, oder über alle Tags eines Objekts. Dieser Artikel zeigt ein Beispiel, wie eine solche Schleife zu realisieren wäre.
Iteration über Objekte
Hier wird über sämtliche Objekte der obersten Hierarchie-Ebene in der Szene iteriert. Das Name jedes Objekts wird in der Konsole ausgegeben.
Beispielcode C++:
void IterateObjects(BaseObject *op)
{
// Schleife durchlaufen, solange op ein gültiges Objekt ist
while (op)
{
// Als Beispiel den Namen des Objekts in der Konsole ausgeben
GePrint(op->GetName());
// Nächstes Objekt
op = op->GetNext();
}
}
Aufgerufen wird die Funktion z.B. so:
BaseDocument *doc = GetActiveDocument(); BaseObject *op = doc->GetFirstObject(); IterateObjects(op);
Rekursive Iteration über Objekte
In diesem Beispiel ruft die Funktion sich selbst erneut auf, um Unterobjekte (und deren Unterobjekte) ebenfalls zu iterieren. Als Ergebnis erscheinen die Namen sämtlicher Objekte in der Szene in der Konsole.
Beispielcode C++:
void IterateObjects(BaseObject *op)
{
// Schleife durchlaufen, solange op ein gültiges Objekt ist
while (op)
{
// Als Beispiel den Namen des Objekts in der Konsole ausgeben
GePrint(op->GetName());
// Wenn mindestens ein Unterobjekt existiert, Rekursion starten
if (op->GetDown()) IterateObjects(op->GetDown());
// Nächstes Objekt
op = op->GetNext();
}
}
Rekursive Iteration über Objekte und deren Tags
Hier wird die Funktion noch erweitert, um auch die Tags sämtlicher Objekte zu iterieren, und deren Namen in der Konsole auszugeben.
Da Tags keine Unter-Tags besitzen können, ist für die Iteration über die Tags eines Objekts keine Rekursion erforderlich.
Beispielcode C++:
void IterateObjectsAndTags(BaseObject *op)
{
BaseTag *tag = NULL;
// Schleife durchlaufen, solange op ein gültiges Objekt ist
while (op)
{
// Als Beispiel den Namen des Objekts in der Konsole ausgeben
GePrint(op->GetName());
// Erstes Tag des Objekts ermitteln
tag = op->GetFirstTag();
// Schleife durchlaufen, solange tag ein gültiges Tag ist
while (tag)
{
// Namen des Tags in der Konsole ausgeben
GePrint("-> " + tag->GetName());
// Nächstes Tag
tag = tag->GetNext();
}
// Wenn mindestens ein Unterobjekt existiert, Rekursion starten
if (op->GetDown()) IterateObjects(op->GetDown());
// Nächstes Objekt
op = op->GetNext();
}
}
Objekte und Tags zählen
Möchte man nun wissen, wieviele Objekte und Tags im Zuge der Rekursion insgesamt durchlaufen wurden, steht man als unerfahrener Entwickler zunächst vor der Frage: Wie zähle ich sowas? Eine Variable innerhalb der Funktion macht keinen Sinn, denn die würde für jede Rekursions-Ebene neu initialisiert.
Die Lösung ist eine Referenz zu einer Zähler-Variable außerhalb der Rekursion. In diesem Beispiel sogar zwei Variablen, da sowohl Objekte als auch Tags gezählt werden sollen.
Beispielcode C++:
void IterateObjectsAndTags(BaseObject *op, LONG &ObjCounter, LONG &TagCounter)
{
BaseTag *tag = NULL;
// Schleife durchlaufen, solange op ein gültiges Objekt ist
while (op)
{
// Als Beispiel den Namen des Objekts in der Konsole ausgeben
GePrint(op->GetName());
// Erstes Tag des Objekts ermitteln
tag = op->GetFirstTag();
// Schleife durchlaufen, solange tag ein gültiges Tag ist
while (tag)
{
// Namen des Tags in der Konsole ausgeben
GePrint("-> " + tag->GetName());
// Nächstes Tag
tag = tag->GetNext();
// Tagzähler erhöhen
TagCounter++;
}
// Wenn mindestens ein Unterobjekt existiert, Rekursion starten
// Dabei wird die Referenz auf die Zähler-Variablen mit übergeben
if (op->GetDown()) IterateObjects(op->GetDown(), ObjCounter, TagCounter);
// Nächstes Objekt
op = op->GetNext();
// Objektzähler erhöhen
ObjCounter++;
}
}
Aufruf der Funktion:
BaseDocument *doc = GetActiveDocument();
BaseObject *op = doc->GetFirstObject();
LONG ObjCounter = 0;
LONG TagCounter = 0;
IterateObjects(op, ObjCounter, TagCounter);
GePrint("Es gibt insgesamt " + LongToString(ObjCounter) + " Objekte und " + LongToString(TagCounter) + " Tags in der Szene.");
Jetzt werden in der Konsole zuerst alle Objektnamen und die Namen der zugehörigen Tags ausgegeben, und am Ende die Gesamtanzahl der Objekte und Tags.
Objekte bestimmer Art iterieren
Manchmal möchte man vielleicht gar nicht alle Objekte in der Szene bearbeiten, sondern nur Objekte bestimmter Art, z.B. Null-Objekte. In dem Fall muss einfach der Typ jedes Objekts ermittelt und mit dem gesuchten Typ verglichen werden. Der folgende Code iteriert wieder sämtliche Objekte in der Szene, kümmert sich jedoch nur um Null-Objekte. Wird ein Null-Objekt gefunden, erscheint dessen Name in der Konsole, und der Objektzähler wird erhöht.
Beispielcode C++:
void IterateObjects(BaseObject *op, LONG ObjType, LONG &ObjCounter)
{
// Schleife durchlaufen, solange op ein gültiges Objekt ist
while (op)
{
if (op->GetType() == ObjType)
{
// Als Beispiel den Namen des Objekts in der Konsole ausgeben
GePrint(op->GetName());
// Objektzähler erhöhen
ObjCounter++;
}
// Wenn mindestens ein Unterobjekt existiert, Rekursion starten
if (op->GetDown()) IterateObjects(op->GetDown(), ObjTyp, ObjCounter);
// Nächstes Objekt
op = op->GetNext();
}
}
Der Aufruf könnte folgendermaßen aussehen:
BaseDocument *doc = GetActiveDocument();
BaseObject *op = doc->GetFirstObject();
LONG ObjCounter = 0;
IterateObjects(op, Onull, ObjCounter); // Anstelle von "Onull" kann auch die ID jedes beliebigen Objekts verwendet werden
GePrint("Es gibt insgesamt " + LongToString(ObjCounter) + " Objekte vom Typ " + LongToString(ObjType) + " in der Szene.");
