Categories
Tekla C#

Refleksja o dzieleniu się

Wpis [part not set] z 2 w serii Tekla - wyrównanie przekrojów

W poprzednim poście wspomniałem o GitHub. W budownictwie co chwila ‘jaramy’ się nowym platformami CDE do zarządzania dokumentacją w toku inwestycji. Obiecują one łatwiejszą komunikację, wersjonowanie modeli/dokumentów, wykrywanie kolizji, ekstra premie za ukończenie projektu przed czasem. A nie, wróć, to budownictwo 😉

GitHub jest właśnie takim CDE, tylko, że darmowym. Oczywiście do pewnego zakresu funkcjonalności, jest też wersja płatna, ale spokojnie, nie dotrzemy do tego etapu. Z GitHub’a korzysta więcej niż 70 milionów programistów, pracując nad szeregiem projektów, w znacznej części publicznych. Robią to zazwyczaj już po godzinach swojej zwykłej pracy.

Dlaczego ktoś chciałby za darmo ‘pracować’ po godzinach? Co programista to inny powód, jednak najczęściej jest to chęć rozwijania się w innym kierunku niż ten aktualny w pracy. Programowanie to szereg wyborów, co człowiek to inne podejście i trudno żeby Twój pomysł zawsze był tym najlepszym. Dopiero konfrontacja z innymi ludźmi, z ich ideami daje możliwość spojrzenia na problem szerzej. W ten sposób rozwijasz swoje umiejętności, zarówno miękkie jak i twarde. Uczysz się współpracować i klepać lepsze, wydajniejsze programy. Poświęcając swój czas – zyskujesz.

Na GitHub znajdziesz wiele przykładów jak tworzyć rozszerzenia do Tekli. Rzuć okiem na repozytorium TSOpenAPIExamples lub na porfolio projektów Dawida Dyrcza..

Dobra, pogadałem, czas na konkrety: tu jest link do naszego repozytorium LetsConstructIT. Tam będą pojawiać się kolejne programy powstałe w ramach społeczności. Na tym etapie wiedz, że gdy okrzepniesz będziesz mógł wprowadzać zmiany do różnych repozytoriów. Obecnie poruszaj się raczej w obszarze read-only, czyli pobieraj kod źródłowy na swój komputer (Code -> Download ZIP).

Ok, pobrałeś repozytorium, rozpakowałeś ZIP’a, uruchomiłeś solucję TeklaApplications.sln w Visual Studio. Być może nawet skompilowałeś projekt SectionAligner. Warto żebyś wysłuchał opowieści o wersjach bibliotek.

Co roku zarówno producenci hardware jak i software wypuszczają nowe wersje swoich flagowców. Znak czasu, przejaw rozwiniętego kapitalizmu ktoś by powiedział. Nowe wersje = pieniądze za aktualizacje, wsparcie, itd. Waluta w gospodarce wędruje, wszyscy (no, prawie) są zadowoleni. Jak to przekłada się na programowanie? Niestety, nie operujemy w próżni, rozszerzenia Tekli opierają się na … Tekli, jej systemie wersji. Co roku, wraz z pojawieniem się nowej instancji publikowana jest kolejna wersja Tekla Open API. Na szczęście, jądro API Tekli jest stałe od wielu wersji. Bardzo rzadko zdarzają się wersje zmieniające funkcjonalność poprzednika. Skorzystamy z tego faktu w celu ułatwienia rozwoju nakładek.

W klasycznym schemacie kompilowanie pod różne Tekle wymaga przepinania wykorzystywanych bibliotek Tekla Open API na adekwatne wersje. Da się to zrealizować przez różne konfiguracje w Visual Studio, można pójść w stronę zaproponowaną przez Dawida Dyrcza, można też inaczej. W C# dostępny jest mechanizm przekierowań wersji wykorzystywanych bibliotek w trakcie uruchamiania programu. Czyli kompilujemy program celując np. w Teklą 2020 a uruchamiamy go pod Teklą 2018i. Lub jeśli jest taka potrzeba pod 2021. Wszystko dzięki elementowi <bindingRedirect> w konfiguracji programu.

Spójrz proszę w zawartość pliku App.config. Obecnie zawiera on wskazanie, że w trakcie uruchamiania programu należy używać wersji 2022.0.0.0 Teklowego API. Jeżeli np. pracujesz w Tekli 2016i to chcesz żeby Twój App.config wykorzystywał Teklowe biblioteki w wersji 2016.1.0.0. Zmień więc u siebie lokalnie zawartośc App.config stosownie do używanej wersji Tekli. Ciekawostką jest fakt, że ten mechanizm jest używany w ramach przygotowywania plików .tsep, czyli instalatorów Teklowych dodatków. Szerszy opis dostępny pod linkiem.

