Rok akademicki 2011/2012 Politechnika Warszawska Wydział Elektroniki i Technik Informacyjnych Instytut Informatyki

Praca Dyplomowa Inżynierska

Marcin Gecow

Modelowanie i animacja układów napędowych parowozów w programie 3ds Max

Opiekun pracy dr inż. Cezary Stępień

Ocena: ......

...... Podpis Przewodniczącego Komisji Egzaminu Dyplomowego Specjalność: Inżynieria Systemów Informatycznych

Data urodzenia: 1988.03.28

Data rozpoczęcia studiów: 2008.02.21

Życiorys Urodziłem się 28.03.1988r. w Warszawie. W roku 2004 rozpocząłem naukę w XIV Liceum Ogólnokształcącym im. Stanisława Staszica w Warszawie. Po zdaniu egzami- nów maturalnych dostałem się na studia dzienne I stopnia na Wydziale Elektroniki i Technik Informacyjnych Politechniki Warszawskiej na kierunek Informatyka. Od trzeciego roku studiów moją wybraną specjalnością jest Inżynieria Systemów Infor- matycznych w Instytucie Informatyki. Poza studiami interesuję się fotografią, turystyką oraz sportami zespołowymi.

...... Podpis studenta

EGZAMIN DYPLOMOWY

Złożył egzamin dyplomowy w dniu ...... 2012 r. z wynikiem ......

Ogólny wynik studiów ......

Dodatkowe wnioski i uwagi Komisji: ......

......

...... STRESZCZENIE Niniejsza praca dotyczy modelowania i animacji mechanizmów napędowych pa- rowozów. Ma na celu utworzenie narzędzia w środowisku 3ds Max, umożliwiającego szybkie i łatwe odtworzenie zależności mechanicznych takiego układu. Do realiza- cji został wybrany układ napędowy Walschaertsa-Heusingera, gdyż jest najbardziej popularny wśród maszyn parowych. Pracę zrealizowano w programie firmy Autodesk — 3ds Max, z wykorzystaniem dostarczonego języka skryptowego — MAXScript. Kwestie mechanizmów zosta- ły rozwiązane z wykorzystaniem algorytmów kinematyki odwrotnej. Przygotowa- ny skrypt umożliwia utworzenie odpowiedniego systemu zależności mechanicznych, adekwatnych do realizowanego układu napędowego.

Słowa kluczowe: kinematyka odwrotna, MAXScript, parowóz, układ napędowy, układ korbowy, rozrząd pary, modelowanie, animacja, grafika komputerowa

MODELING AND ANIMATION OF STEAM GEAR IN 3DS MAX This thesis concerns the modeling and animating of mechanisms of steam lo- comotive . Its aim is to create a tool in a 3ds Max environment which enables quick and easy reconstruction of mechanical dependences of system of this type. To implementation was chosen Walschaerts-Heusingers valve gear, since it is the most popular . The work was realized in the Autodesk’s program — 3ds Max, at use of sup- plied scripting language — MAXScript. Problems of mechanisms have been solved with the use of inverse kinematics algorithms. Created script enables creation of an appropriate system of mechanical dependences relevant for realized drive system.

Keywords: inverse kinematic, MAXScript, steam locomotive, drive system, system, valve gear, modeling, animation, computer graphics Spis treści

1. Wstęp ...... 6 1.1. Cel pracy ...... 6 1.2. Układy napędowe w parowozach ...... 6 1.3. Zasada działania systemu Walschaertsa-Heusingera ...... 8 2. Dostępne metody animacji układu ...... 10 2.1. Opis ruchu z pomocą funkcji matematycznych ...... 10 2.2. Zastosowanie ograniczników ...... 11 2.3. Zastosowanie systemów kości ...... 13 2.4. Zastosowanie algorytmów kinematyki odwrotnej bez wykorzystania systemów kości ...... 14 3. Założenia projektowe ...... 16 3.1. Środowisko graficzne Autodesk 3ds Max ...... 16 3.2. Zastosowanie języka MAXScript ...... 16 3.3. Możliwość korzystania z fotografii ...... 17 3.4. Uniwersalność rozwiązania ...... 17 4. Projekt rozwiązania ...... 18 4.1. Działanie narzędzia ...... 18 4.2. Podział na podzespoły ...... 19 5. Opis implementacji ...... 23 5.1. Łączenie podzespołów ...... 23 5.2. Zakończenia podzespołów ...... 23 5.2.1. Końcowy efektor ...... 24 5.2.2. Wiązania ...... 24 5.3. Kulisa — realizacja łuku ...... 24 5.4. Kulisa — środek okręgu ...... 25 5.4.1. Wyznaczenie środka okręgu na podstawie trzech punktów ...... 25 5.4.2. Wyznaczenie środka okręgu na podstawie dwóch punktów oraz promienia ...... 26 5.5. Możliwość korzystania z fotografii ...... 28 5.5.1. Ustawienie tapety ...... 29 5.5.2. Nałożenie tekstury ...... 31 5.6. Parametry algorytmu kinematyki odwrotnej ...... 31 6. Opis wyników weryfikacji opracowanego rozwiązania ...... 33 6.1. Modelowanie parowozu TKh1-191 ...... 33 6.2. Modelowanie parowozu Las47 ...... 36 6.3. Modelowanie parowozu Ty2-50 ...... 38 6.4. Modelowanie parowozu Ty51-137 ...... 41 6.5. Opis wizualizacji realistycznej parowozu TKh1-191 ...... 45 6.6. Wnioski ...... 47 7. Podsumowanie ...... 48 Bibliografia ...... 49 Spis rysunków ...... 50 Spis treści 5

Dodatki ...... 52 Dodatek A. Dokumentacja techniczna ...... 52 A.1. Wykaz głównych funkcji i złożonych obiektów ...... 52 A.2. Instrukcja obsługi ...... 52 A.2.1. Instalacja ...... 52 A.2.2. Obsługa ...... 53 Dodatek B. Układ napędowy parowozu w ujęciu historycznym ...... 55 Dodatek C. Skrypt ...... 55 Dodatek D. Zawartość płyty CD ...... 66 D.1. Opis animacji umieszczonych na płycie CD ...... 66 1. Wstęp

Przyrost mocy obliczeniowych komputerów powoduje, że coraz skuteczniej wy- korzystywane są one do tworzenia przeróżnych przestrzennych animacji. Równole- gle rośnie stale zapotrzebowanie na coraz bardziej specjalistyczne oprogramowanie ułatwiające i przyspieszające pracę grafików komputerowych. Dlatego cały czas po- wstają dla nich przeróżne, nowe narzędzia.

1.1. Cel pracy

Celem pracy jest opracowanie narzędzia graficznego w standardzie 3D, ułatwia- jącego modelowanie i animację układów napędowych parowozów. Jest ich wiele rodzajów. Przygotowane narzędzie ma służyć do modelowania najbardziej rozpo- wszechnionego napędu, jakim jest system Walschaertsa-Heusingera. Niniejsza praca służy do odtworzenia mechanicznych zależności, które można potem wykorzystać w animacji parowozów.

1.2. Układy napędowe w parowozach

Jednym z fragmentów mechanizmu napędowego parowozu jest układ korbowy. Energia dostarczana z kotła w postaci gorącej, sprężonej pary wprawia w ruch tłoki. Układ korbowy zamienia ruch posuwisto-zwrotny na ruch obrotowy. Zwykle składa się on z korby, korbowodu oraz suwaka (rysunek 1.1).

Rysunek 1.1. Układ korbowy

Jeden koniec korbowodu jest przymocowany wahliwie do elementu posuwisto-zwrotnego — suwaka. W typowym silniku samochodowym suwakiem jest tłok, a w parowozie jest to tzw. krzyżulec będący zakończeniem tłoczyska. Natomiast funkcję korby w lokomotywach parowych pełni koło. Oprócz tego w mechanizmie napędowym parowozu jest układ dźwigni stano- wiący rozrząd pary, dzięki któremu można sterować kierunkiem i prędkością jazdy. Rozdział 1. Wstęp 7

Nadzoruje on pracę suwaka zaworu, który odpowiada za to, z której strony oraz ile pary zostanie wpuszczone do cylindrów. Kierunek jazdy jest wynikiem zależno- ści czasowych pomiędzy ruchem poszczególnych elementów układu. Ilość dostarcza- nej pary wpływa na prędkość. Schemat budowy wraz z opisem układu napędowego Walschaertsa-Heusingera przedstawia rysunek 1.2.

Nazwy poszczególnych elementów: 1. koło silnikowe, 11. ramię wsteczne nastawnika, 2. koła wiązane, 12. wodzidło suwaka, 3. wiązar, 13. krzyżulec, 4. korba mimośrodu, 14. wodzik wahacza, 5. drążek mimośrodowy, 15. prowadnica trzonu suwaka, 6. korbowód, 16. wahacz krzyżulcowy, 7. drąg stawidłowy, 17. trzon tłokowy, 8. łącznik wodzidła, 18. trzon suwaka, 9. kulisa, 19. suwak. 10. ramię unoszące nastawnika,

Rysunek 1.2. Mechanizm napędowy i parorozdzielczy Rysunek na podstawie grafiki ze strony http://pl.wikipedia.org/wiki/Parowóz

W parowozach układ napędowy zazwyczaj składa się z dwóch lustrzanych mecha- nizmów. Konstruowano również parowozy o 3 lub 4 cylindrach. Czasami zdarzały się parowozy 6-cylindrowe. Parowozy mające więcej niż 6 cylindrów występowały bardzo rzadko. Większa liczba cylindrów pozwalała na wzrost sprawności poprzez zastosowanie silnika o podwójnym rozprężaniu. Para, pod dużym ciśnieniem, dopły- wała do cylindra wysokociśnieniowego, a następnie była źródłem zasilania znacznie większego cylindra niskociśnieniowego. Przykładem konstrukcji składającej się z dwóch lustrzanych mechanizmów jest system Walschaertsa-Heusingera. Jeden mechanizm jest po lewej, drugi po prawej stronie parowozu. Mechanizmy te są przesunięte w fazie, by wyeliminować wzajemnie tzw. martwe punkty. Wszystkie rozważania w niniejszej pracy dotyczą jednego z tych mechanizmów. Najczęściej stosowany system Walschaertsa-Heusingera, wybrany jako główny w tej pracy, skonstruowany został w roku 1850 i szybko rozpowszechnił się na całym świecie. Swój sukces zawdzięczał precyzyjnej pracy oraz ważnej przy utrzymaniu — prostocie. Niniejsza praca dotyczy tego właśnie systemu. Rozdział 1. Wstęp 8

1.3. Zasada działania systemu Walschaertsa-Heusingera

Zasadniczymi elementami silnika parowego są: z tłokiem oraz mecha- nizm korbowy. Na rysunku 1.3 przedstawione są dwa uproszczone schematy maszyny parowej. W obu przypadkach układy korbowe i tłoki są w tym samym położeniu. Cylindry z tłokami mają po dwie komory. Do jednej z nich jest wpuszczana gorąca para pod ciśnieniem. Komora przeciwległa jest połączona z układem wydechowym. Różnica ciśnień powoduje jednostronne parcie na tłok, w wyniku czego przesuwa się on zgodnie z kierunkiem tej siły. W zależności od tego, do której z komór zostanie wpuszczona para pod ciśnieniem — układ korbowy zacznie się obracać w inną stronę. Po obrocie o 90◦ tłok dojdzie do swojego zwrotnego punktu. Jest to tzw. martwy punkt. W tym momencie należy zamienić dotychczasowe funkcje komór tzn. dostar- czyć parę do komory, która była do tej pory połączona z układem wydechowym, a z drugiej umożliwić swobodny wypływ pary. Jeśli układ ma za duże opory i zmia- na ta nie zostanie wykonana odpowiednio szybko — może się zdarzyć, że układ się zatrzyma. W systemie Walschaertsa-Heusingera przeciwdziała temu przesunięcie fazowe lustrzanych mechanizmów napędowych.

(a) Silnik z bocznym ujściem pary (b) Silnik z centralnym ujściem pary Rysunek 1.3. Schematy silnika parowego

Para do cylindrów może być kierowana w różny sposób np. osobnymi zaworami. Najczęściej używany jest jednak jeden zawór suwakowy, który równocześnie wpusz- cza parę do wybranej komory cylindra i otwiera sąsiednią. Na rysunku przedstawiono schematycznie dwie wersja zaworów, jakie można spotkać w publikacjach dotyczą- cych silników parowych. Każdy z nich ma trzy komory — dwie skrajne i środkową. W zaworze na rysunku 1.3(a) gorąca para pod ciśnieniem dostarczana jest do komory środkowej suwaka, na rysunku 1.3(b) zaś do komór skrajnych. W obu przypadkach pozostałe komory służą do odprowadzenia zużytej, rozprężonej pary do atmosfery. Jak widzimy ze schematów w wyniku innej budowy zaworów, przesunięcie su- waków w prawo spowoduje dostarczenie pary do innych komór cylindrów i obrót mechanizmów korbowych w inną stronę. W obu przypadkach w chwili dojścia tło- ków do skrajnych położeń, aby silnik nie stanął, suwaki zaworów trzeba przesunąć w drugą stronę. Ruch tłoka wyprzedzany jest nieznacznie przez ruch suwaka. Od tego, w którą stronę jest wyprzedzany, zależy kierunek jazdy. W parowozie realizuje to mechanizm rozrządu pary. Ustala on wzajemne powiązania pomiędzy ruchem tłoka i suwakiem zaworu. Na rysunku 1.2 (zamieszczonym w rozdziale 1.2) jest pokazany cały układ na- pędowy z zaworem takim, jak na rysunku 1.3(a). Wodzidło suwaka jest zaczepione w kulisie i może się w niej suwliwie poruszać po łuku znajdującej się w niej pro- wadnicy. Względem kulisy jest ono ustawiane przez maszynistę za pomocą drąga stawidłowego, nastawnika i łącznika wodzidła. Wahająca się zaś cyklicznie kulisa Rozdział 1. Wstęp 9 porusza w poziomie wodzidłem. Im dalej od osi obrotu kulisy jest zaczepione wo- dzidło, tym większy skok ma zawór i tym większe jest napełnienie cylindra. Gdy wodzidło jest przesunięte poniżej osi kulisy — parowóz porusza się do przodu, gdy jest powyżej — do tyłu. W przypadku przesunięcia wodzidła tak, by jego zaczepienie było nieco wyżej niż oś obrotu kulisy — nieznaczny ruch wodzidła zostanie kompensowany ruchem krzyżulca. W efekcie pomimo wahania się wahacza krzyżulcowego — jego oś obrotu będzie prawie nieruchoma. Suwak zaworu znajdujący się w pozycji środkowej będzie się tylko nieznacznie przesuwał. Dzięki równoczesnemu zamknięciu przepustnicy — para nie jest dostarczana do cylindrów. W takim przypadku, dzięki zastosowaniu jeszcze dodatkowych mechanizmów, możliwe jest ciągłe połączenie obu komór z ukła- dem wydechowym. Ruch tłoka nie jest wtedy hamowany koniecznością sprężania zawartości komór i lokomotywa, jeśli była w ruchu — dalej jedzie rozpędem. 2. Dostępne metody animacji układu

