2387x
001659
2020-10-13

Aktualizacja między modelami i dostosowywanie danych konstrukcyjnych przy użyciu interfejsu COM

W przypadku niektórych konstrukcji konieczne jest aby zaprojektować je w różnej konfiguracji. Może się zdarzyć, że podnośnik koszowy będzie musiał być analizowany zarówno w pozycji złożonej, pół-rozłożonej, jak i w pełni rozłożonej. Ponieważ takie zadania wymagają utworzenia kilku modeli, które są prawie identyczne, możliwość aktualizacji wszystkich modeli za pomocą jednego kliknięcia myszy jest bardzo przydatna.

Poniższy artykuł zakłada, że użytkownik posiada podstawową wiedzę na temat interfejsu COM. Linki tu zawarte prowadzą do artykułów na temat podstaw programowania.

Zadanie

Program powinien automatycznie dostosowywać dowolne dane dotyczące konstrukcji, takie jak współrzędne węzłów, linie, pręty itp., poprzez kliknięcie odpowiedniego przycisku. Na przykład współrzędne węzła 1 powinny zostać przeniesione z modelu głównego do różnych modeli i wariantów drugorzędnych. Jednak nie wszystkie wartości powinny być przenoszone, a tylko te, które zostały wcześniej dowolnie wskazane przez użytkownika.

Model przykładowy

Jako przykład demonstrujący funkcje opisywanego programu zamodelowany został prosty podnośnik koszowy. Poniższy model jest traktowany jako model główny.

Model podnośnika nie jest sparametryzowany i jest dostępny w trzech konfiguracjach: w pełni rozłożony, złożony, w pozycji pół-rozłożonej. Podnośnik całkowicie rozłożony jest zdefiniowany jako model główny, pół-rozłożony jako typ 1, a złożony jako typ 2.

Uwagi

Aby zadanie mogło zostać wykonane, wymagany jest plik konfiguracyjny lub jakaś forma graficznego interfejsu użytkownika, w którym można zaznaczyć, które modele mają być ze sobą porównywane.

W celu zdefiniowania wolnych lub zmiennych współrzędnych węzła należy wykorzystać funkcję komentarza dla stosownego elementu. Program wyszukuje w treści komentarza konkretny ciąg znaków, a jeśli zostanie on znaleziony, modyfikuje odpowiednie współrzędne lub pozostawia je niezmienione. Ponadto byłoby przydatne, gdyby nowe elementy były tworzone automatycznie we wszystkich submodelach. Konstrukcja powinna być zatem utworzona w taki sposób, aby użytkownik aktywował żądany model w programie RFEM (edytowany na pierwszym planie), a program otworzył żądane modele, porównując je z modelem głównym.

Graficzny interfejs użytkownika

Do graficznego interfejsu użytkownika wybrano następujące proste rozwiązanie:

Użytkownik może wpisać ścieżkę w polu tekstowym lub wstawić ją za pomocą opcji kopiuj i wklej. Za pomocą opcji „Dodaj nowy model” można dodać go do listy modeli do dostosowania. Przycisk "Usuń wybrany model" służy do usuwania wybranego modelu z listy. Przycisk "Modyfikacja modeli" uruchamia program.

Podstawowy tok pracy programu

Na początku program posiada tylko ścieżki do modeli i wariantów drugorzędnych oraz wymaga najpierw połączenia z RFEM. Jeżeli połączenie z programem RFEM zostanie nawiązane, pętla programu powinna uruchomić się na modelach drugorzędnych. Ponieważ program powinien również tworzyć elementy, musi być zachowana odpowiednia hierarchia obiektów. Dlatego najpierw porównywane są węzły, następnie linie, materiały, przekroje i na końcu pręty. Wyjątek stanowią węzły, ponieważ w tym przypadku kierunki x, y i z należy w razie potrzeby uzgodnić lub pozostawić bez zmian. Wszystkie pozostałe elementy są przejmowane w całości lub pozostawione bez zmian. W przypadku wszystkich elementów powinna jednak zostać zachowana zasada, że zawsze będzie możliwość dodania nowych elementów.

