2389x
001659
13. Oktober 2020

Modellübergreifendes Aktualisieren und Angleichen von Strukturdaten mit Hilfe der COM-Schnittstelle

Bei manchen Strukturen ist es nötig, dass diese in verschiedenen Konfigurationen bemessen werden müssen. So kann es sein, dass eine Hebebühne sowohl in der Stellung am Boden, in der Mitte und ausgefahren analysiert werden muss. Da solche Aufgaben das Anlegen mehrere Modelle erfordert, welche aber nahezu identisch sind, ist eine Aktualisierung aller Modelle mit nur einem Mausklick eine erhebliche Arbeitserleichterung.

Im Folgenden wird davon ausgegangen, dass Grundkenntnisse im Umgang mit der COM-Schnittstelle vorhanden sind. In den Links werden Beiträge mit Grundlagen in der Programmierung bereitgestellt.

Aufgabenstellung

Das Programm soll mittels Klick auf einen Button bei mehreren Modellen strukturelle Daten wie Knoten, Linien, Stäbe et cetera automatisch angleichen. Es sollen beispielsweise die Koordinaten des Knotens 1 aus einem Hauptmodell in diversen Nebenmodellen und Varianten übernommen werden. Dabei dürfen allerdings nicht alle Werte übernommen werden, sondern nur Werte, welche vom Benutzer zuvor als frei definiert wurden.

Beispielmodell

Als Beispiel für die Funktion des Programms wurde eine simple Hebebühne modelliert. Das folgende Modell gilt als das Hauptmodell.

Diese Hebebühne ist nicht parametrisiert und liegt in drei Varianten vor: voll ausgefahren, am Boden und in einer mittleren Stellung. Die voll ausgefahrene Variante wird als Hauptmodell festgelegt, die mittlere als Variante 1 und die am Boden als Variante 2.

Vorüberlegungen

Um die Aufgabenstellung zu erreichen, wird entweder eine Art Konfigurationsdatei benötigt oder eine grafische Oberfläche, um zu definieren, welche Modelle miteinander verglichen werden sollen.

Für die Definition der freien oder variablen Koordinaten eines Knotens soll der Kommentar des jeweiligen Elements genutzt werden. Das Programm soll im Kommentar nach einer bestimmten Zeichenkette suchen und, falls diese gefunden wurde, die entsprechenden Koordinaten abändern oder belassen. Zudem wäre es sinnvoll, wenn neue Elemente automatisch in allen Untermodellen ebenfalls angelegt werden. Die Struktur soll daher so sein, dass der Nutzer das gewünschte Modell in RFEM aktiviert (im Vordergrund bearbeitet) und das Programm dann die erforderlichen Modelle öffnet und mit diesem Hauptmodell vergleicht.

Grafische Oberfläche

Für die grafische Oberfläche wurde folgendes einfaches Design gewählt.

Der Nutzer kann per Copy & Paste einen Pfad in der Text-Box einfügen oder eintippen. Mit "Add New Model" kann dieser der Liste der anzugleichenden Modelle hinzugefügt werden. Mit Hilfe des Buttons "Remove Selected Model" kann ein in der Liste selektiertes Modell entfernt werden. Der Button "Modify Models" starten dann das Programm.

Prinzipieller Programmablauf

Das Programm hat zu Beginn nur die Pfade der Nebenmodelle und Varianten und braucht zuerst die Anbindung an RFEM. Wenn die Verbindung zu RFEM steht, soll als Nächstes eine Schleife über die Nebenmodelle laufen. Da das Programm auch Elemente anlegen soll, muss die Hierarchie beachtet werden. Es werden daher zuerst die Knoten, dann Linien, Materialien, Querschnitte und zuletzt Stäbe verglichen. Eine Ausnahme bilden die Knoten, denn hier sollen die Richtungen x, y und z je nach Bedarf übernommen oder belassen werden. Alle anderen Elemente werden entweder komplett übernommen oder belassen. Für alle Elemente soll allerdings gleich sein, dass Neue angelegt werden.

Grundgerüst des Programms