Istnieje kilka możliwości realizacji animacji układu, które trzeba było na wstępie porównać. Testy mające na celu zestawienie tych metod, przeprowadzono modelując układ korbowy. Przyjęto (odwrotnie niż w rzeczywistym układzie napędowym paro- wozu), że czynnikiem sprawczym wszystkich ruchów jest ruch korby. Takie podejście pozwoliło na utrzymanie stałej prędkości obrotowej kół związanych bezpośrednio z korbowodem. W rzeczywistości wszystkie metody polegają na wykonaniu jedynie korbowodu wraz z suwakiem. Korba natomiast jest tworzona i wprawiana w ruch osobno. Niezależnie od stosowanej metody tworzenia korbowodu, korba może być wykonana w dowolny sposób. Celem jest otrzymanie punktu poruszającego się po okręgu, do którego można podłączyć korbowód. Jedną z najprostszych metod realizacji korby jest utworzenie dwóch obiektów, np. typu Dummy. Należy przyjąć, że są one jej dwoma końcami. Pierwszy z nich jest środkiem okręgu, który należy wprawić w ruch obrotowy. Drugi z nich jest punk- tem na okręgu — poprzez ogranicznik Link kopiuje ruch obrotowy po pierwszym. Wykorzystywane typy ograniczników opisane są w dalszej części pracy. Program 3ds Max udostępnia kilka sposobów realizacji układu korbowego. Moż- na je stosować odrębnie, jednak najlepsze rezultaty osiągane są poprzez ich łączenie. W kolejnych podrozdziałach zostały przedstawione różne sposoby realizacji korbo- wodu z suwakiem. Każda metoda wymaga jeszcze osobnego utworzenia korby, wpra- wiającej układ w ruch.

2.1. Opis ruchu z pomocą funkcji matematycznych

Każdy ruch można opisać za pomocą wzorów matematycznych. Metoda ta polega na wcześniejszym wyprowadzeniu wzorów dla wszystkich poruszających się obiektów i ich późniejszym zastosowaniu. Na rysunku 2.1 przedstawiony jest schematycznie układ korbowy. Odcinek r jest korbą, a x1 jego chwilowym rzutem na oś X. Odcinki l i x2 są zaś odpowiednio korbowodem i jego rzutem na oś X.

Rysunek 2.1. Układ korbowy w podejściu matematycznym Rozdział 2. Dostępne metody animacji układu 11

Mając dane wartości: długości r, l oraz kąt α, możliwe jest obliczenie pozostałych wymaganych wartości, potrzebnych do animacji (odległości suwaka od osi korbowo- du x = x1 + x2 oraz kąta β). Można je wyprowadzić z funkcji trygonometrycznych, poprzez kolejne przekształcenia:

h = r sin α, (2.1) x = r cos α, (2.2) 1 √ 2 2 x2 = l − h , (2.3) q 2 2 2 x2 = l − r sin α, (2.4)

x = x1 + x2, (2.5)

q x = r cos α + l2 − r2 sin2 α, (2.6)

h! β = arc sin , (2.7) l r sin α β = arc sin , (2.8) l W ten sposób otrzymane wzory na długość x (2.6) oraz kąt β (2.8) pozostaje jedynie przypisać odpowiednim obiektom. Wartość x — położeniu suwaka, czyli punktowi B. Kąt β — nachyleniu korbowodu, czyli odcinka |AB|. Zaletą tej metody jest jej duża dokładność. Wadą jednak jest potrzeba wypro- wadzenia dokładnych wzorów dla wszystkich obiektów. Przy bardziej skomplikowa- nych układach, jak np. przy pełnym układzie napędowym parowozu, wyprowadzenie wszystkich wzorów byłoby znacznie bardziej skomplikowane.

2.2. Zastosowanie ograniczników

Kolejnym sposobem na zbudowanie modelu układu korbowego jest użycie do- starczonych przez program ograniczników (Constraints). Umożliwiają one nakła- danie różnego typu więzów na jeden obiekt względem drugiego. Program 3ds Max udostępnia siedem typów ograniczników: — Attachment, — Surface, — Path, — Position, — Link, — LookAt, — Orientation. Pierwszym ogranicznikiem wykorzystywanym przy tej próbie jest LookAt. Sto- sowany jest tylko przy tej metodzie. Pozwala on na to, aby obiekt obracał się wokół swego punktu obrotu, automatycznie patrząc na inny obiekt. Wymaga wcześniej- szego ustawienia punktu obrotu obiektu (Pivot). Przy realizacji układu korbowego ogranicznik ten można zastosować do zmiany nachylenia korbowodu tak, aby był on skierowany w stronę suwaka. Czyli, by korbowód leżał na linii łączącej punkt A z punktem B. Działanie opisanego ogranicznika jest przedstawione na rysunku 2.2. A jest punktem obrotu, B zaś suwakiem, którego położenie jest śledzone. Za- leżnie czy suwak (punkt B) jest bliżej czy dalej od osi korby (punkt O) — to kąt β odpowiednio rośnie bądź maleje. Rozdział 2. Dostępne metody animacji układu 12

Rysunek 2.2. Układ korbowy zbudowany przy użyciu ogranicznika LookAt

Powstaje problem, jak wyznaczać chwilowe położenie suwaka. Można to zrobić w sposób uproszczony korzystając z ogranicznika Link. Ogranicznik ten został wy- korzystany we wszystkich testowanych metodach np. do tworzenia korby. Polega na kopiowaniu zmian położenia, kąta oraz rozmiaru innego obiektu. Istnieje możliwość wskazania tylko niektórych parametrów do naśladowania i wyłączenie pozostałych. Jest to bardzo przydatne narzędzie. Przy realizacji metodą tworzenia animacji ukła- du korbowego z wykorzystaniem jedynie ograniczników, ogranicznik Link jest do- datkowo używany, aby wprawić w ruch suwak. W tym celu jest kopiowany ruch punktu z końca korby, jednak tylko wzdłuż osi X. Dzięki temu suwak porusza się w sposób posuwisto-zwrotny. Ruch ten nie jest jednak dokładnym odzwierciedle- niem rzeczywistego układu. Chociaż suwak posiada ten sam skok — jego chwilowe prędkości, a tym samym i chwilowe położenia, są inne niż w rzeczywistym układzie. Rzeczywisty korbowód ma stałą długość. Jeżeli suwak w danej chwili znajduje się zbyt blisko punktu O (na rysunku 2.3 przedstawiono jako punkt B0) — to korbowód okazuje się być za długi. Kiedy zdarzy się natomiast, że suwak jest za daleko (na rysunku przedstawione jako punkt B00) — to korbowód do niego nie sięga.

Rysunek 2.3. Różnice wynikające z prędkości suwaka Rozdział 2. Dostępne metody animacji układu 13

Występujące różnice pomiędzy ruchem układu rzeczywistego i uproszczonego przedstawione są na rysunku 2.3. Wyższy układ przedstawia fragment poprawnie poruszającego się układu, w którym długość korbowodu jest zawsze stała — tu długość l. Pod nim pokazane są te same fazy ruchu układu, w którym położenie suwaka wyznaczane jest przez kopiowanie rzutu położenia końca korby na oś X (są odpowiednio kopiowane odcinki x1, x2, x3). 0 00 0 00 Początkowe położenia B0 i B0 oraz końcowe B4, B4 są identyczne. Jednak w po- średnich występują różnice — ∆x1, ∆x2 oraz ∆x3. Przy odpowiednio długim kor- bowodzie oraz stosunkowo krótkiej korbie, błąd ten można przyjąć za akceptowalny i niezauważalny. W celach animacji można próbować go ukryć poprzez ustawienie zmiennej długości korbowodu albo schowanie jego końca w odpowiednio dużym su- waku. Zaletą tej metody jest łatwa implementacja. Nie potrzeba wcześniejszych obli- czeń ani innych przygotowań. Wadą jest jednak przyjęty błąd ruchu suwaka. Można się spodziewać, że podczas realizacji bardziej skomplikowanych układów, potrzebne byłyby dalsze uproszczenia. Celem pracy, jest jak najwierniejsze oddanie zależności mechanicznych, więc ta metoda nie jest dobra. Powstały problem można w łatwy sposób rozwiązać opisując ruch suwaka wzo- rami matematycznymi, jak w poprzedniej metodzie. Położenia zaś korbowodu wy- znaczać stosując ogranicznik LookAt. Łączenie tych dwóch metod znacznie ułatwia proces modelowania.

2.3. Zastosowanie systemów kości

Środowisko 3ds Max udostępnia możliwość tworzenia gotowego systemu kości. Jest on zwykle kilkoma punktami połączonymi według pewnych zależności. Przykład przedstawiono na rysunku 2.4. Wyglądem przypomina strukturę drzewa. Elementy od strony grubszego końca nazywamy rodzicami. Od drugiej, cieńszej strony są tzw. dzieci. Istnieją ograniczenia uniemożliwiające tworzenie pętli zależności. Oznacza to, że dzieci nie mogą być rodzicami swoich rodziców. Drugim ważnym ograniczeniem jest możliwość posiadania przez każde dziecko tylko jednego bezpośredniego rodzica. Każdy rodzic może posiadać jednak dowolną liczbę potomków. Wszystkie zmiany, którym są poddani rodzice, wpływają na ich dzieci.

Rysunek 2.4. Przykład prostego systemu kości wraz z nazwami

Po zastosowaniu algorytmu kinematyki odwrotnej, dodawane są zależności w dru- gą stronę — od dziecka do przodków. Przykładowo, gdy najmłodszy element zmieni Rozdział 2. Dostępne metody animacji układu 14 swoje położenie — algorytm kinematyki odwrotnej obliczy ułożenie pozostałych obiektów w łańcuchu. Typowym przykładem obrazującym zależności jest ramię ro- bota. Łańcuch zależności jest tak ustawiony, że dłoń jest najmłodszym potomkiem, a jego przodkami są pozostałe elementy. Gdy dłoń próbuje sięgnąć po jakiś obiekt, algorytm oblicza i zmienia ułożenie wszystkich jego przodków. System kości automatycznie wykorzystuje algorytmy kinematyki odwrotnej. Wy- starczy jedynie wybrać algorytm i można przystąpić do modelowania. Wygenerowa- nie w ten sposób układu korbowego jest bardzo szybkie. Dostępne są cztery różne algorytmy kinematyki odwrotnej: — HI (history independent) — algorytm niezależny od historii obiektu, — IK limb — algorytm przeznaczony do ruchu kończyn, — SplineIK — algorytm obsługujący krzywe, — HD (history dependent) — algorytm zależny od historii obiektu. Każdy z tych algorytmów góruje nad innymi w pewnym zakresie zastosowań. Zależnie od wybranego algorytmu, w konkretnym zastosowaniu użytkownik może osiągnąć trochę inne efekty. Algorytmy różnią się między sobą także wyglądem (ry- sunek 2.5).

Rysunek 2.5. Prezentacja kości z różnymi algorytmami kinematyki odwrotnej. Kolejno od góry: HI, Limb, Spline, HD

Przy realizacji układu korbowego najefektywniejszy okazał się ostatni — HD. Z jego pomocą łatwo można otrzymać pożądany efekt. W tym celu należy utworzyć łańcuch składający się z dwóch kości. W ustawieniach najstarszej kości, która jest odpowiednikiem suwaka, należy zablokować rotację względem wszystkich trzech osi oraz zaznaczyć opcję ślizgania wzdłuż jednej z osi. Po tych zabiegach, system zacho- wuje się, jak układ korbowy. Starsza kość jest rozciągana wzdłuż wskazanej osi — jej młodszy koniec reprezentuje suwak, starszy natomiast szynę. Młodsza kość jest korbowodem, który należy podłączyć do korby. Taka metoda jest bardzo wygodna przy tworzeniu różnych, bardziej lub mniej skomplikowanych mechanizmów. W szybki i łatwy sposób można osiągnąć zadowa- lające efekty. Uzyskana animacja ruchu dobrze naśladuje rzeczywiste układy.

2.4. Zastosowanie algorytmów kinematyki odwrotnej bez wykorzystania systemów kości

Prezentowana metoda polega na wcześniejszym utworzeniu stawów łączących poszczególne elementy i nadawaniu im odpowiednich zależności. Wykorzystuje ona Rozdział 2. Dostępne metody animacji układu 15 również algorytmy kinematyki odwrotnej. Stosuje się je do dowolnych obiektów. Stawy można przedstawić na przykład, jako obiekty pozorne typu Dummy. Są to elementy pomocnicze w kształcie sześcianów. Po utworzeniu odpowiednich obiektów (jak na rysunku 2.6), należy narzucić im hierarchię zależności za pomocą ogranicz- nika Link.

Rysunek 2.6. Obiekty typu Dummy przed zastosowaniem algorytmu kinematyki odwrotnej

Rysunek 2.7. Obiekty typu Dummy z zastosowanym algorytmem HD kinematyki odwrotnej