Dostosowałeś lokalnie App.config, możesz skompilować i uruchomić program. Tylko, właściwie jak to działa? Punktem wejścia do programu jest statyczna metoda Main znajdującą się w pliku Program.cs.

internal class Program
{
    static void Main(string[] args)
    {
        Aligner aligner = new Aligner();
        aligner.Execute();
    }
}

Jej jedyną odpowiedzialnością jest wywołanie metody Execute klasy Aligner, która dyryguje resztą procesu. Spójrzmy na tę klasę:

public class Aligner
{
    private DrawingHandler _dh;
    private Drawing _activeDrawing;

    public void Execute()
    {
        if (!InitailizeDrawingHandler())
            return;

        SectionAggregator sectionAggregator = new SectionAggregator(_dh, _activeDrawing);
        sectionAggregator.GetSectionsFromDrawing();
        sectionAggregator.SourceViews.ForEach(x => x.Align());

        _activeDrawing.CommitChanges();
    }

    private bool InitailizeDrawingHandler()
    {
        _dh = new DrawingHandler();
        if (!_dh.GetConnectionStatus())
            return false;

        _activeDrawing = _dh.GetActiveDrawing();
        if (_activeDrawing == null)
            return false;

        return true;
    }
}

Pierwsze co robi metoda Execute to (linijka 8 wywołującą 18-28) sprawdzenie czy znajdujemy się w obszarze rysunku. DrawingHandler to punkt wejścia do komunikacji z Teklowymi rysunkami. Przy jego pomocy możemy otwierać, zapisywać, edytować, drukować poszczególne rysunki. Jeżeli coś idzie nie tak z połączeniem z Teklą (nie jest włączona, wersje bibliotek są niezgodne, uruchomiona jest więcej niż jedna Tekla) to metoda DrawingHandler.GetConnectionStatus() zwróci false oznaczający brak połączenia. Dopasowywanie przekrojów ma sens tylko wtedy, gdy włączony jest rysunek – stąd sprawdzenie w linijka 24-26.

W wariancie pozytywnym: udane połączenie + rysunek aktywny, idziemy dalej, czyli w ramach metody Execute wywoływane są linijki 11-15. Tam napotykamy na wywołanie nowej klasy – SectionAggregator, która pozycjonuje przekroje zgodnie z zadaną logiką. Zachęcam do prześledzenia działania poszczególnych metod. Analizowanie działania algorytmów to podstawa do tworzenia własnych.

W ramach tego wpisu chcę poruszyć dwa różne scenariusze pobierania elementów z Tekli. W zalezności od potrzeb możesz potrzebować wszystkich obiektów danego typu, spełniających określony zestaw cech. Zrobiłem tak w metodzie GetAllSectionViews w ramach klasy SectionAggregator:

private IEnumerable<View> GetAllSectionViews()
{
    foreach (var item in _drawing.GetSheet().GetAllViews())
    {
        if (item is View)
        {
            View view = (View)item;
            if (view.ViewType == View.ViewTypes.SectionView)
                yield return view;
        }
    }
}

W powyższym listingu pobieram najpierw arkusz z danego rysunku. Arkuszem jest najwyższą instancją rysunkową do której wstawiane są kolejne widoki. I to własnie mając arkusz, mogę te widoki pobrać wykorzystując metodę GetAllViews. Następnie sprawdzam typ widoku – logika aplikacji wymaga w tym miejscu pobrania wyłącznie przekrojów, co zostało zapisane w linijce 8-ej.

Drugi schemat pobierania elementów to potrzeba wykorzystania selekcji, którą wykonał już użytkownik. Nie interesuje nas wszystko na rysunku, chcemy wiedzieć co jest obecnie zaznaczone. W tym celu powstała metoda GetOnlySelectedViews bazująca na pobraniu od DrawingHandler’a obiektu klasy DrawingObjectSelector. Dzieje się to w linijce 5-ej poniżej:

private List<SourceViewWithSections> GetOnlySelectedViews()
{
    List<SourceViewWithSections> sourceViews = new List<SourceViewWithSections>();

    foreach (var selectedObject in _dh.GetDrawingObjectSelector().GetSelected())
    {
        if (selectedObject is View)
        {
            View selectedView = selectedObject as View;
            if (selectedView.ViewType == View.ViewTypes.SectionView)
            {
                AddSectionViewWithRelatedSource(selectedView, sourceViews);
            }
            else
            {
                AddSectionViewsFromMainView(selectedView, sourceViews);
            }
        }
    }

    return sourceViews;
}