Podstawowa struktura programu

Kod uruchamiany przyciskiem "Modyfikuj modele" ma następującą podstawową strukturę:

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();
 }
}

Jak już stwierdzono, najpierw nawiązywane jest połączenie z RFEM poprzez GetActiveObject ("RFEM5.Application"). Następnie nawiązywane jest połączenie z aktywnym modelem poprzez GetActiveModel (). Aby możliwe było przeprowadzenie porównania, submodele są otwierane jeden po drugim poprzez pętlę za pomocą wpisów w polu listy (GetModelData ()). W tym momencie wszystkie dane geometryczne są dostępne i można je porównać.

Jeżeli wystąpi problem, na przykład nie można otworzyć modelu, błąd zostanie wychwycony przez blok try-catch, wyświetli się stosowny komunikat, a program zostanie odblokowany.

Porównanie węzłów

Porównanie węzłów między modelem głównym i drugorzędnym przebiega w następujący sposób:

Najpierw pobierane są dane wszystkich węzłów w modelu głównym i wprowadzane są do pętli. W pętli tej program najpierw stara się pobrać dane z modelu drugorzędnego odnośnie węzła o numerze pobranym z modelu głównego. Jeżeli to się nie powiedzie, ponieważ węzeł taki nie istnieje, błąd jest wychwytywany przez kolejny blok try-catch, a w modelu drugorzędnym węzeł o takim numerze jest tworzony na podstawie danych z modelu głównego.

Jeżeli węzeł istnieje, komentarz jest odczytywany i rozkładany na części za pomocą separatora ";". Jeżeli powstanie mniej niż trzy części, dane zostaną pobrane z modelu głównego. Jeśli będą trzy lub więcej części, zostaną potraktowane jako dane dla algorytmu. Litera „f” oznacza stałą wartość, której nie należy nadpisywać. Jeżeli nie jest to „f”, wartość jest nadpisywana przez wartość z modelu głównego.

Krótkim przykładem jest ciąg "f ;; f1; kkl" w polu komentarzu dla węzła. Po rozłożeniu na części powstają ciągi „f”, „”, „f1” i „kkl”. W ten sposób wartość współrzędnej x pozostaje niezmieniona dla tego węzła, a wartości y i z są nadpisywane, ponieważ dla współrzędnej y istnieje pusty ciąg znaków, zaś dla współrzędnej z pojawia się „f1” nie zaś „f”.

//  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();
 }
 
}

Linie, materiały i inne porównywane elementy

Pozostałe elementy różnią się nieznacznie od porównania węzłów, ale są one identyczne (względem siebie).

//  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();
 }
 
}

Różnica w stosunku do porównywania węzłów polega na tym, że element zostanie całkowicie nadpisany, jeśli w podzielonym na części komentarzu nie zostanie znalezione żadne "f" (rozdzielone przez separator ";"). Pozostałe elementy są tworzone i porównywane w dokładnie taki sam sposób. Odszukać to można w załączonym kodzie źródłowym (projekt programu Visual Studio).

Ocena

Program jest w stanie wprowadzić żądane zmiany w modelach drugorzędnych. Sposób działania pokazano na filmie załączonym do artykułu. Największym problemem jest obecnie to, że nieprawidłowe wpisy (dane w komentarzach) nie są wychwytywane lub są wychwytywane w niewielkim stopniu.

Podsumowanie i potencjał rozwoju

Prezentowany tu program może aktualizować modele drugorzędne w oparciu o model główny. Zmiany w węzłach i innych elementach, aż do prętów, są przenoszone prawidłowo.

Brakuje procedur do przechwytywania błędnych wpisów użytkownika. Dalszą optymalizacją może być na przykład opcjonalne zamykanie modeli drugorzędnych, dzięki czemu przetwarzanie może odbywać się w tle. Przydatne może być również dodawanie kolejnych danych dotyczących konstrukcji, obciążeń i kombinacji.


Autor

Pan Günthel zapewnia wsparcie techniczne klientom firmy Dlubal Software i zajmuje się ich zapytaniami.

Odnośniki
Pobrane