Po takim przygotowaniu można zaimplementować wybrany algorytm kinematyki odwrotnej. W tym celu należy wskazać pierwszy i ostatni obiekt w łańcuchu obiek- tów. Obiekty zostaną wtedy połączone w charakterystyczny dla tej metody sposób, jak na rysunku 2.7. Na koniec otrzymanemu układowi należy nadać odpowiednie ustawienia, podobnie jak w poprzedniej metodzie. Różnica polega na tym, że kości zostały zastąpione wybranymi obiektami, w tym przypadku typu Dummy. Zabloko- wanie rotacji względem wszystkich trzech osi oraz zaznaczenie opcji ślizgania wzdłuż jednej z osi było zastosowane w poprzedniej metodzie do najstarszej kości. W tej metodzie należy analogicznie zmienić ustawienia najstarszego stawu. Takie podejście przy realizacji dowolnych układów daje identyczne efekty, jak poprzednia metoda, chociaż wymaga większej liczby kroków. Pozwala jednak swo- bodnie edytować pojedyncze elementy przed połączeniem ich w jedną całość. Ta metoda została zastosowana w dalszym etapie prac jako najbardziej odpowiednia. 3. Założenia projektowe

Przyjęto następujące założenia projektowe: — realizację w programie firmy Autodesk — 3ds Max, — zastosowanie języka MAXScript, — możliwość korzystania z fotografii, — uniwersalność rozwiązania.

3.1. Środowisko graficzne Autodesk 3ds Max

Zgodnie z otrzymanymi założeniami praca powinna być zrealizowana w progra- mie 3ds Max, firmy Autodesk. Obecnie producent udostępnia dwie jego wersje — 3ds Max 2012 oraz 3ds Max Design 2012. Istniejący podział na dwa odrębne programy obowiązuje od wydania 2009. Są one do siebie bardzo zbliżone, jednak różnią się dodatkowymi modułami. Wersja 3ds Max Design posiada m.in. moduł Exposure, przeznaczony do symulacji i ana- lizy słońca, nieba oraz sztucznego oświetlenia w scenach 3D. Skierowana jest ona raczej do architektów, projektantów przemysłowych i specjalistów od wizualizacji. Natomiast wersja 3ds Max zawiera m.in. moduł SDK (Software Development Kit), który umożliwia tworzenie własnych wtyczek, przez co jest skierowana głównie do twórców gier, animacji i efektów specjalnych w produkcji filmowej. Różnice między nimi nie wpływają jednak na realizację pracy i z projektowanego narzędzia można korzystać w obydwu wersjach.

3.2. Zastosowanie języka MAXScript

Praca powinna być napisana przy użyciu istniejącego w obydwu odmianach pro- gramu języka skryptowego — MAXScript. Umożliwia on wprowadzenie automa- tyzacji przy tworzeniu animacji nowych systemów napędowych i dzięki temu daje znaczną oszczędność czasu. Z pomocą tego języka można zrealizować dowolne opera- cje dostępne w programie. Dodatkowo jest również udostępniony interpreter poleceń oraz edytor skryptów. Użytkownik tworzonego skryptu powinien otrzymać narzędzie z przejrzystym interfejsem. System napędowy parowozu jest skomplikowanym układem o wielu ele- mentach. Osoby nie znające dokładnych zależności mogą mieć trudności z tworze- niem animacji. Skrypt ma umożliwiać łatwą edycję tworzonego systemu tak, aby każdy mógł z niego swobodnie korzystać. Rozdział 3. Założenia projektowe 17

3.3. Możliwość korzystania z fotografii

Narzędzie powinno umożliwiać korzystanie z fotografii oraz schematów. Wyma- gana jest metoda ułatwiająca pobieranie z nich potrzebnych proporcji oraz wy- miarów. Dzięki temu nie jest konieczne wcześniejsze wykonywanie dokładnych po- miarów. Takie ułatwienie może znacznie usprawnić tworzenie graficznych modeli rzeczywistych układów.

3.4. Uniwersalność rozwiązania

Dostarczone rozwiązanie powinno umożliwić tworzenie mechanizmów o zróżnico- wanych parametrach. W ramach wybranego do realizacji w pracy układu napędowe- go Walschaertsa-Heusingera istnieje duże zróżnicowanie poszczególnych systemów. Różnice dotyczą między innymi: liczby osi, promieni kół oraz długości i proporcji po- szczególnych elementów. Projekt powinien brać to wszystko pod uwagę i umożliwiać edycję poszczególnych składników napędu. 4. Projekt rozwiązania

4.1. Działanie narzędzia

Zamierzone działanie narzędzia w postaci skryptu zostało przedstawione na ry- sunku 4.1.

Rysunek 4.1. Diagram czynności przy korzystaniu ze skryptu

Najpierw użytkownik uruchamia skrypt. Określa przy tym podstawowe parame- try, takie jak liczba osi, oraz wskazuje koło silnikowe. Skrypt tworzy wtedy podsta- wowe obiekty oraz otwiera okno pomocnicze do dalszych ustawień. Użytkownik z po- mocą utworzonego okna przestawia poszczególne obiekty tak, aby odzwierciedlały proporcje modelowanego mechanizmu. Może przy tym również skorzystać z fotografii lub schematu prawdziwego układu. Rozdział 4. Projekt rozwiązania 19

Po upewnieniu się, że wszystkie elementy znajdują się na odpowiednich miej- scach, użytkownik zatwierdza zmiany uruchomieniem funkcji finalizującej skryptu. Są tworzone wtedy pozostałe obiekty oraz wszystko jest odpowiednio łączone. Po tych zabiegach powstaje gotowy system zależności animowanego układu napędowe- go. Skrypt nie obejmuje już dalszych czynności. Użytkownik może zapisać efekt prac lub dalej go edytować. W celu otrzymania animacji, na posiadany system należy nałożyć przygotowane osobno wizualizacje poszczególnych elementów. Dodatkowo, ponieważ realizowany układ napędowy wy- stępuje w parowozach dwukrotnie, jako lewy i prawy, to należy go skopiować i prze- sunąć o rozstaw kół. Ruch obydwu systemów powinien być przesunięty w fazie, co również należy ustawić. W tym celu należy zaznaczyć obiekt pozorny reprezentujący oś koła silnikowego. Następnie w edytorze krzywych (Curve Editor) trzeba zmienić orientację tego obiektu o 90◦ względem osi Y w pierwszej i ostatniej klatce animacji.

4.2. Podział na podzespoły

Układ napędowy parowozu został podzielony na mniejsze fragmenty — pod- zespoły. Najpierw się je tworzy, a następnie łączy według zależności istniejących w pierwowzorze. Każdy taki podzespół jest osobnym mechanizmem, istotnym dla działania całego układu. Wyodrębnione fragmenty to: — system wiązarów, — układ korbowy, — rozrząd pary, — nastawnik wraz z drągiem stawidłowym, — dźwignia maszynisty. Poniżej są ze sobą zestawione parami rysunki poszczególnych podzespołów (zreali- zowanych za pomocą napisanego narzędzia) ze schematami, na których są zakoloro- wane odpowiadające im fragmenty. Rysunki 4.2 oraz 4.3 przedstawiają system wiązarów. Służą one do przenoszenia napędu z głównego koła, tzw. silnikowego do pozostałych, tzw. wiązanych. Należy zwrócić uwagę na to, że wiązary są połączone z kołami jednakowymi wykorbieniami co do długości i kąta. W środkowym kole połączenie to jest na wspólnej osi z korbo- wodem napędowym. Widoczna zaś oś po jego lewej stronie jest połączeniem dwóch wiązarów.

Rysunek 4.2. Fragment układu napędowego — system wiązarów Rozdział 4. Projekt rozwiązania 20

Rysunek 4.3. Fragment układu napędowego — system wiązarów

Rysunki 4.4 oraz 4.5 przedstawiają układ korbowy wraz z głównym tłokiem. Mechanizm ten służy do przeniesienia posuwisto-zwrotnego ruchu tłoka na ruch obrotowy koła.

Rysunek 4.4. Fragment układu napędowego — układ korbowy

Rysunek 4.5. Fragment układu napędowego — układ korbowy Rozdział 4. Projekt rozwiązania 21

Rysunki 4.6 oraz 4.7 przedstawiają system rozrządu pary.

Rysunek 4.6. Fragment układu napędowego — rozrząd pary

Rysunek 4.7. Fragment układu napędowego — rozrząd pary

Rysunki 4.8 oraz 4.9 przedstawiają nastawnik wraz z drągiem stawidłowym. Elementy te są przeznaczone do sterowania pracą układu rozrządu pary.

Rysunek 4.8. Fragment układu napędowego — nastawnik wraz z drągiem stawidłowym Rozdział 4. Projekt rozwiązania 22

Rysunek 4.9. Fragment układu napędowego — nastawnik wraz z drągiem stawidłowym

Rysunek 4.10. Fragment układu napędowego — dźwignia maszynisty

Rysunek 4.10 nie posiada swojego odpowiednika na schemacie z rysunku 1.2, po- nieważ jest to prosty mechanizm, realizowany na różne sposoby. Przedstawia dźwi- gnię maszynisty, którą może sterować układem rozrządu pary, poprzez wcześniej- szy mechanizm nastawnika wraz z drągiem stawidłowym. Zastosowanie dźwigni jest pewnym uproszczeniem na potrzeby animacji. Zwykle w jego miejscu znajduje się mechanizm śrubowy poruszany korbą lub kołem. Jest on jednak zwykle niewidoczny, przez co nie zawsze istotny dla animacji. Dzięki temu, że element ten jest potrak- towany jako osobny podzespół, gdyby zaszła potrzeba, istnieje możliwość łatwego zastąpienia go dowolnym innym mechanizmem. 5. Opis implementacji

W kolejnych podrozdziałach są przedstawione sposoby rozwiązania poszczegól- nych zagadnień: — sposób łączenia podzespołów, — metody zakończenia podzespołów, — realizacja łuku kulisy, — obliczenie środku okręgu, na którym znajduje się kulisa, — możliwość korzystania z fotografii, — wykorzystane parametry algorytmu kinematyki odwrotnej.

5.1. Łączenie podzespołów

Dużym problemem przy tworzeniu pełnego układu były ograniczenia nałożone przez algorytmy kinematyki odwrotnej (opisane w rozdziale 2.3). Aby rozwiązać ten problem, podzielono układ na kilka mniejszych. Są one następnie ze sobą wiąza- ne (funkcja Bind). Pozwala to na przyczepienie jednego obiektu do drugiego oraz ustawienie wagi połączenia (Weight). Waga połączenia jest tym bardziej istotna im więcej zakończeń ma dany łańcuch. Większa wartość oznacza mocniejsze wiązanie. W razie nieprawidłowego działania układu, w pierwszej kolejności zostaną rozerwa- ne słabsze wiązania. Przy tworzeniu wiązania jest również ustawiane czy wiązanie dotyczy pozycji czy rotacji. Rozróżnienie ich od siebie umożliwia np. tworzenie zwią- zanych punktów o takiej samej pozycji, ale swobodnym obrocie. Ustawienia można stosować w dowolnej kombinacji — sama rotacja, sama pozycja albo obydwa razem. W rzeczywistości jednak elementy oddziałują na siebie w obie strony — gdy jeden ciągnie — to drugi stawia opór. Tutaj natomiast, przy wiązaniu podzespo- łów, powstaje jedynie zależność w jedną, wybraną stronę — obiekt przywiązany nie wpływa na zachowanie tego, do którego jest doczepiony. Poszczególne podzespoły zostały połączone zgodnie z nałożonym ograniczeniem. Głównym elementem nadającym ruch wszystkim pozostałym jest oś koła silnikowe- go. Bezpośrednio do niego są przywiązane: układ korbowy, rozrząd pary oraz system wiązarów. Rozrząd pary jest również przywiązany do układu korbowego (poprzez krzyżulec). Do rozrządu jest przywiązany nastawnik wraz z drągiem stawidłowym. Do niego natomiast, ostatni podzespół — dźwignia maszynisty. Taka kolejność wią- zania pozwala połączyć wszystkie podzespoły w jeden spójny system napędowy.

5.2. Zakończenia podzespołów

Końce niektórych podzespołów: suwak, dźwignia maszynisty oraz osie kół wiąza- nych, nie są wiązane do innych, ponieważ nie istnieją podzespoły, do których można by je przywiązać. Należy je więc zakończyć w inny sposób. W tym celu możliwe jest zastosowanie końcowych efektorów lub wiązań — opisanych poniżej. Rozdział 5. Opis implementacji 24

5.2.1. Końcowy efektor Jedną z metod zakończenia jest stosowanie końcowych efektorów (End Effector). Są one celem kinematyki odwrotnej, czyli punktami obrotu ostatnich węzłów w łań- cuchach. Końcowy efektor algorytmu kinematyki odwrotnej jest przedstawiony w wi- doku, jako różowy krzyżyk. Można je aktywować lub dezaktywować dla dowolnego węzła w ustawieniach Motion/Parameters/IK Controller Parameters/End Effectors. Istnieją dwa rodzaje końcowych efektorów — pozycji oraz rotacji. Pierwszy stosuje się do ustawienia położenia, drugi do obrotu. W modelowanym układzie wszystkie zakończenia wymagałyby końcowych efektorów położenia. Suwak natomiast potrze- bowałby obydwu, aby suwał się tylko wzdłuż jednej z osi. Zaletą ich stosowania jest to, że przy rozszerzeniu właściwości węzłów, do których są przypisane, nie powstają żadne dodatkowe obiekty. Stosowanie końcowych efek- torów jest jednak niewygodne przy przesuwaniu całego utworzonego modelu układu napędowego. Rozwiązanie to wymaga bowiem przesuwania osobno każdego węzła posiadającego końcowy efektor oraz w całości pozostałej części układu.

5.2.2. Wiązania Drugim sposobem na zakończenie wskazanych podzespołów jest użycie wcześniej opisanych wiązań (Bind). Ten sposób został zastosowany w niniejszej pracy. Wyma- ga to wcześniejszego utworzenia w tych miejscach dodatkowych obiektów pozornych, do których będą przywiązane zakończenia. Następnie, tak jak przy łączeniu podze- społów, należy przywiązać końcowe elementy do tych nowo utworzonych. Taki sposób zakończenia poszczególnych nieprzywiązanych końców podzespołów pozwala swobodnie przesuwać cały układ, po zaznaczeniu wszystkich obiektów. Je- żeli użytkownik chce natomiast obrócić układ, to w tym celu należy wcześniej za- znaczyć całość i utworzyć z całego modelu grupę (Group/Group). Dzięki temu przy próbie rotacji wszystkie obiekty będą obracane według jednego punktu obrotu, a nie każdy wokół swojego własnego. Później jeżeli zajdzie potrzeba można z powrotem rozdzielić obiekty (Group/Ungroup).