Wywołując GetSelected() na obiekcie DrawingObjectSelector pobieram aktualne zaznaczenie w obszarze rysunku. Dalej następuje sprawdzenie czy ten obiekt odpowiada naszym potrzebom – czy jest widokiem o typie ‘przekrój’.

Jak widzisz operujemy na bibliotece, którą dostarcza Trimble. Komunikujemy się z rysunkiem (w przyszłości z modelem) w ramach przewidzianych przez producenta programu. Ktoś w centrali dawno temu założył, że potrzebny jest DrawingHandler, który udostępni metodę GetSheet, która zwróci arkusz, z którego będziemy mogli to i owo. Kluczem jest zrozumienie, że ktoś poczynił pewne założenia jak to API ma działać i co ma oferować. I choć możliwości rozszerzania Tekli są znaczne, to mają swój kres – granicą są możliwości Tekla Open API, która jest furtką do bazy danych kryjącej pod schludnym interfejsem programu.

Żeby nie kończyć aż tak pesymistycznie (napotkasz na bariery, których nie skruszysz) chcę pokazać Ci dwie sztuczki, które możesz wykorzystać aby wydobyć więcej z API. Pierwszą z nich są metody rozszerzeniowe, czyli doklejki zwiększające możliwości jakie mają Teklowe obiekty. Spójrz proszę na screen:

Widzimy wywołanie metody GetId() na obiekcie klasy View. Ciekawostką jest fakt, że w oryginale klasa View nie posiada takiej metody. Dodałem ją jako metodą rozszerzeniową dodając nową moc do widoku:

public static class DrawingExtensions
{
    public static int GetId(this DatabaseObject view)
    {
        var identifier = (Tekla.Structures.Identifier)view.GetPropertyValue("Identifier");
        return identifier.ID;
    }
}

Deklarowanie metod rozszerzeniowych jest możliwe tylko w ramach statycznych klas. Sama metoda musi być statyczna a jej argument jest poprzedzony słowem kluczowym this. W ten sposób możesz dodawać nowe umiejętności klasom, które nie są Twoje, które pochodzą z zewnętrznych bibliotek.

W ramach tego rozszerzania wykorzystałem jeszcze jedną funkcjonalność C#. Tekla Open API nie eksponuje publicznie identyfikatorów (unikalnych adresów) obiektów rysunkowych. Ma je jednak wewnątrz swoich klas jako wewnętrzne właściwości. O proszę, tutaj są:

No i klops, przydałby nam sie unikalny identyfikator obiektu rysunkowego a ktoś kiedyś uznał, że nie powinien on być eksponowany jako publiczny. Na pewno miał ku temu powód (pewnie brak zaufania co do jego trwałości), ale my go potrzebujemy dosłownie na chwilkę – nie będziemy go zapisywać na przyszłość i wykorzystywać za tydzień. Jest on nam potrzebny w ramach tej sesji pracy w programie, więc hello – dajcie nam go!

Niestety, nikt nam go nie da – musimy pójśc po niego sami i właśnie do tego potrzebujemy tytułowej refleksji, którą wykorzystałem w ramach statycznej klasy ReflectionHelper. Dzięki niej jesteśmy w stanie w trakcie działania programu wydobyć to co ukryte – poznać wewnętrzny identyfikator obiektu rysunkowego.

Na ten moment wystarczy. Refleksja, metody roszerzeniowe, wspołpraca w ramach GitHub – pojawiło się kilka wartościowych nowości. W kolejnym wpisie przedstawię różne możliwości dystrybuowania Twoich Teklowych roszerzeń. Do usłyszenia!

Categories
Tekla C#

Ułatwmy sobie życie – rysunek w Tekli

Wpis [part not set] z 2 w serii Tekla - wyrównanie przekrojów

Doskonale pamiętam zgrzytanie zębami w trakcie mojej praktyki inżynierskiej, gdy jedyny feedback jaki otrzymywałem do wykonanego rysunku w Tekli brzmiał: przekroje nie są wyrównane do podstawowego widoku. Brzmi dla Ciebie abstrakcyjnie? Spójrz proszę na rysunek pobrany z oficjalnej dokumentacji programu:

Przekroje pochodzące z podstawowych widoków nr 1 i 2 są wyrównane w poziomie i pionie do źródła. Wygląda to ładnie, schludnie, po prostu inżyniersko. Tylko, że ich wyrównanie to klikologia, żmudne wskazanie rodzaju wyrównania (w pionie/poziomie) i wskazanie dwóch punktów określających wektor translacji widoku. Za pierwszym razem, gdy poznasz tę funkcję powiesz ‘wow’ – fajne, ułatwiające życie. Niestety przy setnym wyrównywaniu zaczniesz się zastanawiać, czy Twoje 5 lat studiowania było niezbędne do ‘ogarnięcia’ tej czynności.

Możesz teraz przewrotnie powiedzieć: po co to wyrównanie, nie ma takiej potrzeby, to strata czasu. Ale dla dobra tej serii proszę porzuć tę negację i zobacz co dla Ciebie przygotowałem:

W materiale video przedstawiłem działanie pierwszego, darmowego marka do Tekla Structures powstałego w ramach LetsConstructIT. Makro możesz pobrać z linku. Po wyświetleniu zawartości docelowej strony wybierz prawy przycisk myszy i skorzystaj z opcji Zapisz jako.

Tylko gdzie zapisać makro? Sprawdź w Tekli gdzie znajduje się folder z którego odczytywane są makra. W tym celu uruchom zaawansowane ustawienia:

A następnie w nowo otwartym oknie, w domyślnie otwartej zakładce File Locations odczytaj wartość zmiennej XS_MACRO_DIRECTORY:

W moim wypadku jest to ścieżka C:\TeklaStructures\2022.0\environments\common\macros. Skoro nasze makro jest dostępne z poziomu rysunku to powinniśmy je zapisać w podfolderze drawings powyższego katalogu. Czyli u mnie makro powinno zostać zapisane w: C:\TeklaStructures\2022.0\Environments\common\macros\drawings Pamiętaj, że w Twojej Tekli/środowisku ta ścieżka może być inna, ale odczytując aktualną wartość z zaawansowanych ustawień na pewno trafisz do brzegu.

Po zapisaniu źródłowego pliku Section Aligner.cs w folderze drawings i ponownym uruchomieniu Teklu będziesz miał do dyspozycji nowe makro rysunkowe o nazwie Section Aligner:

Narzędzie w zależności od wstępnego zaznaczenia posiada trzy tryby pracy:

  • wyrównanie wyłącznie zaznaczonego przekroju – przed uruchomieniem makra zaznacz jeden lub więcej przekrojów, w ten sposób określasz, które widoki mają zostać przesunięte,
  • wyrównanie wszystkich przekrojów pochodządzych od zaznaczonego widoku głównego – każdy przekrój ma swoje źródło, czyli widok na którym początkowo wskazany został zakres przekroju; zaznacz ten widok podstawowy a wyrównane zostaną wszyskie przekroje pochodne,
  • wyrównanie wszystkich przekrojów na rysunku – nie zaznaczaj niczego, odpal makro i ciesz się wykonaną pracą.

Ten skrypt jest dla mnie ważny z kilku powodów. Po pierwsze wydaje się całkiem funkcjonalny, przynajmniej dla niektórych użytkowników Tekli – wierzę, że zachęci to nowe osoby to choćby pobieżnego zapoznania się z programowaniem. Po drugie, w celu jego stworzenia musiałem wykorzystać kilka nowych dla Ciebie konceptów dostępnych w C# – będę o nich pisał w kolejnych postach, rozszerzając wachlarz Twoich umiejętności. Po trzecie, po przerwie, miałem okazję przypomnieć sobie wszystkie blaski i cienie Tekla Open API, które nadal uważam za podstawowy czynnik bardzo wysokiej ceny Tekli. Niestety, świadomość możliwości jakie niesie Tekla Open API jest niskie, nie mówiąc o umiejętnościach jego wykorzystania. Chęć nauczenia/wskazania tych nieodkrytych dróg była jednym z motorów powstania #LetsConstructIT.

Makro, którego dotyczy wpis jest zlepkiem kilku klas. Nie tworzyłem go jako jednego pliku – to był ostatni etap tworzenia. W kolejnym poście wskażę repozytorium na GitHub zawierające właściwe źródło. Zdecydowałem się na połączenie wszystkiego w jeden plik z uwagi na prostotę przekazania tego dalej – każdy użytkownik może dodać nowe makro do swojej Tekli, spiąć to z wypatrzonym skrótem klawiszowym i działać – do czego serdecznie Cię zachęcam 🙂