Die Methode, welche beim Klicken des Buttons "Modify Models" ausgeführt wird, hat folgenden prinzipiellen Aufbau.

private void button_mod_click(object sender, EventArgs e)
{
 // RFEM
 //##############################
 Dlubal.RFEM5.IModel3 iModel_org = null;
 Dlubal.RFEM5.IApplication iApp = null;
 try
 { 
  // get interface to application and open model
  iApp = Marshal.GetActiveObject("RFEM5.Application") as Dlubal.RFEM5.IApplication;
  iApp.LockLicense();
  iModel_org = iApp.GetActiveModel() as Dlubal.RFEM5.IModel3;
  
  // loop over found models
  Dlubal.RFEM5.IModel iModel_cpy = null;
  
  for (int i = 0; i < listBox_models.Items.Count; ++i)
  {
   // open model
   iModel_cpy = iApp.OpenModel(listBox_models.Items[i].ToString());
   
   // get structural data
   Dlubal.RFEM5.IModelData2 iModData_org
    = iModel_org.GetModelData() as Dlubal.RFEM5.IModelData2;
   Dlubal.RFEM5.IModelData2 iModData_cpy
    = iModel_cpy.GetModelData() as Dlubal.RFEM5.IModelData2;
   
   //  compare/change nodes
   //  compare/change lines
   //  compare/change materials
   //  compare/change cross sections
   //  compare/change members
  }
  
 }
 catch (Exception ex)
 {
  MessageBox.Show(ex.Message, ex.Source);
 }
 finally
 {
  if (iApp != null)
  {
   iApp.UnlockLicense();
   
   // Releases COM object - not needed anymore
   // Marshal.ReleaseComObject(iApp);
   iApp = null;
  }
  
  iModel_org = null;
  
  // Cleans Garbage Collector for releasing all COM interfaces and objects.
  System.GC.Collect();
  System.GC.WaitForPendingFinalizers();
 }
}

Wie bereits beschrieben, wird zuerst die Anbindung an RFEM hergestellt über GetActiveObject("RFEM5.Application"). Danach wird über GetActiveModel() eine Verbindung zum aktiven Modell hergestellt. Um den Vergleich durchführen zu können, werden jetzt in einer Schleife über die Einträge in der List-Box nacheinander zusätzlich die Untermodelle und deren Strukturdaten (GetModelData() ) geöffnet. Zu diesem Zeitpunkt liegen dann alle geometrischen Daten vor und können verglichen werden.

Falls es ein Problem gibt, dass zum Beispiel ein Modell nicht geöffnet werden kann, wird über den try-catch-Block der Fehler abgefangen, angezeigt und das Programm entsperrt.

Knotenvergleich

Der Vergleich der Knoten zwischen Hauptmodell und Nebenmodell läuft wie folgt ab.

Zuerst werden alle Knoten des Hauptmodells geholt und eine Schleife über diese Knoten gestartet. In dieser Schleife wird zuerst versucht, die Daten des Knotens mit der gleichen Nummer im Nebenmodell zu holen. Falls dies misslingt, weil der Knoten nicht existiert, wird der Fehler mit einem weiteren try-catch-Block abgefangen und stattdessen der Knoten mit den Daten aus dem Hauptmodell im Nebenmodell angelegt.

Falls der Knoten existiert, wird der Kommentar ausgelesen und mit Hilfe des Separators ";" zerlegt. Wenn es danach weniger als drei Teile gibt, werden die Daten aus dem Hauptmodell übernommen. Wenn es drei Teile oder mehr gibt, werden diese ausgewertet. Ein "f" steht dabei für einen festen Wert, der nicht überschrieben werden soll. Falls es kein "f" ist, wird der Wert durch den Wert aus dem Hauptmodell überschrieben.

Ein kurzes Beispiel ist die Zeichenkette "f;;f1;kkl" im Kommentar eines Knotens. Zerlegt ergeben sich die Zeichenketten "f", "", "f1" und "kkl". Bei dem Knoten wird also der Wert x belassen und die Werte y und z überschrieben, da für y eine leere Zeichenkette vorliegt und für z nicht genau "f", sondern "f1".