5.3. Kulisa — realizacja łuku

Kulisa w przeciwieństwie do pozostałych elementów wymagała innego podejścia. W celu zrealizowania jej kształtu, wzdłuż którego może przemieszczać się wodzidło suwaka, został utworzony dodatkowy węzeł. Obiekt ten jest środkiem okręgu, na którym jest położony łuk kulisy. Rozwiązanie jest przedstawione na rysunku 5.1.

Rysunek 5.1. Realizacja łuku kulisy — oś obrotu znajduje się w punkcie A Rozdział 5. Opis implementacji 25

Punkt A jest miejscem przyczepienia kulisy, na którym się ona obraca. Jest poło- żony w okolicach połowy jej długości. Punkt B jest punktem teoretycznym będącym środkiem okręgu, na którym znajduje się łuk kulisy. Przemieszcza się on ruchem wa- hadłowym razem z kulisą w trakcie jej ruchu po łuku względem punktu A. Punkt C jest miejscem chwilowego usytuowania sworznia wodzidła suwaka w prowadnicy kulisy. Strzałki pokazują występujące relacje. Punkt A jest najstarszy. Dzięki temu, że długości |AB| oraz |BC| są stałe — w rezultacie punkt C porusza się po od- powiednim łuku, względem punktu B — czyli wzdłuż kulisy. Nie ma dodatkowych ograniczeń stopni swobody. Takie podejście w pełni oddaje działanie rzeczywistej kulisy. Przy późniejszym nakładaniu obiektów graficznych, w celach wizualizacji, należy pamiętać, że węzeł B jest pomocniczy i nie wymaga graficznej reprezentacji.

5.4. Kulisa — środek okręgu

Jednym z problemów przy modelowaniu rozrządu pary było odtworzenie łuku kulisy. Narzędzie będące wynikiem tej pracy udostępnia dwie metody wyznaczania środka okręgu, na którym się on znajduje. Poprawne odtworzenie tego mechanizmu jest istotne dla sprawnego funkcjonowania całego układu.

5.4.1. Wyznaczenie środka okręgu na podstawie trzech punktów Pierwsza metoda wykorzystuje trzy różne punkty położone na kulisie. W układzie mechanicznym występują tylko dwa specyficzne A i C (rysunek 5.1). Wybieramy więc dodatkowy trzeci punkt należący do łuku kulisy. Mając trzy punkty można wyznaczyć środek okręgu za pomocą wzorów geometrycznych.

Rysunek 5.2. Okrąg z położonymi na nim trzema punktami

Konieczne jest, aby punkty A, B, C (rysunek 5.2), nie leżały na jednej prostej, ponieważ wówczas promień okręgu byłby równy nieskończoności. Nie mogą również się pokrywać (każdy musi mieć inne współrzędne). Środek okręgu przechodzącego przez posiadane trzy punkty można wyznaczyć wykorzystując równanie okręgu:

2 2 2 r = (x − xS) + (y − yS) , (5.1) Rozdział 5. Opis implementacji 26

gdzie: r — promień okręgu; x, y — współrzędne punktu na obwodzie okręgu; xS, yS — współrzędne środka okręgu; Znając współrzędne punktów A, B, C można utworzyć układ równań:

 2 2 2  r = (xA − xS) + (yA − yS)  2 2 2 r = (xB − xS) + (yB − yS) (5.2)  2 2 2  r = (xC − xS) + (yC − yS)

W układzie (5.2) znajdują się trzy niewiadome (r, xS, yS), z czego interesują nas dwie. Po odpowiednim przekształceniu otrzymałem:

2 2 2 2 2 2 2 2 2 2 2 2  1 −yAyB +yAyC +yAxC −yAxB −yB yC −yB xC +yC yB +yC xB −yC yA+yB yA−yC xA+yB xA  xS =  2 yAxC −yAxB −yB xC −yC xA+yC xB +yB xA (5.3) 2 2 2 2 2 2 2 2 2 2 2 2  1 xAxB −xAxC −xAyC +xAyB +xB xC +xB yC −xC xB −xC yB +xC xA−xB xA+xC yA−xB yA  yS = 2 yAxC −yAxB −yB txC −yC xA+yC xB +yB xA Po wyznaczeniu środka okręgu (5.3), dodatkowy punkt staje się zbędny i auto- matycznie zostaje usunięty.

5.4.2. Wyznaczenie środka okręgu na podstawie dwóch punktów oraz promienia Druga metoda wykorzystuje dwa różne punkty położone na kulisie oraz promień okręgu. Jak już była mowa w poprzednim podrozdziale — w układzie mechanicz- nym występują już dwa specyficzne punkty — A i C, co pokazano na rysunku 5.1. Promień natomiast jest podawany przez użytkownika.

Rysunek 5.3. Wyznaczanie środka okręgu na podstawie dwóch punktów i promienia

Rozwiązywany problem jest przedstawiony na rysunku 5.3. Odcinek |AB| posia- da symetralną przechodzącą przez trzy pozostałe punkty: S1,C,S2. Znając położenie punktów A i B oraz długość promienia r, można obliczyć położenie obydwu środków okręgów, z pomocą algebry wektorów. Rozwiązanie wymaga kolejnych kroków: Znalezienie odległości między dwoma punktami i przypisanie jej do zmiennej q: q 2 2 q = (xB − xA) + (yB − yA) , (5.4) Rozdział 5. Opis implementacji 27

Obliczenie współrzędnych punktu C, położonego w połowie odcinka |AB|:

