-
Notifications
You must be signed in to change notification settings - Fork 0
/
rozdzial4.tex
372 lines (279 loc) · 27.5 KB
/
rozdzial4.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
\chapter{Implementacja aplikacji}
\label{cha:implementacjaApp}
W rozdziale opiszę projekt aplikacji. Omówię strukturę programu, interefejs użytkownika, użyte algorytmy oraz przedstawię, jak aplikacja została przetestowana.
%---------------------------------------------------------------------------
\section{Struktura aplikacji}
\label{sec:strukturaApp}
Struktura omawianej aplikacji opiera się na wzorcu architektonicznym Model View Controller (MVC). Wzorce architektoniczne określają sprawdzony sposób tworzenia architektury systemu. Definiują one, z jakich elementów składa się system, ogólna strukturę komponentów, komunikację pomiędzy modułami oraz jaki zakres funkcjonalności przypada na każdy komponent.
MVC głównie używany jest w aplikacjach, posiadających interfejs graficzny. Składa się on z 3 części:
\begin{enumerate}%[1)]
\item Model - określa logikę aplikacji
\item View - odpowiada za prezentowanie danych użytkownikowi
\item Kontroler - opisuje, jak Model komunikuje się z View.
\end{enumerate}
Nierozłącznymi elementami każdej aplikacji są struktury danych, algorytmy i komunikacja. MVC silnie separuje każdy z elementów. Przykładowo, w dobrze zaprojektowanej aplikacji kod wyświetlający informacje użytkownikowi nie może znajdować się w modelu. Do zalet tego wzorca należą:
\begin{enumerate}%[1)]
\item Niezależność modelu i widoku - można zmienić wygląd lub dodać inny do aplikacji bez konieczności ingerencji w model
\item Lepsza podatność na zmiany - zespoły pracujące nad widokiem i modelem mogą pracować niezależnie
\end{enumerate}
Natomiast wady to:
\begin{enumerate}%[1)]
\item Złożoność - aplikacje oparte na tym wzorcu bywają rozbudowane, dlatego najczęściej stosuje się go wobec średnich i dużych projektów
\item Kosztowne zmiany interfejsów
\end{enumerate}
MVC jest bardzo popularnym wzorcem pośród aplikacji internetowych, gdzie widok jest definiowany w języku HTML, model określa aplikacja serwerowa i komunikacja na ogól opiera się na żądaniach HTTP\cite{fowler}. Windows Presentation Foundation opiera się na wzorcu MVVM (Model View View-Model), jednak nie korzystałem z niego w swojej aplikacji - cechy jakie posiada MVVM nie były konieczne. Strukturę widoku wizualizacji najlepiej oddaje rysunek ~\ref{fig:guistruc}.
\begin{figure}[h!]
\centering
\includegraphics[scale=0.7]{guistruc}
\caption{Struktura widoku - podział na kontenery.}
\label{fig:guistruc}
\end{figure}
W głównym oknie osadzony jest kontener typu Grid (Main Grid). Jest to rodzaj panelu, który pozwala na umieszczenie wielu elementów wewnątrz. Zoom Control służy do powiększania i pomniejszania modeli. Obok niego jest panel, w którym znajdują się guziki oraz suwaki (Buttons Panel) i panel z filtrem maski (Mask Panel). Najistotniejszy, z punktu widzenia użytkownika, jest panel typu Viewport3D (View Port), który odpowiada ze wyświetlanie obiektów w trzech wymiarach. W środku znajduje się Visual Model, do którego przypisany jest model atomów\cite{wpf}. Dzięki takiej strukturze aplikacja w łatwy sposób dostosowuje się do różnych rozdzielczości ekranu.
W aplikacji można wyszczególnić kilka wzorców projektowych, które są wszechobecne wśród programów. Deweloperzy bardzo często korzystają z wzorców, często niejawnie, aby wykorzystać najlepsze i sprawdzone rozwiązanie. Jednym z wzorców kreacyjnych, z których korzystam jest Budowniczy. Dzięki niemu można oddzielić tworzenie obiektów od logiki, co pozwala nam używać tego samo procesu dla różnych obiektów np. obiektów służących do testów\cite{builder}. Na podstawie plików wynikowych i parametrów ustawionych przez użytkownika program tworzy modele atomów w komórce elementarnej. Używana do tego jest klasa AtomBuilder, która z kolekcji atomów tworzy model 3D.
Program do wizualizacji składa się z 5569 niepustych linii kodu, 11 plików i biblioteki WPFExtenstion, która nie wchodzi w skład standardowej biblioteki. Rysunek ~\ref{fig:solution} przedstawia strukturę projektu:
\begin{figure}[h!]
\centering
\includegraphics[scale=0.6]{solution}
\caption{Struktura projektu Complex Alloys Visualisation.}
\label{fig:solution}
\end{figure}
Properties zawierają informacje, takie jak numer identyfikacyjny biblioteki lub pliku wykonywalnego. Folder References określa wszystkie zależności, jakie posiada projekt. W folderze Misc znajduje się klasa Helper, definiująca metody pomocnicze. Następnie folder Primitives posiada klasę Sphere3D, która definiuje teselacje sfery. Plik ExpressionDark.xaml w folderze Styles określa wygląd GUI. App.xaml oraz App.xaml.cs określają punkt startowy aplikacji oraz obiekty istniejące przez cały czas istnienia procesu. Klasa Atom definiuje obiekt reprezentujący pojedynczy atom. AtomBuilder tworzy model z atomów. MainWindow.xaml odpowiada z GUI w oknie głównym. MainWindows.xaml.cs określa interakcje użytkownika z programem. MathHelper posiada funkcję do konwersji stopni na radiany. Klasa MouseHelper określa w jaki sposób myszka może obracać model.
%---------------------------------------------------------------------------
\section{Użyte Algorytmy i Struktury Danych}
\label{sec:uzyteAlgo}
Aplikacja w pełni napisana jest w języku obiektowym C\#. W książce ,,Język C\# Programowanie'' znalazłem bardzo dobrą definicję języka:
\begin{quote}
C\# (wymawiane jako ,,si szarp'' to prosty, nowoczesny, obiektowy i bezpieczny pod względem stosowania typów język programowania. Korzenie C\# tkwią w rodzinie języków C, dzięki czemu szybko będą go mogli przyswoić programiści używający C, C++ i Java. Standaryzacją C\# zajmuje się organizacja ECMA International, która opracowała normę ECMA-334, oraz IOS/IEC, odpowiedzialna za normę ISO/IEC 23270. Kompilator języka C\# oferowany przez firmę Microsoft w ramach platformy .Net spełnia wymogi obydwu wymienionych standardów.
C\# jest językiem obiektowym, lecz zapewnia także wsparcie dla programowania komponentowego (ang. component-oriented). Nowoczesne sposoby projektowania oprogramowania w coraz większym stopniu opierają się na komponentach programowych, mających postać niezależnych i samoopisujących się pakietów funkcji. Kluczem do tego typu komponentów jest to, że prezentują one model programowania za pomocą właściwości, metod i zdarzeń, są wyposażone w atrybuty udostępniające deklaratywne informacje na temat komponentu, a także zawierają swoją własną dokumentację. C\# umożliwia korzystanie z konstrukcji językowych, które w bezpośredni sposób wspierają wymienione koncepcje, co czyni go niejako naturalnym językiem do tworzenia i używania komponentów programowych\cite{csharp}.
\end{quote}
Język ten jest kompilowany do kodu pośredniego Common Intermediate Language (CIL), który jest wykonywany przez środowisko uruchomieniowe. Natywnie wspieranym środowiskiem jest .Net działający pod system Windows. Istnieje również alternatywna, otwarta implementacja Mono, która wspiera wiele systemów operacyjnych. Język C\# jest stosunkowo młodym językiem. Pierwsza wersja powstała w 2001 roku. C\# posiada bardzo wiele przydatnych cech, takich jak zarządzanie pamięcią, wyrażenia LINQ czy pełna kontrola typów. Jednak dla mnie najbardziej użyteczna jest wieloparadygmowość języka. C\# w wersji 1.0 pozwalał na pisanie kodu obiektowego oraz proceduralnego. C\# 2.0 dodał wsparcie dla programowania generycznego. C\# 3.0 został wzbogacony o elementy programowania funkcjonalnego poprzez wyrażenia lambda oraz LINQ. C\# 4.0 dodał wsparcie dla programowania dynamicznego, natomiast C\# 5.0 wspiera programowanie asynchroniczne. Na daną chwilę nie istnieje żaden inny mainstreamowy język, który wspierałby tak wiele metodologii programowania. Język ten posiada również mało tzw. ,,gotcha'' (sprzeczne z intuicją rozwiązanie, które powoduje błędy w programowaniu), przez co programy zawierają mniej błędów. Moim zdaniem jest to istotna cecha, która wpływa na jakość oprogramowania. Ludzki mózg posiada swoje ograniczenia, więc korzystając z prostszych narzędzi, możemy budować bardziej skompilowane systemy\cite{csharp}.
\subsection{Funkcje pomocnicze}
\label{subsec:funkcjePom}
Każda aplikacja średniej lub dużej wielkości posiada zbiór funkcji pomocniczych. Pomagają one w ograniczeniu powtarzającego się kodu w obrębie programu. Dlaczego tworzyć zbiór funkcji zamiast biblioteki? Ponieważ często są zbyt specyficzne dla danej domeny problemu, aby złożyć z nich bibliotekę. Programista ma zawsze możliwość wniesienia zmian według wymagań. Na potrzeby aplikacji stworzyłem 3 funkcje pomocnicze. Pierwsza z nich służy do zamiany stopni na radiany według powszechnie znanego wzoru:
\begin{equation}
\frac{stopnie}{180} * \Pi
\end{equation}
Dwie kolejne metody służą do parsowania łańcuchów tekstowych i zamiany na liczbę zmiennoprzecinkową. Dlaczego definiować na nowo tak prostą funkcję, która istnieje w wielu bibliotekach? Są ku temu dwa powody: różny separator dziesiętny oraz formatowanie liczb.
\begin{figure}[h!]
\centering
\includegraphics[scale=0.6]{separator}
\caption{Rodzaje separatorów dziesiętnych na świecie. Zielony: przecinek. Niebieski: kropka. Czerwony: momayyez.
Źródło: Wikipedia na licencji Creative Commons.}
\end{figure}
Na świecie dominują dwa różne separatory. Pierwszy z nich to kropka, który na powyższej mapce zaznaczony jest kolorem niebieskim. Drugi to przecinek - kolor zielony. Istnieje również trzeci separator, momayyez, który występuje w krajach arabskich. Użycie nieprawidłowego separatora dziesiętnego może mieć różne rezultaty. Najmniej szkodliwe jest oczywiście nieprawidłowe wyświetlanie, natomiast bardzo często aplikacja zmienia swoje działanie lub zawiesza się. Fakt ten wynika z niewiedzy, ignorancji lub błędu w projekcie, tak jak w przypadku platformy .Net. Domyślnie ustawiony jest lokalny separator, dlatego przykładowo aplikacja czytająca plik w Wielkiej Brytanii może działać poprawnie, natomiast w Polsce zawiesza się. Jest kilka rozwiązań dla tego problemu. Jeżeli posiadamy źródła programu, możemy poprawić kod, który sprawia problemy. W przypadku braku dostępu do kodu źródłowego możemy stworzyć moduł, który będzie konwertował pliki. Innym sposobem jest zmiana ustawień użytkownika, jednak może to wpłynąć na inne aplikacje. Najlepszym rozwiązaniem jest stworzenie nowego użytkownika z odpowiednimi ustawieniami tylko dla tej aplikacji.
Aby uniknąć tego błędu, moja funkcja korzysta z wbudowanej funkcji z odpowiednimi parametrami:
\begin{lstlisting}
static bool TryParseDouble(this string text, out double value)
{
return double.TryParse(text, NumberStyles.Any,
CultureInfo.InvariantCulture, out value);
}
\end{lstlisting}
Funkcja akceptuje każdy format liczby zmiennoprzecinkowej. Dobrą praktyką jest akceptowanie większego zbioru danych, aby później odpowiednio je filtrować. Zdefiniowana metoda jest metodą rozszerzeń. Można ją rozpoznać po słowie kluczowym ,,this''. Dzięki temu można ją użyć, jakby była zdefiniowana w typie string. Druga metoda ma to samo zadanie, jednak dodatkowo wyświetla błąd dla użytkownika w postaci czerwonego tekstu. Świadczy on o nieprawidłowym formacie liczby.
\begin{figure}[h!]
\centering
\includegraphics[scale=1.0]{abcd}
\caption{Nieprawidłowa pozycja kamery.}
\end{figure}
\subsection{Klasa Sphere3D}
\label{subsec:sphere}
Model każdego atomu jest przedstawiany jako sfera. Kształt pojedynczej sfery jest tworzony w kodzie przy pomocy algorytmu teselacji, który definiuje poniższy pseudokod:
\begin{enumerate}%[1)]
\item Ustalamy warunki początkowe: powierzchnia sfery składa się z 32 trójkątów
\item Budujemy sferę, posługując się kątem theta z zakresu <0; 360> oraz zmienną y z zakresu <-1;1>
\item Tworzymy pusta siatkę MeshGeometry3D
\item Dla kroków dt oraz dy dodajemy do siatki pozycje punktów, normalne oraz współrzędne tekstury
\item Łączymy punkty trójkątami
\item ,,zamrażamy'' siatkę
\end{enumerate}
Tak stworzona siatka może zostać wykorzystana wielokrotnie, dlatego obliczana jest tylko raz.
\subsection{Klasa Atom}
\label{subsec:atom}
Klasa atom definiuje strukturę danych dla pojedynczego atomu. Seria atomów jest tworzona podczas parsowania pliku z parametrami. Każdy atom ma następujące parametry:
\begin{enumerate}%[1)]
\item Współrzędne x, y oraz z wyrażone jako względna wartość z zakresu <-0,5; 0,5>
\item Długość komórki elementarnej
\item Rodzaj atomu (Magnez lub Aluminium)
\item Prawdopodobieństwo wystąpienia wakancji
\item Prawdopodobieństwo obsadzenia atomem Aluminium
\item Prawdopodobieństwo obsadzenia atomem Magnezu
\item Stała konwersji do Angstremów (28,289)
\end{enumerate}
Dzięki tym parametrom możemy zbudować model siatki krystalicznej dla komórki elementarnej.
\subsection{Klasa AtomBuilder}
\label{subsec:atomBuilder}
Metoda CreateModel w klasie AtomBuilder tworzy model 3D na podstawie kolekcji atomów. Podczas implementacji algorytmu napotkałem pierwsze ograniczenie narzucone przez WPF. Jest to brak bezpośredniego dostępu do Z-buffer, który odpowiada za zarządzanie głębią w przestrzeni trójwymiarowej. Dzięki Z-bufferowi rysowane są tylko te elementy, które są widoczne. Problem pojawia się, gdy niektóre elementy są całkowicie lub częściowo przeźroczyste. Domyślnie tekstura DiffuseMaterial używa Z-buffer, przez co przeźroczyste atomy na pierwszym planie zasłaniają te na dalszym\cite{wpf}.
\begin{figure}[h!]
\centering
\includegraphics[scale=1.0]{zbuffer}
\caption{Materiał używający Z-buffer.}
\end{figure}
Jako rozwiązanie tego problemu dodałem drobną modyfikację. Jeżeli przeźroczystość atomu jest poniżej 30\%, zmieniam materiał na EmissiveMaterial, który nie zapisuje wartości do Z-buffera.
Podczas wizualizacji modeli kolor jest jednym z kluczowych parametrów. Dostarcza użytkownikowi informacje o prawdopodobieństwie obsadzenia. Zależności pomiędzy kolorem a prawdopodobieństwem opisuje dana tabelka:
\begin{table}
\begin{center}
\begin{tabular}{ | l | p{3cm} | p{3cm} | p{3cm} | p{3.5cm} |} %p{4cm}
\hline
Kanał Alfa & Prawd. wakancji & Prawd. Obsadzenia Mg & Prawd. Obsadzenia Al & Komentarz \\ \hline
0 & 1 & 0 & 0 & Brak atomu \\ \hline
1 & 0 & 1 & 0 & Atom Mg (kolor niebieski) \\ \hline
1 & 0 & 0 & 1 & Atom Al (kolor czerwony) \\ \hline
0,5 & 0,5 & 0,5 & 0 & Mg 50\% \\ \hline
0,5 & 0,5 & 0 & 0,5 & Al 50\% \\ \hline
1 & 0 & 0,5 & 0,5 & Jest pełne obsadzenie, ale mieszane \\ \hline
\hline
\end{tabular}
\caption{Zależność prawdopodobieństwa i koloru.}
\end{center}
\end{table}
Sumaryczne prawdopodobieństwo każdej ze składowych wynosi 1. Wszystkie wartości pośrednie powstają przez mieszanie się barwy czerwonej i niebieskiej. Niestety kolor składający się z 50\% czerwonego oraz 50\% niebieskiego nie jest zbyt wyraźny. Dlatego aby polepszyć kontrast i jakość modelu, dodatkowo występuje kanał zielony. Ilość zieleni jest proporcjonalna do różnicy poziomu obsadzenia magnezu i aluminium.
\begin{equation}
I(g) = 1 - \frac{|P(Mg) - P(Al)|}{|P(Mg) + P(Al)|}
\end{equation}
Zmienna I(g) jest poziomem intensywności kanału zielonego.
%\begin{figure}[h!]
% \centering
% \includegraphics[scale=0.6]{test}
% \caption{Zbiór testowy 20 atomów .}
%\end{figure}
%\newpage
\subsection{MainWindow}
\label{subsec:mainWindow}
W pliku MainWindow.cs znajduje się kod, który definiuje interakcję użytkownika z aplikacją. Architektura WPF opiera się na zdarzeniach, które są obsługiwane przez funkcje obsługi. W przypadku klasy MainWindow jest to 19 funkcji odpowiedzialnych za m.in. obsługę przycisków, powiększanie lub pomniejszanie modelu, zmianę kamery, zmianę wektora kierunkowego kamery, skalowanie, zapis zrzutu ekranu, zmianę maski, przetwarzanie grupy plików oraz zmianę przeźroczystości. Typ MainWindow definiuje również pola, które opisują stan. Pierwszy z nich to lista obiektów typu Atom z początkową pojemnością dla 2000 elementów. Kolejna jest lista masek filtrująca serie pomiarowe. Następnie obiekty typu AtomBuldier, MouseHelper, domyślny promień dla atomów wynoszący 1.0 oraz łańcuch znaków wskazujący użytkownikowi, że żaden plik nie został wybrany.
Funkcje klasy MainWindow można podzielić na 3 grupy: tworzenie modelu, modyfikacja parametrów i przetwarzanie grupy modeli. Tworzenie modelu definiuje poniższy algorytm:
\begin{enumerate}%[1)]
\item Użytkownik naciska przycisk Open File i w oknie wyboru pliku wybiera plik danych z rozszerzeniem .chmc
\item Czytane są dane z wybranego pliku, na podstawie których tworzona są obiekty reprezentujące atomy
\item Lista stworzonych atomów jest filtrowana poprzez maskę
\item Tworzony jest model 3D
\end{enumerate}
Atomy filtrowana są poprzez zapytanie LINQ. LINQ jest nową technologią, opracowaną przez firmę Microsoft. Definiuje zbiór metod, z których tworzone są zapytania dla obiektów, takich jak kolekcje, bazy danych, XML czy inne zbiory danych. Jest to część języka, która bazuje na funkcjonalnym stylu programowania.\cite{csharp}. Zastosowałem zapytanie LINQ do filtracji serii atomów, które są zgodne z wybraną maską.
\begin{lstlisting}
private void draw()
{
var filteredAtoms = from atom in atoms
where masks.Contains(atom.PositionNumber)
select atom;
visualModel.Content = atomBuldier.CreateModel(filteredAtoms,
alphaSlider.Value);
}
\end{lstlisting}
Czytelnik znający język SQL może dostrzec podobieństwo słów kluczowych w zapytaniach LINQ.
Przetwarzanie grupy modeli jest w gruncie rzeczy modyfikacją algorytmu dla pojedynczego modelu:
\begin{enumerate}%[1)]
\item Po naciśnieciu Process Files użytkownik, w oknie wyboru folderu, wybiera folder z plikami
\item Wczytywane są pliki o rozszerzeniu .chmc
\item Dla każdego pliku wczytywane są dane, filtrowane atomy zgodnie z maską, renderowane i ustawiane są parametry, które zdefiniował użytkownik
\item Każdy model zapisany jest w pliku w formacie PNG, gdzie jego nazwa odpowiada temperaturze
\end{enumerate}
Ponieważ przetwarzanie dużej liczby plików może trwać dłuższą chwilę, aplikacja wyświetla kolejne modele, tak aby użytkownik wiedział, że program nie zawiesił działania. Dodatkowo na środku ekranu pojawia się napis ,,Processing Files''.
\subsection{MouseHelper}
\label{subsec:mouseHelper}
Klasa MouseHelper służy do obrotu obiektu przy użyciu myszki. W tym celu WPF używa kwaternionów. Dla każdego ruchu myszki w poziomie i pionie obliczany jest obrót obiektu, jeżeli wciśnięty jest lewy klawisz a mysz znajduje się w obrębie okna.
%---------------------------------------------------------------------------
\section{Graficzny Interfejs Użytkownika}
\label{sec:grafInter}
Graficzny interfejs użytkownika (ang. Graphical User Interface), nazywany również środowiskiem graficznym, stanowi ogólne określenie sposobu prezentacji informacji przez komputer oraz sposobu interakcji z użytkownikiem. Głównym sposobem interakcji jest operacja na różnych elementach, które są rysowane na monitorze pod postacią obrazów. Klasycznie użytkownik komunikuje się z komputerem przy pomocy komend tekstowych\cite{GUIdef}.
Prekursorem wszystkich graficznych interfejsów był Sketchpad. Sketchpad został stworzony z myślą o wsparciu projektów technicznych. Użytkownik przy pomocy specjalnego pióra tworzył figury geometryczne, którymi następnie mógł manipulować poprzez obrót, skalowanie i przesuniecie. \cite{Sketch}
Pierwsze prototypu interfejsów znanych z dzisiejszych systemów powstały w laboratorium PARC firmy Xerox. PARC User Interface zawierał okienka, przyciski, ikony i menu. Dodano obsługę urządzenia wskazującego poza standardową klawiaturą. \cite{parc}
GUI mojej aplikacji składa się z głównego okna, w którym wyświetlane są modele atomów i dwóch paneli bocznych.
\begin{figure}[h!]
\centering
\includegraphics[scale=0.5]{gui}
\caption{GUI programu do wizualizacji CMA.}
\end{figure}
%\newpage
W lewym panelu znajduje się kontrolka odpowiedzialna za skalowanie modelu.
\begin{figure}[h!]
\centering
\includegraphics[scale=1.0]{zoom}
\caption{Kontrolka skalowania modelu.}
\end{figure}
%\newpage
Atomy mogą być skalowane od 0.01 do 100 przy użyciu kółka w myszce lub bezpośrednio suwakiem. Kontrolka może również wrócić do domyślnej skali 1:1 lub wypełnić cały ekran. Służą do tego przyciski odpowiednio: ,,1:1'' oraz Fill.
W lewym panelu znajdują się również elementy odpowiedzialne za główną funkcjonalność aplikacji.
\begin{figure}[h!]
\centering
\includegraphics[scale=1.0]{lpanel}
\caption{Lewy panel GUI.}
\label{fig:lpanel}
\end{figure}
%\newpage
Rysunek \ref{fig:lpanel}: posiada ponumerowane kontrolki, które odpowiednio służą do:
\begin{enumerate}%[1)]
\item Wyświetlania nazwy pliku, z którego stworzony jest model
\item Otwierania pliku z modelem, który następnie jest parsowany do tworzenia modelu
\item Powrotu do domyślnych ustawień
\item Zmiany pozycji kamery w płaszczyźnie xy
\item Zmiany wektora, w jakim kierunku skierowana jest kamera
\item Skalowania promienia atomów
\item Zapisu zrzutu ekranu
\item Otwierania i zamykania panelu masek
\item Przetwarzania grupy plików
\item Zmiany przeźroczystości
\end{enumerate}
Każdy z elementów panelu został zaprojektowany w taki sposób, aby rezultat operacji był natychmiast widoczny dla użytkownika np. brak dodatkowego kroku w postaci odświeżania. Gdy użytkownik wpisze nieprawidłowe dane do pola tekstowego, tekst jest podświetlony kolorem czerwonym. Dane sprawdzane są z każdym kliknięciem klawiatury.
Lewy panel zawiera kontrolki służące do filtracji atomów.
\begin{figure}[h!]
\centering
\includegraphics[scale=0.8]{rpanel}
\caption{Maski serii atomów.}
\end{figure}
Poprzez kliknięcie odpowiedniego checkboxa dodajemy lub usuwamy serię atomów.
%---------------------------------------------------------------------------
\section{Testy}
\label{sec:testy}
Testowanie oprogramowania jest to badanie prowadzone w celu zapewnienia zainteresowanym stronom informacji o jakości produktu lub usługi. Testowanie może również dostarczyć dodatkowych informacji o systemie, takich jak ryzyko związanie z projektem.
Testowanie oprogramowania można podzielić na proces weryfikacji i walidacji składający się z czterech części:
\begin{enumerate}%[1)]
\item sprawdzenie produktu pod kątem wymagań
\item czy oprogramowanie zachowuje się zgodnie z przewidywaniami
\item czy może być zaimplementowane zgodnie z wymaganiami
\item czy spełnia potrzeby zleceniodawcy
\end{enumerate}
Testowanie tradycyjnie jest jednym z ostatnich etapów w budowaniu aplikacji, jednak nowe metodologie, takie jak Agile, przesuwają znaczną część testów do początkowych etapów.\cite{extest}
Przykładem takiego podejścia jest Test-driven development (TDD), który opiera się na krótkich cyklach podzielonych na:
\begin{enumerate}%[1)]
\item tworzenie automatycznych testów początkowych, które opisują nową funkcjonalność
\item pisanie początkowego kodu, który "przechodzi" przez wszystkie testy
\item refactoring kodu do określonych standardów
\end{enumerate}
Programiści często korzystają z TDD, aby poprawić jakość istniejącego już programu. \cite{TDD}
Testowanie oprogramowania nigdy nie potwierdzi w 100\% czy system nie ma wad, lecz daje nam odpowiedź na inne pytanie: Czy w pewnych warunkach oprogramowanie posiada błędy?
Przeanalizujmy poniższą funkcję:
\begin{lstlisting}
int add(int a, int b) {
return a + b;
}
\end{lstlisting}
Aby w pełni przetestować tę funkcję, należy sprawdzić wynik dla każdych możliwych danych wejściowych. W przypadku typu liczbowego int daje nam to 4 294 967 296 możliwości dla pierwszej oraz tyle samo dla drugiej liczby. W sumie daje to $ 1,84467441 \times 10^{19}$ testów jednostkowych tej trywialnej funkcji! Dlatego nigdy nie tworzy się wszystkich możliwych testów. Funkcję add, w praktyce, należy przetestować dla kilku wartości losowych oraz dla przypadków szczególnych, takich jak maksymalna wartość int. \\
Bardzo ważnym elementem testowania jest tworzenie testów z uwzględnieniem odbiorcy oprogramowania. Użytkownicy gry video diametralnie różnią się od użytkowników systemu bankowego.
Testowanie oprogramowania jest złożonym procesem, który wymaga sporych nakładów ludzkich. Jak zawsze w takich sytuacjach, pojawia się pytanie o opłacalność prowadzenia testów. W 2002 National Institute of Standards and Technology (NIST) sporządził raport dotyczący wpływu błędów oprogramowania na gospodarkę amerykańską. Roczny koszt nieprawidłowego działania aplikacji w roku 2002 wyniósł 59,5 mld dolarów. Około jedną trzecią tej kwoty da się zaoszczędzić, jeżeli oprogramowanie byłoby lepiej testowane\cite{reportEco}.
Wcześniej wykryte błędy są tańsze w naprawie. Potwierdza to analiza wielu projektów, której wyniki opisuje dana tabelka. Wartości reprezentują krotności pojedynczego kosztu\cite{codeComplete}.
\begin{table}
\centering
\scalebox{0.8}{
\begin{tabular}{|c|c|c|c|c|c|c|}
\hline
\multicolumn{2}{|c|}{Koszt naprawy} & \multicolumn{5}{|c|}{Czas wykrycia} \\ \cline{3-7}
\multicolumn{2}{|c|}{} & Wymagania & Architektura & Programowanie & Testy & Po dostarczeniu \\ \hline
Czas Wystąpienia & Wymagania & 1x & 3x & 5-10x & 10x & 10-100x \\\cline{2-7} & Architektura & - & 1x & 10x & 15x & 25-100x \\\cline{2-7}
& Programowanie & - & - & 1x & 10x & 10-25x \\\hline
\end{tabular}
}
\caption{Zależności miedzy kosztem naprawy błędu a etapem wystąpienia. }
\end{table}
Testowanie oprogramowania można podzielić na kilka kategorii. Jednym z nich jest podział na testy statyczne i dynamiczne. Testy statyczne są to testy, które nie wymagają uruchomienia programu np. Code Review, zaś testy dynamiczne są to takie, w których aplikacja jest uruchamiana np. testy jednostkowe.
Metody testowania również dzielą się na Black-box oraz White-box. Przy testowaniu typu White-box tester ma wiedzę o architekturze i wewnętrznej strukturze testowanego modułu. Stosowane są głównie jako testy jednostkowe, testy API. Testy typu Black-box nie korzystają z wewnętrznych informacji. Tester ma tylko informację o spodziewanym rezultacie. Istnieją również hybrydowe metody, nazywane Grey-box.\cite{softTesting}
Podczas tworzenia aplikacji do wizualizacji CMA korzystałem głównie z testów GUI, wydajnościowych i regresywnych. Testy GUI mają na celu sprawdzenie działania każdego elementu interfejsu. Istotne nie tylko jest poprawne działanie każdego z elementów, ale również ich zachowanie w określonej sekwencji. Z tego powodu wraz z komplikacją GUI liczba testów rośnie eksponencjalnie. Mój program posiada tylko kilkanaście elementów, dlatego manualne testowanie jest wystarczające.
Testy wydajnościowe mają na celu zbadanie, jak system zachowuje się pod obciążeniem. Możemy określić, czy system spełnia wymagania wydajnościowe, zbadać skalowalność i niezawodność. Testy wydajnościowe mogą również pomóc w wykrywaniu błędów. Podczas testowania odkryłem, że jedna z metod zajmuje około 95\% czasu. Był to banalny błąd. Dla każdego atomu obliczałem siatkę na nowo, mimo że jest współdzielona.
Testy pomogły również zoptymalizować przetwarzanie grupy plików. W pierwszej wersji przetworzenie 30 plików zajmowało około 20 minut. W ostatecznej wersji proces ten trwa około 3 minuty.
Testy regresywne jest to rodzaj testowania, który szuka błędów w istniejącej funkcjonalności po wprowadzeniu zmian. Innymi słowy, chcemy zbadać, czy wprowadzane poprawki nie naruszają działającej poprawnie części systemu.\cite{softTesting} Po każdej większej zmianie, a przed dodaniem kodu do systemu kontroli wersji, przeprowadzałem co najmniej jeden test regresywny.
Ostatnim testem była kontrola wizualizacji prawdopodobieństw obsadzenia. Posłużył do tego plik test.chmc, który zawierał kombinacje obsadzeń ze zmianą od całkowitego Al do całkowitego Mg poprzez obsadzenia mieszane. Generuje to w sumie 20 atomów (rysunek \ref{fig:test}).
\begin{figure}[h!]
\centering
\includegraphics[scale=0.5]{test}
\caption{Zbiór testowy 20 atomów.}
\label{fig:test}
\end{figure}
Na rysunku \ref{fig:test} widać, że przejścia w palecie są gładkie oraz kolor, zgodnie z oczekiwaniami, przechodzi od czerwonego do niebieskiego z domieszką zielonej barwy.