//  compare/change nodes
Dlubal.RFEM5.Node[] nodes_org = iModData_org.GetNodes();
for(int j=0; j < nodes_org.Length; ++j)
{
 try
 {
  Dlubal.RFEM5.INode iNode = iModData_cpy.GetNode(nodes_org[j].No, Dlubal.RFEM5.ItemAt.AtNo);
  Dlubal.RFEM5.Node node = new Dlubal.RFEM5.Node();
  node = iNode.GetData();
  
  // check, if there are fixed components
  List<string> defs = (node.Comment).Split(';').ToList<string>();
  
  if (defs.Count >= 3)
  {
   if (defs[0] != "f")
    node.X = nodes_org[j].X;
   
   if (defs[1] != "f")
    node.Y = nodes_org[j].Y;
    
   if (defs[2] != "f")
    node.Z = nodes_org[j].Z;
  }
  else
  {
   node.X = nodes_org[j].X;
   node.Y = nodes_org[j].Y;
   node.Z = nodes_org[j].Z;
  }
  
  // set node
  iModData_cpy.PrepareModification();
  iNode.SetData(node);
  iModData_cpy.FinishModification();
  
 }
 catch (Exception ex)
 {
  // if nodes doesn't exist, create it;
  iModData_cpy.PrepareModification();
  iModData_cpy.SetNode(nodes_org[j]);
  iModData_cpy.FinishModification();
 }
 
}

Linien, Materialien und restliche Vergleiche

Die anderen Elemente sind im Ablauf leicht anders zum Knotenvergleich und identisch untereinander.

//  compare/change lines
Dlubal.RFEM5.Line[] lines_org = iModData_org.GetLines();
for (int j = 0; j < lines_org.Length; ++j)
{
 try
 {
  Dlubal.RFEM5.ILine iLine = iModData_cpy.GetLine(lines_org[j].No, Dlubal.RFEM5.ItemAt.AtNo);
  Dlubal.RFEM5.Line line = new Dlubal.RFEM5.Line();
  line = iLine.GetData();
  
  // check, if the line is fixed
  List<string> defs = (line.Comment).Split(';').ToList<string>();
  
  if (defs[0] != "f")
  {
   line = lines_org[j];
  }
  
  // set line
  iModData_cpy.PrepareModification();
  iLine.SetData(line);
  iModData_cpy.FinishModification();
  
 }
 catch (Exception ex)
 {
  // if nodes doesn't exist, create it;
  iModData_cpy.PrepareModification();
  iModData_cpy.SetLine(lines_org[j]);
  iModData_cpy.FinishModification();
 }
 
}

Der Unterschied zum Knotenvergleich besteht darin, dass das Element komplett überschrieben wird, wenn kein "f" im zerlegten Kommentar (zerlegt mit ";") gefunden wird. Die anderen Elemente werden auf exakt die gleiche Art und Weise angelegt und verglichen. Siehe dazu den Quellcode im angehängten Visual-Studio-Projekt.

Auswertung

Das Programm ist in der Lage, die gewünschten Veränderungen in den Nebenmodellen umzusetzen. Die Funktionsweise wird im Video zum Beitrag gezeigt. Das größte Problem besteht aktuell darin, dass Fehleingaben nicht oder nur wenig abgefangen werden.

Zusammenfassung und Ausblick

Das hier vorgestellte Programm ist in der Lage, Nebenmodelle anhand eines Hauptmodells zu aktualisieren. Veränderungen bei Knoten bis hin zu Stäben werden ordnungsgemäß übertragen.

Was fehlt, sind Routinen zum Abfangen von Fehleingaben, welche noch ergänzt werden könnten. Weitere Optimierungen wären beispielsweise das optionale Schließen der Nebenmodelle, was zu einer Bearbeitung im Hintergrund führen kann. Die Ergänzung weiterer Strukturdaten, Lasten und Kombinatorik kann ebenfalls sinnvoll sein.


Autor

Herr Günthel kümmert sich im Kundensupport um die Anliegen unserer Anwender.

Links
Downloads