( xA+xB xC = 2 yA+yB (5.5) yC = 2

Wyznaczenie wektora przesunięcia między punktami A oraz B:

~ AB = (xA − xB, yA − yB) (5.6)

Wektor przesunięcia znajdujący się na symetralnej można uzyskać poprzez za- mianę składowych oraz zmianę znaku na przeciwny jednego z nich:

(yA − yB, xB − xA) (5.7)

Następnie otrzymany wektor jest normalizowany, co oznacza, że jego długość ma być równa 1. Można to uzyskać poprzez podzielenie obydwu jego składowych ((yA − yB) oraz (xB − xA)) przez wartość q. Obydwa środki kół znajdują się na symetralnej i można znaleźć, jak daleko znaj- dują się od punktu C (xC , yC ). Odległość od punktu C jest taka sama zarówno do punktu A, jak i B, i wynosi połowę długości q. Odległość do przesunięcia po symetralnej można wyznaczyć z twierdzenia Pitagorasa:

s  q 2 r2 − (5.8) 2

Aby otrzymać środek okręgu należy przesunąć się po symetralnej w jedną lub w drugą stronę:  r  2  2 q yA−yB  xS1 = xC + r − · 2 q (5.9) r  2  2 q xB −xA  yS1 = yC + r − 2 · q

 r  2  2 q yA−yB  xS2 = xC − r − · 2 q (5.10) r  2  2 q xB −xA  yS2 = yC − r − 2 · q Pozostaje tylko podstawić do wzorów wyprowadzoną wcześniej wartość q:

 s √ 2   (x −x )2+(y −y )2   x = x + r2 − B A B A · √ yA−yB  S1 C 2 2 2  (xB −xA) +(yB −yA) s √ 2 (5.11)   (x −x )2+(y −y )2   y = y + r2 − B A B A · √ xB −xA  S1 C 2 2 2  (xB −xA) +(yB −yA)

 s √ 2   (x −x )2+(y −y )2   x = x − r2 − B A B A · √ yA−yB  S2 C 2 2 2  (xB −xA) +(yB −yA) s √ 2 (5.12)   (x −x )2+(y −y )2   y = y − r2 − B A B A · √ xB −xA  S2 C 2 2 2  (xB −xA) +(yB −yA)

Po obliczeniu położenia obydwu środków (5.11 oraz 5.12), wybierany jest ten, który ma większą wartość x — czyli jest położony od strony tłoków. Rozdział 5. Opis implementacji 28

5.5. Możliwość korzystania z fotografii

Jedną z większych dogodności przy tworzeniu animacji układu napędowego jest możliwość korzystania ze schematów i fotografii prawdziwych układów napędowych. Jeżeli stosowana jest fotografia, to należy pamiętać, że powinna być zrobiona pro- stopadle do układu napędowego oraz z odpowiednio dużej odległości, aby otrzyma- ny obraz był jak najlepszym przybliżeniem rzutu prostokątnego. Jest to istotne ze względu na to, że mechanizmy napędowe parowozu nie leżą w jednej płaszczyźnie. Ich wzajemne ułożenie zmienia się w zależności od kąta patrzenia.

Rysunek 5.4. Przykład zniekształcenia perspektywicznego

Rysunek 5.5. Przykładowa fotografia układu napędowego parowozu

Kiedy obiekt jest uchwycony ze zbyt małej odległości, wtedy powstają znie- kształcenia perspektywiczne, które są widoczne głównie z lewej i prawej strony. Przy układach napędowych parowozów, najlepiej jest to widoczne na podkładach. Przy rzucie prostopadłym powinno być widać jedynie ich czoła. Na fotografii jest tak jednak jedynie pośrodku kadru (rysunek 5.4). Im fotografia jest robiona z dalszej Rozdział 5. Opis implementacji 29 odległości, tym linie łączące skrajne punkty obiektu z obiektywem są mniej roz- bieżne. Z tego powodu najkorzystniej jest fotografować, z jak największej odległości z użyciem obiektywu przybliżającego. Z różnych względów jest to często niemożli- we. Warto również pamiętać o tym, że podczas fotografowania z dużych odległości trudno uzyskać ostry obraz, gdyż nawet małe drgnięcie aparatu daje niekorzystne efekty. Należy więc posługiwać się statywem. Posiadany obraz (przykładowy na ry- sunku 5.5 dobrze jest też przyciąć tak, aby obejmował jedynie istotny w ramach animacji fragment — tak, jak na rysunku 5.6.

Rysunek 5.6. Przykładowa fotografia układu napędowego parowozu po odpowiednim skadrowaniu

Następnie należy zdecydować, w jaki sposób skorzystamy z fotografii. W kolej- nych podrozdziałach przedstawiam dwie metody pozwalające na ich wykorzystanie w celu utworzenia realistycznej animacji układu napędowego.

5.5.1. Ustawienie tapety

Rysunek 5.7. Ustawienia tapety Rozdział 5. Opis implementacji 30

Pierwszą możliwością jest ustawienie obrazu, jako tapety w wykorzystywanym widoku programu. Aby tego dokonać należy wejść w ustawienia tapety (Views/View- port Background/Viewport Background...). W otwartym oknie należy ustawić odpo- wiednie opcje (rysunek 5.7). Trzeba zaznaczyć, że tapeta ma zachowywać proporcje używanego pliku (Aspect Ratio/Match Bitmap) oraz zablokować jej rozmiar i po- zycję (Lock Zoom/Pan). Dzięki temu powiększanie, zmniejszanie ani przesuwanie okna widoku nie będzie miało na nie wpływu. Trzeba jeszcze wskazać plik z foto- grafią z komputera, którą chcemy umieścić na tapecie (Background Source/Files...). Pozostałe ustawienia należy pozostawić bez zmian.

Rysunek 5.8. Ustawienie punktów z pomocą fotografii użytej jako tapety

Rysunek 5.9. Otrzymany układ po wyłączeniu tapety

Po zatwierdzeniu zmian i odpowiednim ustawieniu używanego widoku, nale- ży zresetować ustawienia tapety (Views/Viewport Background/Reset Background Transform). Zabieg ten dopasuje tapetę do aktualnego widoku. Tak przygotowane tło umożliwia łatwe pobranie wszystkich proporcji potrzebnych do prawidłowego działania układu. Czynność ta polega na przeniesieniu kolejno, wszystkich punktów na poszczególne elementy widoczne na fotografii. Przykład zastosowania opisanej metody przedstawiony jest na rysunkach 5.8 oraz 5.9. Gdy tapeta przestanie być niezbędna, można ją wyłączyć (Views/ Viewport Background/Show Background). Rozdział 5. Opis implementacji 31

5.5.2. Nałożenie tekstury Innym sposobem na wykorzystanie fotografii jest utworzenie dodatkowego obiek- tu w formie płaszczyzny (Plane) i nałożenie na nią obrazu jako tekstury. W tym celu utworzonej płaszczyźnie trzeba przypisać teksturę bitmapową z fotografią układu. Trzeba również ustawić odpowiednie proporcje, by fotografia nie była rozciągnięta wzdłuż którejś z osi. Można to osiągnąć przez nałożenie na obiekt odpowiedniego modyfikatora, np. UVW Map. Trzeba jeszcze odpowiednio zmienić jego ustawienia, takie jak: płaszczyzna wy- świetlania oraz sposób rozciągnięcia obrazu. Takie rozwiązanie pozwala na dokład- niejsze ustawienie wielkości obrazu. Można wcześniej wstępnie obliczyć wielkości fotografii oraz pewnych elementów, aby później utworzyć odpowiedniej wielkości obiekt do teksturowania. Dzięki temu można z obrazu odczytać rzeczywiste wy- miary dowolnego elementu. Modelowanie z wykorzystaniem rzeczywistych jednostek długości jest wspomagane przez program 3ds Max. Należy oczywiście pamiętać, by zarówno w obliczeniach, jak i na obrazie stosować te same jednostki długości.

5.6. Parametry algorytmu kinematyki odwrotnej

Po utworzeniu systemu stosującego algorytm kinematyki odwrotnej, należy nadać mu odpowiednie ustawienia, charakterystyczne dla odtwarzanego układu. W tym celu poniżej opisano dostępne opcje. Większość ustawień dokonywana jest w zakładce Hierarchy/IK. Przykładowe okno przedstawione jest na rysunku 5.10. W ramach zastosowanego rozwiązania istotna jest tylko część dostępnych opcji.

Rysunek 5.10. Ustawienia węzła łańcucha IK - zakładka Hierarchy Rozdział 5. Opis implementacji 32

W drugiej kolumnie widoczna jest opcja Bind. Służy ona do wiązania obiektów. Jej zastosowanie zostało opisane w rozdziałach 5.1 oraz 5.2.2. Po użyciu Bind To Follow Object, należy jeszcze zaznaczyć pola Bind Position albo Bind Orientation, zależnie od tego, które parametry chcemy powiązać. Dodatkowo, gdy łańcuch posia- da rozgałęzienia, to warto czasem zwiększyć wartości Weight. Dzięki temu obiekty przywiązywane będą mocniej przylegać do wskazanych obiektów. Kolejne dwie kolumny służą do zarządzania ustawieniami poszczególnych węzłów w łańcuchu kinematyki odwrotnej. Poprzez zaznaczenie pola Active, można wskazać zachowanie względem starszego węzła. Sliding Joints umożliwiają zmianę odległości między nimi wzdłuż danej osi. Opcja Rotational Joints umożliwia zablokowanie albo odblokowanie obrotu danego węzła.

Rysunek 5.11. Ustawienia łańcucha IK — zakładka Motion

Poprzednie ustawienia dotyczyły jednego, wskazanego węzła. W zakładce Motio- n/Parameters dostępne są opcje odnoszące się również do całego łańcucha kinematy- ki odwrotnej. Niezależnie, który element zostanie zaznaczony, to zmiana niektórych ustawień będzie dotyczyła całego systemu. Część istotnych parametrów jest przed- stawionych na rysunku 5.11. Parametry Thresholds (Position oraz Rotation) okre- ślają próg drgania pozycji lub obrotu. Im są bliższe zeru, tym ustawienie jest dokład- niejsze. W całej pracy są one zerowane, ponieważ inne wartości powodują drgania w miejscach połączeń podzespołów. Niżej w ramce Solution zebrane są parametry określające, w których ramkach animacja układu jest aktywna oraz dokładność ob- liczeń algorytmu kinematyki odwrotnej. Ważna jest zmiana ustawienia Iterations na większą wartość niż domyślna (20), aby algorytm kinematyki odwrotnej obliczył zmiany więcej razy. Dzięki temu ruch układu będzie dokładniejszy i płynniejszy. 6. Opis wyników weryfikacji opracowanego rozwiązania

Poprawność działania skryptu została przetestowana poprzez wykonanie serii różnych układów napędowych. Otrzymane animacje porównywane były z dostępny- mi w Internecie filmami, na których modelowane typy parowozów zarejestrowane są w trakcie jazdy. Analiza otrzymanych mechanizmów wykazała, że działają one poprawnie i animacja w pełni oddaje ruch rzeczywistych elementów. Z przeprowa- dzonych testów przedstawione są na rysunkach poszczególne fazy ruchu modelów co 45◦ obrotu koła silnikowego.

6.1. Modelowanie parowozu TKh1-191

Pierwszym parowozem wybranym do testów jest parowóz TKh1-191. Obecnie jest eksponatem w skansenie w Chabówce. Jest to parowóz normalnotorowy i posiada trzy osie napędzające. Osią silnikową jest oś druga. W parowozie tym aby realizować jazdę do przodu wodzidło suwaka musi być przesunięte nad oś kulisy.

Rysunek 6.1. Fotografia parowozu TKh1-191 Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 34

Rysunek 6.2. Model utworzony na tle fotografii — TKh1-191

Rysunek 6.3. Zdjęcia po klatkowe TKh1-191 — jazda do przodu (cały obrót koła) Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 35

Rysunek 6.4. Zdjęcia po klatkowe TKh1-191 — jazda do tyłu (pół obrotu koła)

Rysunek 6.5. Zdjęcia po klatkowe TKh1-191 — jazda rozpędem do przodu (pół obrotu koła)

W każdym z trzech testowanych animacji wszystkie elementy poruszały się zgod- nie z przewidywanym dla nich zakresem ruchu. W żadnym połączeniu nie następo- wało rozrywanie, drganie ani chwilowe przesunięcia. Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 36

6.2. Modelowanie parowozu Las47

Drugim parowozem wybranym do testów jest parowóz Las47. Obecnie jest eks- ponatem w skansenie w Chabówce. Jest to parowóz wąskotorowy i posiada trzy osie napędzające. Osią silnikową jest oś trzecia. Na uwagę zasługuje nietypowa konstruk- cja wodzidła suwaka, gdyż łącznik wodzidła znajduje się nie za, ale przed suwakiem. Aby realizować jazdę do przodu, wodzidło suwaka musi być przesunięte poniżej osi kulisy.

Rysunek 6.6. Fotografia parowozu Las47

Rysunek 6.7. Model utworzony na tle fotografii — Las47 Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 37

Rysunek 6.8. Zdjęcia po klatkowe Las47 — jazda do przodu (cały obrót koła)

Rysunek 6.9. Zdjęcia po klatkowe Las47 — jazda do tyłu (pół obrotu koła) Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 38

Rysunek 6.10. Zdjęcia po klatkowe Las47 — jazda rozpędem do przodu (pół obrotu koła)

Również i w tym przypadku model zachowywał się za każdym razem prawidłowo. Nie zauważono żadnych drgań ani przesunięć w połączeniach.

6.3. Modelowanie parowozu Ty2-50

Trzecim parowozem wybranym do testów jest parowóz Ty2-50. Obecnie jest eks- ponatem w skansenie w Chabówce. Jest to parowóz normalnotorowy i posiada pięć osi napędzających. Osią silnikową jest oś trzecia. Aby realizować jazdę do przodu, wodzidło suwaka musi być przesunięte poniżej osi kulisy.

Rysunek 6.11. Fotografia parowozu Ty2-50 Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 39

Rysunek 6.12. Model utworzony na tle fotografii — Ty2-50

Rysunek 6.13. Zdjęcia po klatkowe Ty2-50 — jazda do przodu (cały obrót koła) Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 40

Rysunek 6.14. Zdjęcia po klatkowe Ty2-50 — jazda do tyłu (pół obrotu koła)

Rysunek 6.15. Zdjęcia po klatkowe Ty2-50 — jazda rozpędem do przodu (pół obrotu koła)

Tak jak w poprzednich dwóch testowanych modelach i w tym modelu nie stwier- dzono żadnych nieprawidłowości. Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 41

6.4. Modelowanie parowozu Ty51-137

Czwartym parowozem wybranym do testów jest parowóz Ty51-137. Obecnie jest eksponatem w skansenie w Chabówce. Jest to parowóz normalnotorowy i posiada pięć osi napędzających. Osią silnikową jest oś trzecia. Aby realizować jazdę do przo- du, wodzidło suwaka musi być przesunięte poniżej osi kulisy.

Rysunek 6.16. Fotografia parowozu Ty51-137

Rysunek 6.17. Model utworzony na tle fotografii — Ty51-137 Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 42

Rysunek 6.18. Zdjęcia po klatkowe Ty51-137 — jazda do przodu (cały obrót koła) Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 43

Rysunek 6.19. Zdjęcia po klatkowe Ty51-137 — jazda do tyłu (cały obrót koła) Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 44

Rysunek 6.20. Zdjęcia po klatkowe Ty51-137 — jazda rozpędem do przodu (cały obrót koła)

Rysunek 6.21. Zbliżenie przedstawiające występujące błędy

Rysunek 6.21 jest powiększonym wycinkiem zdjęcia zarejestrowanego pomiędzy czwartym a piątym zdjęciem po klatkowym z rysunku 6.19. Widoczne są błędy w postaci: wyjścia poza zakres działania kulisy, drgania i nietrzymania poziomu su- waka, rozrywania wiązań korby z drążkiem mimośrodowym oraz rozrywania wiązań Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 45

łącznika wodzidła z nastawnikiem. Analogiczne błędy wystąpiły w ruchu do przodu (rysunek 6.18) i przy jeździe rozpędem (rysunek 6.20). Przyczyną jest to, że użyta do zbudowania tego modelu fotografia nie spełnia wymagań stawianych w rozdziale 5.5. Nie jest zrobiona prostopadle do parowozu. W efekcie tego oraz przestrzennej budowy rzeczywistych mechanizmów, odwzorowane wzajemne wymiary elementów są obarczone różnymi błędami.

6.5. Opis wizualizacji realistycznej parowozu TKh1-191

Do zrealizowania wizualizacji wybrałem pierwszy z testowanych parowozów — TKh1-191. Przeprowadzone wcześniej testy wykazały, że wymodelowany mechanizm działa poprawnie. Proces tworzenia animacji polega na utworzeniu wizualizacji wszystkich elemen- tów i ich podpięciu do przygotowanego wcześniej mechanizmu napędowego ogranicz- nikiem Link. Czynności te wykonywane są na podstawie zdjęć, schematów i filmów z danym modelem lokomotywy. Po utworzeniu prawej strony parowozu wystarczy skopiować ją względem osi symetrii parowozu aby otrzymać całą lokomotywę. Sto- suje się do tego przyrząd lustrzanego odbicia (Mirror). Otrzymane odbicie układu posiada wszystkie wartości Weight ustawione na domyślne, czyli na 1. Aby skopio- wany napęd działał poprawnie, trzeba ręcznie ustawić te wartości we wszystkich zakończeniach podzespołów tak jak w oryginale. Na rysunku 6.22 widoczna jest wizualizacja parowozu TKh1-191, zrealizowana na podstawie fotografii 6.1. Poniższe rysunki: 6.23, 6.24, 6.25, przedstawiają kolejno jazdę do przodu, do tyłu oraz rozpędem do przodu.

Rysunek 6.22. Wizualizacja parowozu TKh1-191 Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 46

Rysunek 6.23. Zdjęcia po klatkowe wizualizacji TKh1-191 — jazda do przodu (cały obrót koła)

Rysunek 6.24. Zdjęcia po klatkowe wizualizacji TKh1-191 — jazda do tyłu (pół obrotu koła) Rozdział 6. Opis wyników weryfikacji opracowanego rozwiązania 47

Rysunek 6.25. Zdjęcia po klatkowe wizualizacji TKh1-191 — jazda rozpędem do przodu (pół obrotu koła)

Przygotowana wizualizacja, widoczna na rysunkach: 6.22, 6.23, 6.24, 6.25, nie jest wiernym odtworzeniem rzeczywistego układu. Istnieje wiele elementów, które nie zostały zrealizowane. Zależnie od dostępnego czasu oraz zdolności animatora można otrzymać bardziej realistyczny efekt.

6.6. Wnioski

Pewnym utrudnieniem przy korzystaniu ze skryptu wraz z fotografią układu napędowego ustawioną na tapecie, jest fakt, że nie wszystkie elementy są zawsze widoczne. Zdarza się, że ich część jest schowana. Zazwyczaj są to mniej skompliko- wane fragmenty, jak na przykład sterujące rozrządem pary. Należy je wtedy ustawić zgodnie z własną intuicją. Można się przy tym posiłkować dodatkowymi fotografiami. Testy zostały przeprowadzone z użyciem różnych fotografii układów napędowych. Otrzymane mechanizmy nieznacznie się od siebie różnią. Ich działanie jest jednak poprawne. Ruch poszczególnych elementów jest płynny i zgodny z rzeczywistym. Błędne działanie można było jedynie zaobserwować, jeżeli fotografia, z której by- ły pobierane proporcje, była źle zrobiona. Powstają wtedy naruszenia istniejących ograniczeń, co powoduje rozrywanie podzespołów oraz chaotyczne przeskakiwanie niektórych elementów w trakcie animacji. Jeżeli jedno z wymagań dotyczących przy- gotowania poprawnej fotografii zostanie pominięte, to mogą się pojawić złe proporcje istotnych elementów. W przypadku, gdy wskazania są wypełnione, to skrypt działa poprawnie, generując sprawne systemy napędowe. 7. Podsumowanie

Stworzone w ramach niniejszej pracy narzędzie zrealizowało postawione począt- kowo cele. Może być pomocne przy tworzeniu animacji układów napędowych paro- wozów. Korzystanie z niego jest stosunkowo proste. Istnieje szereg możliwości dalszego rozwijania narzędzia. Obecnie jest ono przygotowane do tworzenia animacji układu napędowego parowozu z systemem Walschaertsa-Heusingera gdyż system ten był najbardziej rozpowszechniony w Pol- sce i na świecie. Istnieje jednak wiele innych rozwiązań technicznych, do których w celu animacji ten skrypt należałoby dostosować, np. system Kuhna posiadający inne rozwiązanie nastawnika albo systemy sprzężone zaprojektowane na większą liczbę cylindrów. Oprócz parowozów, można również realizować animację innych maszyn parowych posiadających podobne mechanizmy, np. maszyn napędzających windy górnicze. Kolejnym rozszerzeniem mógłby być wybór pomiędzy metodami realizacji ukła- dów - kinematyka odwrotna (system kości), wykorzystanie ograniczników lub opis ruchu z pomocą równań matematycznych. W niektórych przypadkach może się oka- zać, że jedna z nich będzie jednak wygodniejsza do zastosowania. Dużym udogodnieniem dla osób słabiej znających się na grafice trójwymiarowej byłoby dodanie szablonowych elementów w celach wizualizacji. Dzięki nim utworze- nie pełnej animacji układu okazałoby się znacznie szybsze. Obecnie przyjęte rozwią- zanie, dzięki realizacji tylko w dwóch wymiarach, dodaje układowi przejrzystości. Animator jednak sam musi pamiętać podczas nakładania składników do wizualizacji o odpowiednim przesunięciu w trzecim wymiarze, tak aby elementy nie nachodziły na siebie. Skrypt mógłby uwzględniać to przesunięcie, dzięki czemu dalsze czynności byłyby łatwiejsze. Otrzymana praca umożliwiła częściową automatyzację powstawania animacji układu napędowego w parowozach. Utworzenie układu napędowego bez opisywanego narzędzia jest nieporównywalnie trudniejsze. Jest jednak wiele możliwości rozwinię- cia tego narzędzia. Bibliografia

[1] Kolej Żelazna Epoki Pary i jej modele w skali TT (1:120). Strona internetowa, 2012. http://www.wokulski.one.pl/tt/index.htm [dostęp: 2012-01-24]. [2] W. P. James. Locomotive Engineman’s Manual: The Classic Locomotive Text From 1919. W. P. James Publishing Company, 1919. Fragment dostępny: http://www. amazon.com/gp/reader/1935327828/ref=sib_dp_pt#reader-link. [3] Kelly L. Murdock. 3ds Max 2011 Bible. John Wiley & Sons, 2011. [4] Joanna Pasek. 3ds max 9. Animacja 3D od podstaw. Helion, 2007. [5] Alan J. Goldfinch Peter William Brett Semmens. How steam really work. Oxford University Press, 2003. Fragment dostępny: http://www.amazon.com/gp/ reader/0198607822/ref=sib_dp_pt#reader-link. [6] Angus Sinclair. The Operation of Steam Locomotives: Locomotive Engine Run- ning and Management. Salzwasser-Verlag, 2010. Fragment dostępny: http://www. amazon.com/gp/reader/3861953439/ref=sib_dp_pt#reader-link. [7] Charles Augustus Smith. Steam Using: Or, Practice. Nabu Press, 2010. Fragment dostępny: http://www.amazon.com/gp/reader/1146356420/ref= sib_dp_pt#reader-link. [8] Hipolit Sobolewski. Trakcja elektryczna, spalinowa i parowa (Własności, wyznaczanie charakterystyk pociągowych). Wydawnictwa Politechniki Warszawskiej, 1963. [9] Parowozy w Polsce. Strona internetowa, 2012. http://parowozy.net/ [dostęp: 2012-01-24]. [10] The Free Encyclopedia Wikipedia. Steam locomotive. Strona internetowa, 2012. http://en.wikipedia.org/wiki/Steam_locomotive [dostęp: 2012-01-24]. [11] Wolna Encyklopedia Wikipedia. Parowóz. Strona internetowa, 2012. http://pl. wikipedia.org/wiki/Parowóz [dostęp: 2012-01-24]. Spis rysunków

1.1 Układ korbowy ...... 6 1.2 Mechanizm napędowy i parorozdzielczy Rysunek na podstawie grafiki ze strony http://pl.wikipedia.org/wiki/Parowóz ...... 7 1.3 Schematy silnika parowego ...... 8

2.1 Układ korbowy w podejściu matematycznym ...... 10 2.2 Układ korbowy zbudowany przy użyciu ogranicznika LookAt ...... 12 2.3 Różnice wynikające z prędkości suwaka ...... 12 2.4 Przykład prostego systemu kości wraz z nazwami ...... 13 2.5 Prezentacja kości z różnymi algorytmami kinematyki odwrotnej. Kolejno od góry: HI, Limb, Spline, HD ...... 14 2.6 Obiekty typu Dummy przed zastosowaniem algorytmu kinematyki odwrotnej . 15 2.7 Obiekty typu Dummy z zastosowanym algorytmem HD kinematyki odwrotnej 15

4.1 Diagram czynności przy korzystaniu ze skryptu ...... 18 4.2 Fragment układu napędowego — system wiązarów ...... 19 4.3 Fragment układu napędowego — system wiązarów ...... 20 4.4 Fragment układu napędowego — układ korbowy ...... 20 4.5 Fragment układu napędowego — układ korbowy ...... 20 4.6 Fragment układu napędowego — rozrząd pary ...... 21 4.7 Fragment układu napędowego — rozrząd pary ...... 21 4.8 Fragment układu napędowego — nastawnik wraz z drągiem stawidłowym . . . 21 4.9 Fragment układu napędowego — nastawnik wraz z drągiem stawidłowym . . . 22 4.10 Fragment układu napędowego — dźwignia maszynisty ...... 22

5.1 Realizacja łuku kulisy — oś obrotu znajduje się w punkcie A ...... 24 5.2 Okrąg z położonymi na nim trzema punktami ...... 25 5.3 Wyznaczanie środka okręgu na podstawie dwóch punktów i promienia . . . . . 26 5.4 Przykład zniekształcenia perspektywicznego ...... 28 5.5 Przykładowa fotografia układu napędowego parowozu ...... 28 5.6 Przykładowa fotografia układu napędowego parowozu po odpowiednim skadrowaniu ...... 29 5.7 Ustawienia tapety ...... 29 5.8 Ustawienie punktów z pomocą fotografii użytej jako tapety ...... 30 5.9 Otrzymany układ po wyłączeniu tapety ...... 30 5.10 Ustawienia węzła łańcucha IK - zakładka Hierarchy ...... 31 5.11 Ustawienia łańcucha IK — zakładka Motion ...... 32

6.1 Fotografia parowozu TKh1-191 ...... 33 6.2 Model utworzony na tle fotografii — TKh1-191 ...... 34 6.3 Zdjęcia po klatkowe TKh1-191 — jazda do przodu (cały obrót koła) ...... 34 6.4 Zdjęcia po klatkowe TKh1-191 — jazda do tyłu (pół obrotu koła) ...... 35 6.5 Zdjęcia po klatkowe TKh1-191 — jazda rozpędem do przodu (pół obrotu koła) 35 6.6 Fotografia parowozu Las47 ...... 36 6.7 Model utworzony na tle fotografii — Las47 ...... 36 6.8 Zdjęcia po klatkowe Las47 — jazda do przodu (cały obrót koła) ...... 37 6.9 Zdjęcia po klatkowe Las47 — jazda do tyłu (pół obrotu koła) ...... 37 Spis rysunków 51

6.10 Zdjęcia po klatkowe Las47 — jazda rozpędem do przodu (pół obrotu koła) . . 38 6.11 Fotografia parowozu Ty2-50 ...... 38 6.12 Model utworzony na tle fotografii — Ty2-50 ...... 39 6.13 Zdjęcia po klatkowe Ty2-50 — jazda do przodu (cały obrót koła) ...... 39 6.14 Zdjęcia po klatkowe Ty2-50 — jazda do tyłu (pół obrotu koła) ...... 40 6.15 Zdjęcia po klatkowe Ty2-50 — jazda rozpędem do przodu (pół obrotu koła) . . 40 6.16 Fotografia parowozu Ty51-137 ...... 41 6.17 Model utworzony na tle fotografii — Ty51-137 ...... 41 6.18 Zdjęcia po klatkowe Ty51-137 — jazda do przodu (cały obrót koła) ...... 42 6.19 Zdjęcia po klatkowe Ty51-137 — jazda do tyłu (cały obrót koła) ...... 43 6.20 Zdjęcia po klatkowe Ty51-137 — jazda rozpędem do przodu (cały obrót koła) 44 6.21 Zbliżenie przedstawiające występujące błędy ...... 44 6.22 Wizualizacja parowozu TKh1-191 ...... 45 6.23 Zdjęcia po klatkowe wizualizacji TKh1-191 — jazda do przodu (cały obrót koła) 46 6.24 Zdjęcia po klatkowe wizualizacji TKh1-191 — jazda do tyłu (pół obrotu koła) 46 6.25 Zdjęcia po klatkowe wizualizacji TKh1-191 — jazda rozpędem do przodu (pół obrotu koła) ...... 47

A.1 Okno główne ...... 53 A.2 Okno pomocnicze ...... 54 Dodatki

Dodatek A. Dokumentacja techniczna

A.1. Wykaz głównych funkcji i złożonych obiektów utility steamLocomotive ”Steam locomotive” — główna roleta narzędzia; rollout locomotiveHelper ”STEAM LOCOMOTIVE - HELP WINDOW” — główna roleta okna pomocniczego, zawiera interfejs użyteczny przy edycji uproszczonego modelu układu — pozwala zaznaczyć dowolny obiekt pomocniczy; rollout locomotiveHelperButtons1 ”Choose :” — element okna pomocniczego — roleta pozwalająca na zaznaczenie dowolnego obiektu pozor- nego, będącym osią któregoś z kół; rollout locomotiveHelperButtons2 ”Arc of the slider:” — element okna po- mocniczego — roleta udostępniająca funkcję ustawiającą środek okręgu, na któ- rym znajduje się łuk kulisy, na podstawie trzech punktów; rollout locomotiveHelperButtons3 ”Radius of the slider:” — element okna pomocniczego — roleta udostępniająca funkcję ustawiającą środek okręgu, na którym znajduje się łuk kulisy, na podstawie dwóch punktów i promienia; rollout locomotiveHelperButtons4 ”Other:” — element okna pomocniczego — roleta zawierająca funkcjonalności pominięte w poprzednich (wyrównanie osi kół, zmiana jednostek pracy, finalizacja modelu oraz zamknięcie okna); fn starting — funkcja tworząca niepełny, uproszczony model układu, który można swobodnie edytować; fn openHelper — funkcja otwierająca w widoku pomocnicze okno; fn finishing — funkcja finalizująca edycję uproszczonego układu i modyfikująca go na w pełni sprawny oraz ostateczny model.

Obiekty pomocnicze (Dummy), z których jest zbudowany cały model, są ze sobą połączone w sposób przypominający strukturę drzewa. W związku z tym są odpo- wiednio nazwane, aby oddać tę strukturę. Przykładowa nazwa to two 5 — oznacza ona, że obiekt znajduje się na drugiej gałęzi drzewa i jest piąty licząc od korzenia.

A.2. Instrukcja obsługi

A.2.1. Instalacja Instalacja skryptu polega na skopiowaniu jego plików do odpowiedniego katalogu programu 3ds Max (.../scripts/startup/ ). W ten sposób będzie on kompilowany przy każdym uruchomieniu programu i gotowy do użycia. Należy postąpić tak, gdy chcemy wielokrotnie uruchamiać program. Druga metoda jest zalecana, gdy narzędzie ma być wykorzystane jednorazowo. Wymaga uruchomienia w 3ds Max edytora języka skryptowego (MAXScript/MA- XScript Editor...) i wciągnięcia do niego pliku z kodem. Po skompilowaniu (Tools/ Dodatki 53

Evaluate All albo Ctrl+E), skrypt jest zainstalowany w aktualnej sesji 3ds Max i go- towy do użycia. Metoda ta wymaga powtórzenia opisanych czynności przy każdym ponownym uruchomieniu programu.

A.2.2. Obsługa Aby skorzystać ze skryptu należy otworzyć roletę języka skryptowego (Utilities/ Utilities/MAXScript). W otwartym oknie (MAXScript), trzeba z rozwijanej listy (Utilities), wybrać nazwę uruchamianego narzędzia (Steam locomotive). Zostanie otwarte okno skryptu (rysunek A.1) — można przejść do jego wykorzystania.

Rysunek A.1. Okno główne

Przed wykorzystaniem narzędzia, użytkownik powinien zadbać o odpowiednie przygotowanie sceny. Skrypt generuje wiele obiektów i operuje na nich poprzez ich nazwy, więc aby nie zaszły żadne konflikty, najlepiej jest otworzyć nowy projekt. Układ jest modelowany w jednej płaszczyźnie i jest najlepiej dostosowany do wyko- rzystania przedniego widoku (front view). Po zakończeniu przygotowań, użytkownik określa w oknie narzędzia, ile osi ma posiadać modelowany napęd ( number) oraz, które koło jest główne (Main wheel). Istnieje ograniczenie ilości osi do pięciu. Po ustawieniu powyższych parame- trów należy zatwierdzić przyciskiem START. Skrypt wygeneruje następnie uprosz- czony model układu napędowego parowozu składający się z odpowiednio połączo- nych obiektów pomocniczych, po czym otworzy okno pomocnicze. Po zamknięciu okna pomocniczego, zawsze można je otworzyć ponownie przyciskiem HELP WIN- DOW. Użytkownik może swobodnie przesuwać wszystkie obiekty pomocnicze. Jeżeli chce wspomóc się fotografią może skorzystać z metod opisanych w rozdziale 5.5. Dodatki 54

Okno pomocnicze ułatwia modyfikowanie układu do własnych potrzeb. Jest w nim schemat napędu z okienkami pozwalającymi na zaznaczenie i odpowiednie przesu- nięcie dowolnego obiektu pomocniczego. Po prawej stronie są cztery rolety z różnymi funkcjonalnościami:

Rysunek A.2. Okno pomocnicze

— Choose wheel axle — pozwala na zaznaczenie obiektu pomocniczego dowolnej osi koła; — Arc of the slider — służy do ustawienia środka okręgu, na którym znajduje się kulisa, na podstawie trzech punktów; – Create help point — tworzy dodatkowy obiekt pomocniczy, będący trzecim brakującym punktem na łuku kulisy; – Select help point — zaznacza utworzony wyższym przyciskiem obiekt. Moż- na go teraz odpowiednio przesunąc by znajdował się na łuku kulisy; – Move circle’s center — oblicza położenie i ustawia środek okręgu; — Radius of the slider — służy do ustawienia środka okręgu, na którym znajduje się kulisa, na podstawie dwóch punktów i promienia podanego przez użytkownika; – Radius — ustawiana przez użytkownika długość promienia; – Move circle’s center — oblicza położenie i przesuwa środek okręgu; — Other — zawiera pozostałe funkcjonalności nie zawarte w poprzednich roletach; – Align wheel to main — wyrównuje wszystkie osie kół poziomu osi silnikowej; – Change units to in/cm — zmienia jednostki ze standardowych cali na centymetry i w drugą stronę; – FINISH — finalizuje model; – CLOSE — zamyka okno pomocnicze. Po tym jak użytkownik odpowiednio ustawi wszystkie obiekty pomocnicze, za- twierdza zmiany przyciskiem FINISH (przycisk ten znajduje się zarówno w oknie pomocniczym, jak i w głównym oknie). Dodatki 55

Dodatek B. Układ napędowy parowozu w ujęciu historycznym

Kluczowym elementem różniącym poszczególne układy napędowe jest system rozrządu pary nazywany również stawidłem albo mechanizmem parorozdzielczym. Steruje ilością oraz prędkością wpuszczanej i wypuszczanej pary z cylindrów silnika parowego. Przez lata powstawało wiele różniących się od siebie i coraz lepszych systemów, które były równolegle rozwijane i modernizowane. W tabeli B.1 zamieszczono zestawienie najbardziej rozpowszechnionych.

NAZWA SYSTEMU ROK AUTOR Napęd pierwszego paro- 1804 wozu szynowego Inicta Parowozu Rakieta 1829 George & Robert Stephenson Carmichaela 1832 James & Charles Carmichael Jarzmowy — 1832 Jamesa 1832 Wilhelm T. James Stephensona 1841 Wilhelm Williams Goocha 1843 Sir Daniel Gooch Allana-Tricka 1855 Alexander Allan i (niezależnie) Josef Trick Promieniowy — 1844 Walschaertsa-Heusingera 1844 Egide Walschaerts i (niezależnie) Edmund Heusinger von Waldegg Joya 1870 David Joy Browna około 1875 Charles Brown Kuhna 1883 Michaal Kuhn Baguleya 1893 Ernest E. Baguley Bakera 1903 A. D. Baker Company Bagnalla-Price’a 1903 W. G. Bagnall & T. S. Price Sprzężony — 1880 Borriesa 1880 August von Borries Gresleya 1915 Sir Herbert Nigel Gresley Bulleida 1942 Oliver Vaughan Snell Bulleid Wentylowy — 1886 Lentza 1886 Caprottiego 1915 Arturo Caprotti Tabela B.1. Układ napędowy parowozu w ujęciu historycznym

Dodatek C. Skrypt

------Tool is written in MAXScript for 3ds Max environment -- It enables quick and easy reconstruction of mechanical dependences -- of Walschaert-Heusingers valve gear in a steam locomotive. -- Tool written for engineering thesis. -- -- Author: Marcin Gecow ------Dodatki 56

-- number of wheels persistent global wheelCount -- which wheel is main persistent global mainWheel -- help window object locomotiveHelperFloater -- displacement of all model along the x axis shift

-- function finishes edition mode of simplified drive system model and modyfying it into a fully operational and the final model fn finishing=( if( $circle != undefined ) then delete $circle persistent global wheelListb =#()

dummy pos:$two 3.transform.row4 scale:[1.5,1.5,1.5] name:”wheelUp” wirecolor:red dummy pos:$one 4.transform.row4 scale:[1.5,1.5,1.5] name:”wheelRight” wirecolor:red dummy pos:$five 6.transform.row4 name:”one 2” wirecolor:red dummy pos:$three 4.transform.row4 scale:[1.5,1.5,1.5] name:”three 4b” wirecolor:red dummy pos:$four 5.transform.row4 scale:[1.5,1.5,1.5] name:”four 5b” wirecolor:red dummy pos:$six 7.transform.row4 scale:[1.5,1.5,1.5] name:”six 7b” wirecolor:red dummy pos:$seven 9.transform.row4 scale:[1.5,1.5,1.5] name:”seven 9b” wirecolor:red

if( wheelCount > 1 ) then( for i = 1 to wheelCount do( append wheelConnList (dummy pos:(wheelList[i].transform.row4 - wheelList[MainWheel].transform.row4 + $one 4.transform.row4) name:(”wheelConn ” +( i as string)) wirecolor:red) ) for i = 1 to MainWheel-1 do( wheelConnList[i].parent = wheelConnList[MainWheel] wheelList[i].parent = wheelConnList[i] ) ) for i = MainWheel+1 to wheelCount do( wheelConnList[i].parent = wheelConnList[MainWheel] wheelList[i].parent = wheelConnList[i] )

--wheel------wheelList[MainWheel].showLinks = False

$wheelUp.parent = wheelList[MainWheel] --$wheelCenter $wheelRight.parent = wheelList[MainWheel]--$wheelCenter

for i = 1 to MainWheel-1 do( test=HDIKSys.ikChain wheelConnList[MainWheel] wheelList[i] False ik.setAxisActive wheelConnList[i] #rotational#{2} ik.setAxisActive wheelList[i] #rotational#{2} append wheelListb (dummy pos:wheelList[i].transform.row4 scale:[1.5,1.5,1.5] name:(”wheelCenter ” +( i as string)+ ”b”) wirecolor:red) ik.setPinNode wheelList[i] wheelListb[i] ik.setBindPos wheelList[i] true ) for i = MainWheel+1 to wheelCount do( test=HDIKSys.ikChain wheelConnList[MainWheel] wheelList[i] False ik.setAxisActive wheelConnList[i] #rotational#{2} ik.setAxisActive wheelList[i] #rotational#{2} append wheelListb (dummy pos:wheelList[i].transform.row4 scale:[1.5,1.5,1.5] name:(”wheelCenter ” +( i as string)+ ”b”) wirecolor:red) ik.setPinNode wheelList[i] wheelListb[i-1] ik.setBindPos wheelList[i] true ) if( wheelCount != 1 ) then( ik.setBindPos wheelConnList[MainWheel] true ik.setAxisActive wheelConnList[MainWheel] #rotational#{} ik.setPinNode wheelConnList[MainWheel] $wheelRight ik.setAxisActive wheelConnList[MainWheel] #sliding#{1,3} ik.SetPosThreshold wheelConnList[MainWheel] 0 ik.SetRotThreshold wheelConnList[MainWheel] 0 ik.SetStartTime wheelConnList[MainWheel]- 20 ik.SetIterations wheelConnList[MainWheel](( ik.GetEndTime wheelConnList[MainWheel])+20) ) Dodatki 57

--one------$one 3.parent = undefined $one 2.parent = $one 1 $one 3.parent = $one 2 test=HDIKSys.ikChain $one 1 $one 4 False ik.SetPosThreshold $one 10 ik.SetRotThreshold $one 10 ik.setAxisActive $one 1 #rotational#{} ik.setAxisActive $one 2 #rotational#{} ik.setAxisActive $one 2 #sliding#{1} ik.setAxisActive $one 3 #rotational#{2} ik.setAxisActive $one 4 #rotational#{2} ik.setPinNode $one 4 $wheelRight ik.setBindPos $one 4 true ik.SetStartTime $one 1 -20 ik.SetIterations $one 1 ((ik.GetEndTime $one 4)+20)

--two------test=HDIKSys.ikChain $two 1 $two 3 False ik.SetPosThreshold $two 10 ik.SetRotThreshold $two 10 ik.setAxisActive $two 1 #rotational#{2} ik.setAxisActive $two 2 #rotational#{2} ik.setAxisActive $two 3 #rotational#{2} ik.setPinNode $two 3 $wheelUp setPosTaskWeight $two 3 100 ik.setBindPos $two 3 true ik.SetStartTime $two 1 -20 ik.SetIterations $two 1 ((ik.GetEndTime $two 1)+20)

--three------test=HDIKSys.ikChain $two 1 $three 4 False ik.setAxisActive $three 1b #rotational#{2} ik.setAxisActive $three 2 #rotational#{2} ik.setAxisActive $three 3 #rotational#{2} ik.setAxisActive $three 4 #rotational#{2} ik.setAxisActive $three 4b #rotational#{2} ik.setPinNode $three 4 $three 4b setPosTaskWeight $three 4 100 ik.setBindPos $three 4 true

--four------test=HDIKSys.ikChain $two 1 $four 5 False ik.setAxisActive $four 3 #rotational#{2} ik.setAxisActive $four 4 #rotational#{2} ik.setAxisActive $four 5 #rotational#{} ik.setAxisActive $four 5 #sliding#{1} ik.setPinNode $four 5 $four 5b setRotTaskWeight $four 5 1000 setPosTaskWeight $four 5 1000 ik.setBindPos $four 5 true ik.setBindOrient $four 5 true

--five------test=HDIKSys.ikChain $two 1 $five 6 False ik.setAxisActive $five 4 #rotational#{2} ik.setAxisActive $five 5 #rotational#{2} ik.setAxisActive $five 6 #rotational#{} ik.setPinNode $five 6 $one 2 setRotTaskWeight $five 6 100 setPosTaskWeight $five 6 100 ik.setBindPos $five 6 true ik.setBindOrient $five 6 true

--six------$six 5.parent = undefined $three 4b.parent = $six 5 test=HDIKSys.ikChain $six 5 $three 4b False Dodatki 58

test=HDIKSys.ikChain $six 5 $six 7 False

ik.setAxisActive $six 5 #rotational#{2} ik.setAxisActive $six 6 #rotational#{2} ik.setAxisActive $six 7 #rotational#{2} ik.setAxisActive $six 7b #rotational#{2}

ik.SetPosThreshold $six 50 ik.SetRotThreshold $six 50 ik.SetStartTime $six 5 -20 ik.SetIterations $six 5 ((ik.GetEndTime $six 5)+20)

--seven------$seven 8.parent = undefined $six 7b.parent = $seven 8

test=HDIKSys.ikChain $seven 8 $six 7b False test1=HDIKSys.ikChain $seven 8 $seven 9 False

ik.setPinNode $seven 9 $seven 9b ik.setBindPos $seven 9 true

ik.setPinNode $six 7 $six 7b setPosTaskWeight $six 7 100 ik.setBindPos $six 7 true

ik.setAxisActive $seven 8 #rotational#{2} ik.setAxisActive $seven 9 #rotational#{2}

ik.SetPosThreshold $seven 80 ik.SetRotThreshold $seven 80 ik.SetStartTime $seven 8 -20 ik.SetIterations $seven 8 ((ik.GetEndTime $seven 8)+20)

-- create animation of all system animate on( at time 100 (rotate wheelList[MainWheel]( 360) y axis) ) -- change rotate function to linear for i=1 to 3 do( for k in wheelList[MainWheel].rotation.controller[i].controller.keys do( k.inTangentType = k.outTangentType = #linear ) ) )

-- description of help window -- this helpfull tool is used to edit simplified model rollout locomotiveHelper ”STEAM LOCOMOTIVE - HELP WINDOW” width:655 height:290 ( bitmap the bmp ”Bitmap” pos:[0,0] width:489 height:290 fileName:”uklad.jpg” checkbox chk01”” pos: [080,210] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk02”” pos: [385,213] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk03”” pos: [272,213] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk04”” pos: [053,235] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk05”” pos: [198,150] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk06”” pos: [180,185] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk07”” pos: [054,195] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk08”” pos: [190,170] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk09”” pos: [173,170] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk10”” pos: [173,113] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk11”” pos: [318,153] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk12”” pos: [318,168] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk13”” pos: [385,168] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk14”” pos: [318,237] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk15”” pos: [288,237] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk16”” pos: [288,222] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk17”” pos: [210,113] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk18”” pos: [210,075] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk19”” pos: [070,075] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk20”” pos: [066,045] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk21”” pos: [061,005] width:10 height:10 tooltip: ”Select that dummy object” checkbox chk22”” pos: [212,130] width:10 height:10 tooltip: ”Select that dummy object”

subrollout roll height:290 width:165 pos:[490,0]

global checkboxes Dodatki 59

on locomotiveHelper open do checkboxes = for c in locomotiveHelper.controls where matchPattern c.name pattern:”chk*” collect c fn uncheck restx =( checkboxes.checked=False x.checked=True ) ------on chk01 changed state do( select wheelList[mainWheel] uncheck rest chk01 if( mainWheel == 1 ) then locomotiveHelperButtons1.chk1.checked=True else if( mainWheel == 2 ) then locomotiveHelperButtons1.chk2.checked=True else if( mainWheel == 3 ) then locomotiveHelperButtons1.chk3.checked=True else if( mainWheel == 4 ) then locomotiveHelperButtons1.chk4.checked=True else locomotiveHelperButtons1.chk5.checked=True ) ------on chk02 changed state do( select $one 1 uncheck rest chk02 ) on chk03 changed state do( select $one 3 uncheck rest chk03 ) on chk04 changed state do( select $one 4 uncheck rest chk04 ) ------on chk05 changed state do( select $two 1 uncheck rest chk05 ) on chk06 changed state do( select $two 2 uncheck rest chk06 ) on chk07 changed state do( select $two 3 uncheck rest chk07 ) ------on chk08 changed state do( select $three 2 uncheck rest chk08 ) on chk09 changed state do( select $three 3 uncheck rest chk09 ) on chk10 changed state do( select $three 4 uncheck rest chk10 ) ------on chk11 changed state do( select $four 3 uncheck rest chk11 ) on chk12 changed state do( select $four 4 uncheck rest chk12 ) on chk13 changed state do( select $four 5 uncheck rest chk13 ) ------on chk14 changed state do( select $five 4 uncheck rest chk14 ) on chk15 changed state do( select $five 5 Dodatki 60

uncheck rest chk15 ) on chk16 changed state do( select $five 6 uncheck rest chk16 ) ------on chk17 changed state do( select $six 5 uncheck rest chk17 ) on chk18 changed state do( select $six 6 uncheck rest chk18 ) on chk19 changed state do( select $six 7 uncheck rest chk19 ) ------on chk20 changed state do( select $seven 8 uncheck rest chk20 ) on chk21 changed state do( select $seven 9 uncheck rest chk21 ) ------on chk22 changed state do( uncheck rest chk22 if( $circle != undefined ) then( select $circle ) else chk22.checked=False ) )

-- description of rollout placed in help window -- is used to select one of wheel axle rollout locomotiveHelperButtons1 ”Choose wheel axle:” ( checkbox chk1 ”1st” pos:[131,5] width:10 height:15 tooltip: ”Select 1st wheel axle dummy object” label lbl1 ”1st” pos:[131,20] width:15 height:14 checkbox chk2 ”2nd” pos:[101,5] width:10 height:15 tooltip: ”Select 2nd wheel axle dummy object” label lbl2 ”2nd” pos:[101,20] width:20 height:14 checkbox chk3 ”3rd” pos:[71,5] width:10 height:15 tooltip: ”Select 3rd wheel axle dummy object” label lbl3 ”3rd” pos:[71,20] width:20 height:14 checkbox chk4 ”4th” pos:[41,5] width:10 height:15 tooltip: ”Select 4th wheel axle dummy object” label lbl4 ”4th” pos:[41,20] width:20 height:14 checkbox chk5”” pos: [11,5] width:10 height:15 tooltip: ”Select 5th wheel axle dummy object” label lbl5 ”5th” pos:[11,20] width:20 height:14

on locomotiveHelperButtons1 open do checkboxes += for c in locomotiveHelperButtons1.controls where matchPattern c.name pattern:”chk*” collect c

on chk1 changed state do( locomotiveHelper.uncheck rest chk1 select wheelList[1] if( mainWheel == 1 ) then locomotiveHelper.chk01.checked=True ) on chk2 changed state do( if( wheelCount >= 2 ) then( locomotiveHelper.uncheck rest chk2 select wheelList[2] if( mainWheel == 2 ) then locomotiveHelper.chk01.checked=True ) else chk2.checked=False ) on chk3 changed state do( if( wheelCount >= 3 ) then( locomotiveHelper.uncheck rest chk3 select wheelList[3] if( mainWheel == 3 ) then locomotiveHelper.chk01.checked=True Dodatki 61

) else chk3.checked=False ) on chk4 changed state do( if( wheelCount >= 4 ) then( locomotiveHelper.uncheck rest chk4 select wheelList[4] if( mainWheel == 4 ) then locomotiveHelper.chk01.checked=True ) else chk4.checked=False ) on chk5 changed state do( if( wheelCount == 5 ) then( locomotiveHelper.uncheck rest chk5 select wheelList[5] if( mainWheel == 5 ) then locomotiveHelper.chk01.checked=True ) else chk5.checked=False ) )

-- description of rollout placed in help window -- is used to calculate and move center of the circle, on which slider is located -- operates on three points rollout locomotiveHelperButtons2 ”Arc of the slider:” ( button btn1 ”Create help point” pos:[10,5] width:130 height:20 button btn2 ”Select help point” pos:[10,30] width:130 height:20 button btn3 ”Move circle’s center” pos:[10,55] width:130 height:20

-- create help point on btn1 pressed do( if( $circle == undefined ) then( dummy pos:[shift+140,0,130] name:”circle” wirecolor:red ) else( messageBox ”Help point exist.” beep:true ) )

-- select help point object on btn2 pressed do( uncheck rest locomotiveHelper.chk22 locomotiveHelper.chk22.checked=True if( $circle != undefined ) then( select $circle ) else( locomotiveHelper.chk22.checked=False messageBox ”Help point doesn’t exist.” beep:true ) )

-- calculate and move the center of the circle located on slider on btn3 pressed do( if( $circle == undefined ) then( messageBox ”You cannot move this point.” beep:true ) else( xa=$two 1.transform.row4[1]*1.0 ya=$two 1.transform.row4[3]*1.0 xb=$three 2.transform.row4[1]*1.0 yb=$three 2.transform.row4[3]*1.0 xc=$circle.transform.row4[1]*1.0 yc=$circle.transform.row4[3]*1.0

if (((xa==xb)and(xb==xc))or((ya==yb)and( yb == yc ))or((xa==xb)and(ya==yb))or((xa==xc)and(ya==yc))or((xb==xc)and(yb==yc))) then( messageBox ”Wrong points position.” beep:true ) else( xo=-0.5*(-(ya*ycˆ2)-(ya*xcˆ2)+(ya*ybˆ2)+(ya*xbˆ2)+(yb*ycˆ2)+(yb*xcˆ2)-(yc*ybˆ2)- (yc*xbˆ2)+(yc*yaˆ2)-(yb*yaˆ2)+(yc*xaˆ2)-(yb*xaˆ2))/((ya*xc)-(ya*xb)-(yb*xc)-(yc*xa)+(yc*xb)+(yb*xa)) yo=0.5*(-(xa*xcˆ2)-(xa*ycˆ2)+(xa*xbˆ2)+(xa*ybˆ2)+(xb*xcˆ2)+(xb*ycˆ2)-(xc*xbˆ2)- (xc*ybˆ2)+(xc*xaˆ2)-(xb*xaˆ2)+(xc*yaˆ2)-(xb*yaˆ2))/((ya*xc)-(ya*xb)-(yb*xc)-(yc*xa)+(yc*xb)+(yb*xa)) Dodatki 62

Transform matrix = $three 1b.transform Transform matrix.row4 =[ xo,$three 1b.transform.row4[2],yo] $three 1b.transform = Transform matrix

-- calculate radius radius=sqrt((xo-xa)ˆ2+(yo-ya)ˆ2) locomotiveHelperButtons3.objRad.value=radius ) ) ) )

-- description of rollout placed in help window -- is used to calculate and move center of the circle, on which slider is located -- operates on two points and radius rollout locomotiveHelperButtons3 ”Radius of the slider:” ( spinner objRad ”Radius:” pos:[30,5] width:100 height:16 range:[0,99999,0] type:#worldunits button btn1 ”Move circle’s center” pos:[10,25] width:130 height:20

-- calculate and move the center of the circle located on slider on btn1 pressed do( xa=$two 1.transform.row4[1]*1.0 ya=$two 1.transform.row4[3]*1.0 xb=$three 2.transform.row4[1]*1.0 yb=$three 2.transform.row4[3]*1.0 radius=objRad.value

q=sqrt((xb-xa)ˆ2+(yb-ya)ˆ2) if(( q/2) > radius ) then( messageBox ”Radius value is too small.” beep:true ) else if(( xa==xb)and(ya==yb)) then( messageBox ”Points are overlap.” beep:true ) else( xc=(xa+xb)/2 yc=(ya+yb)/2 xo1=xc + sqrt(radiusˆ2-(q/2)ˆ2)*(ya-yb)/q yo1=yc + sqrt(radiusˆ2-(q/2)ˆ2)*(xb-xa)/q

xo2=xc - sqrt(radiusˆ2-(q/2)ˆ2)*(ya-yb)/q yo2=yc - sqrt(radiusˆ2-(q/2)ˆ2)*(xb-xa)/q

Transform matrix = $three 1b.transform if( xo1 > xo2 ) then( Transform matrix.row4 =[ xo1,$three 1b.transform.row4[2],yo1] ) else( Transform matrix.row4 =[ xo2,$three 1b.transform.row4[2],yo2] ) $three 1b.transform = Transform matrix ) ) )

-- description of rollout placed in help window -- it has other important functions rollout locomotiveHelperButtons4 ”Other:” ( button btn1 ”Align wheel axles to main” pos:[10,5] width:130 height:20 button btn2 ”Change units to in/cm” pos:[10,30] width:130 height:20 button btn3 ”FINISH” pos:[10,55] width:130 height:20 button btn4 ”CLOSE” pos:[10,80] width:130 height:20 tooltip: ”This will close that window”

-- align every wheel axles to main wheel on btn1 pressed do( for i=1 to mainWheel do( Transform matrix = wheelList[i].transform Transform matrix.row4 = [wheelList[i].transform.row4[1],wheelList[mainWheel].transform.row4[2],wheelList[mainWheel].transform.row4[3]] wheelList[i].transform=Transform matrix ) for i=mainWheel+1 to wheelCount do( Transform matrix = wheelList[i].transform Transform matrix.row4 = [wheelList[i].transform.row4[1],wheelList[mainWheel].transform.row4[2],wheelList[mainWheel].transform.row4[3]] wheelList[i].transform=Transform matrix ) Dodatki 63

)

-- change display unit scale between cm and generic on btn2 pressed do( if( units.DisplayType == #generic ) then( units.DisplayType=#metric units.MetricType=#centimeters units.SystemType=#centimeters ) else( units.DisplayType=#generic units.SystemType=#inches ) )

-- end of edit mode and finish model on btn3 pressed do( finishing() )

-- close help window on btn4 pressed do( destroydialog locomotiveHelper ) )

-- function opens help window fn openHelper =( createdialog locomotiveHelper AddSubRollout locomotiveHelper.roll locomotiveHelperButtons1 AddSubRollout locomotiveHelper.roll locomotiveHelperButtons2 AddSubRollout locomotiveHelper.roll locomotiveHelperButtons3 AddSubRollout locomotiveHelper.roll locomotiveHelperButtons4

if(( $three 1b != undefined) or( $two 1 != undefined)) then( xo=$three 1b.transform.row4[1] xa=$two 1.transform.row4[1] yo=$three 1b.transform.row4[3] ya=$two 1.transform.row4[3] locomotiveHelperButtons3.objRad.value=sqrt((xo-xa)ˆ2+(yo-ya)ˆ2) ) )

-- function creates simplified drive system model and opens help window -- user is allowed to edit this simplified system fn starting =( local wheelShift=270 persistent global wheelList =#() persistent global wheelConnList =#() if( wheelCount == 1 ) then( append wheelList (dummy pos:[0,0,0] scale:[1.5,1.5,1.5] name:”wheelCenter” wirecolor:red) wheelList[1].showLinks = True setInheritanceFlags wheelList[1] #none keepPos:False ) else( for i = 1 to wheelCount do( append wheelList (dummy pos:[((mainWheel-i)*wheelShift),0,0] name:(”wheelCenter ” +( i as string)) wirecolor:red) wheelList[i].showLinks = True ) ) if( mainWheel <= 2) then shift=0 else shift=wheelShift*(mainWheel-2) --one------dummy pos:[shift+425,0,0] name:”one 1” wirecolor:red dummy pos:[shift+320,0,0] name:”one 3” wirecolor:red dummy pos:[27,0,30] name:”one 4” wirecolor:red

$one 3.parent = $one 1 $one 4.parent = $one 3

$one 1.showLinks = True $one 3.showLinks = True $one 4.showLinks = True Dodatki 64

setInheritanceFlags $one 1 #none keepPos:True setInheritanceFlags $one 3 #none keepPos:True setInheritanceFlags $one 4 #none keepPos:True

--two------dummy pos:[shift+145,0,105] name:”two 1” wirecolor:red dummy pos:[shift+165,0,15] name:”two 2” wirecolor:red dummy pos:[32,0,0] name:”two 3” wirecolor:red

$two 2.parent = $two 1 $two 3.parent = $two 2

$two 1.showLinks = True $two 2.showLinks = True $two 3.showLinks = True setInheritanceFlags $two 1 #none keepPos:True setInheritanceFlags $two 2 #none keepPos:True setInheritanceFlags $two 3 #none keepPos:True

--three------dummy pos:[shift+290,0,145] name:”three 1b” wirecolor:red dummy pos:[shift+150,0,90] name:”three 2” wirecolor:red dummy pos:[shift+120,0,93] name:”three 3” wirecolor:red dummy pos:[shift+130,0,175] name:”three 4” wirecolor:red

$three 1b.parent = $two 1 $three 2.parent = $three 1b $three 3.parent = $three 2 $three 4.parent = $three 3

$three 1b.showLinks = True $three 2.showLinks = True $three 3.showLinks = True $three 4.showLinks = True setInheritanceFlags $three 1b #none keepPos:True setInheritanceFlags $three 2 #none keepPos:True setInheritanceFlags $three 3 #none keepPos:True setInheritanceFlags $three 4 #none keepPos:True

--four------dummy pos:[shift+340,0,85] name:”four 3” wirecolor:red dummy pos:[shift+343,0,70] name:”four 4” wirecolor:red dummy pos:[shift+425,0,70] name:”four 5” wirecolor:red

$four 3.parent = $three 2 $four 4.parent = $four 3 $four 5.parent = $four 4

$four 3.showLinks = True $four 4.showLinks = True $four 5.showLinks = True setInheritanceFlags $four 3 #none keepPos:True setInheritanceFlags $four 4 #none keepPos:True setInheritanceFlags $four 5 #none keepPos:True

--five------dummy pos:[shift+370,0,-30] name:”five 4” wirecolor:red dummy pos:[shift+320,0,-30] name:”five 5” wirecolor:red dummy pos:[shift+325,0,0] name:”five 6” wirecolor:red

$five 4.parent = $four 3 $five 5.parent = $five 4 $five 6.parent = $five 5

$five 4.showLinks = True $five 5.showLinks = True $five 6.showLinks = True setInheritanceFlags $five 4 #none keepPos:True setInheritanceFlags $five 5 #none keepPos:True setInheritanceFlags $five 6 #none keepPos:True Dodatki 65

--six------dummy pos:[shift+160,0,180] name:”six 5” wirecolor:red dummy pos:[shift+160,0,200] name:”six 6” wirecolor:red dummy pos:[shift-20,0,200] name:”six 7” wirecolor:red

$six 5.parent = $three 4 $six 6.parent = $six 5 $six 7.parent = $six 6

$six 5.showLinks = True $six 6.showLinks = True $six 7.showLinks = True

setInheritanceFlags $six 5 #none keepPos:True setInheritanceFlags $six 6 #none keepPos:True setInheritanceFlags $six 7 #none keepPos:True

--seven------dummy pos:[shift-20,0,235] name:”seven 8” wirecolor:red dummy pos:[shift-20,0,285] name:”seven 9” wirecolor:red

$seven 8.parent = $six 7 $seven 9.parent = $seven 8

$seven 8.showLinks = True $seven 9.showLinks = True

setInheritanceFlags $seven 8 #none keepPos:True setInheritanceFlags $seven 9 #none keepPos:True

--refresh all $two 1.pos=$two 1.pos $one 1.pos=$one 1.pos

-- open help window openHelper() )

-- main utility description -- creates rollout with main functions utility steamLocomotive ”Steam locomotive” ( spinner objWheels ”Wheels number:” range:[1,5,5] type:#integer tooltip: ”Set the number of wheels” spinner objMainWheel ”Main wheel:” range:[1,5,3] type:#integer tooltip: ”Set the main wheel” button start ”START” width:100 height:20 tooltip: ”Start creating the drive system” button helpWindow ”HELP WINDOW” width:100 height:20 tooltip: ”Show help window” button finish ”FINISH” width:100 height:20 tooltip: ”Finish creating the drive system”

-- range restriction of wheels number and main wheel on objWheels changed sel do ( if( objWheels.value < objMainWheel.value) then objMainWheel.range=[1,objWheels.value,objWheels.value] else objMainWheel.range=[1,objWheels.value,objMainWheel.value] ) -- call starting function on start pressed do( if( objWheels.value >= objMainWheel.value ) then( wheelCount =objWheels.value mainWheel =objMainWheel.value starting() ) else( messageBox ”Number of wheels must be greater or equal to the main wheel.” beep:true ) ) -- call finishing function on finish pressed do( finishing() ) -- call openHelper function on helpWindow pressed do( openHelper() ) ) Dodatki 66

Dodatek D. Zawartość płyty CD

MarcinGECOW praca.pdf — treść pracy inżynierskiej, steamLocomotive.ms — plik ze skryptem napisanego narzędzia do 3ds Max, uklad.jpg — grafika wykorzystywana w skrypcie, parowoz1.avi — animacja testowanego układu w rozdziale 6.1, parowoz2.avi — animacja testowanego układu w rozdziale 6.2, parowoz3.avi — animacja testowanego układu w rozdziale 6.3, parowoz4.avi — animacja testowanego układu w rozdziale 6.4, wizualizacja.avi — animacja zwizualizowanego układu w rozdziale 6.5.

D.1. Opis animacji umieszczonych na płycie CD Animacje parowoz1.avi, parowoz2.avi, parowoz3.avi, parowoz4.avi, przedstawiają testy przeprowadzone w rozdziale 6. Demonstrują kolejno: jazdę do przodu, jazdę rozpędem oraz jazdę do tyłu. Animacje parowoz1.avi, pa- rowoz2.avi, parowoz3.avi, przedstawiają poprawnie działające układy, paro- woz4.avi — błędnie. Animacja wizualizacja.avi przedstawia omawianą w rozdziale 6.5 wizualizację parowozu TKh1-191. Demonstruje kolejno: jazdę do przodu, jazdę rozpędem oraz jazdę do tyłu.