Pokazywanie postów oznaczonych etykietą azp. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą azp. Pokaż wszystkie posty

niedziela, 17 lutego 2013

Golang : obsługa bazy Spatialite

W QAZP2 pojawiła się nowa funkcja, moim zdaniem jedna z ważniejszych, czyli filtrowanie danych. Póki co można ją stosować tylko do stanowisk i polega na wybieraniu z listy stanowisk tych, które spełniają wybrane kryteria. A więc w pierwszym kroku wyszukujemy stanowiska znajdujące się na przykład na pewnym obszarze, a następnie spośród nich stanowiska, które mają dużą wartość dla badań nad przeszłością i wobec których istnieje zagrożenie zniszczenia. To oczywiście tylko przykład, bo praktycznie stanowiska można filtrować w oparciu o większość atrybutów edytowanych w programie. A prezentację sposobu stosowania tego mechanizmu można obejrzeć na krótkim filmie.

To by było na tyle, jeżeli chodzi o ostanie wydarzenia, bo dzisiaj chciałbym dokończyć temat z poprzedniego tygodnia, czyli wykorzystanie języka Go do realizacji projektu QAZP2. Wtedy omówiłem kilka interesujących właściwości Go, które odróżniają go od dobrze znanych C/C++ a także popularnych języków obiektowych, na przykład Javy. Go (Golang) charakteryzuje się bogatą biblioteką standardową, która umożliwia realizację podstawowych zadań, bez konieczności instalacji dodatkowych zależności. W pozostałych przypadkach można się posłużyć intuicyjnym i wygodnym mechanizmem zarządzania nimi. Na przykład do pobrania sterownika do bazy SQLite/Spatialite. Istnieje kilka alternatywnym projektów, w ramach których jest on rozwijany, ja zdecydowałem się na Go-Sqlite3. Jak już pisałem do jego instalacji wystarczy wykonać polecenie
go get github.com/mattn/go-sqlite3
, które po pierwsze pobierze kod źródłowy utrzymywany w repozytorium GIT i po drugie skompiluje go, jeżeli spełnione są wszystkie zależności. To jest proste nie tylko w teorii, z tym że w normalnej postaci sterownika nie można używać do baz przestrzennych. Wynika to z tego, że przed wykonaniem jakiegokolwiek polecenia SQL, które dotyczy danych geometrycznych należy załadować rozszerzenie spatialite, na przykład stosując polecenie (na linuksie) select load_extension('libspatialite.so.3'). Do tego, by ono zadziałało trzeba wcześniej zmodyfikować kod źródłowy sterownika w ten sposób, by w chwili "łączenia się" z bazą umożliwiał ładowanie rozszerzeń, która to możliwość jest domyślnie zablokowana.
Dowolny program może korzystać z bazy SQLite przy pomocy biblioteki funkcji, których używa się na przykład do otwierania bazy, wykonywania poleceń SQL i pobierania wyników. Wśród nich jest także funkcja sqlite3_enable_load_extension, która służy (jak sama nazwa wskazuje ...) do włączenia możliwości ładowania rozszerzeń. Trzeba ją wykonać po otworzeniu pliku z bazą danych. A więc w pliku sqlite3 , wewnątrz funkcji Open, przed deklaracją zwracającą wskaźnik do nowego połączenia z bazą należy wstawić następujące polecenie: 
C.sqlite3_enable_load_extension(db, C.int(1)). I to wszystko. Po otworzeniu bazy zostanie wywołana ww. funkcja, gdzie parametrami są wskaźnik do bazy i liczba 1 oznaczająca True. Po nawiązaniu połączenia wystarczy wykonać polecenie SQL, które spowoduje załadowanie rozszerzenia Spatialite i od tej chwili można przetwarzać dane geometryczne zapisane w przestrzennej bazie danych.

sobota, 9 lutego 2013

Golang : import danych AZP

Jednym z ważniejszych aspektów związanych z projektem QAZP było przygotowanie narzędzia, które (w miarę) bezboleśnie pozwoli na "przerzucenie" danych utworzonych w programie AZPMAX do relacyjnej bazy SQL. Oczywiście pierwszą decyzją był wybór języka programowania, który z wiadomych względów padł na Jave, choćby z tego powodu, że mam sporo doświadczeń związanych z tworzeniem narzędzi obsługujących zarówno DBF-y jak i bazy danych. Niestety musiałem z tego zrezygnować, bo mimo wcześniejszych pozytywnych wyników, tym razem sterownik do SQLite odmówił współpracy z danymi przestrzennymi. Przy próbie inicjalizacji rozszerzenia Spatialite JVM przestawała działać. W związku z tym zdecydowałem się stworzyć narzędzie do importu w języku Golang, który od kilku lat jest rozwijany przez dobrze znaną firmę Google. Ten wybór też ma uzasadnienie, biorąc pod uwagę, że:
  1. mam już pewne doświadczenie związane z tworzeniem oprogramowania w Go,
  2. dobra obsługa baz sql, w tym Sqlite.
Na minus trzeba zaliczyć brak obsługi DBF-ów, ale to póki co rozwiązałem kopiując dane z plików CSV, a do tego formatu można łatwo wyeksportować DBF, posługując się na przykład arkuszem kalkulacyjnym.
Golang / Go ma kilka interesujących właściwości, które przyniosły mu już dużo rozgłosu i powodują, że język dość szybko zyskuje na popularności. Jest statycznie typowany, ale określenie typu zmiennej można przerzucić na kompilator. Wydaje mi się, że nie można go uznać za niskopoziomowy, bo nie umożliwia na przykład wykorzystywanie assemblera, natomiast różnorakie porównania wykazują, że w wielu przypadkach szybkością dorównuje programom pisanym w C / C++. Nad tymi dwoma ma przewagę (przec co niektórych uznawaną za wadę) automatycznego zarządzania pamięcią (garbage collector). Programy można tworzyć w modelu strukturalnym - do reperentowania danych używa się list, map, i struktur bardzo podobnych do tych stosowanych w C / C++, albo takim, który oferuje abstrakcję i polimorfizm (ale bez dziedziczenia) znany z paradygmatu programowania obiektowego. Realizuje się to przy pomocy tak zwanych interfejsów, które nieco przypominają konstrukcje o tej samej nazwie, które stosuje się w Javie. W Golang interfejs jest pewnym kontraktem, który umożliwia tworzenie polimorficznych obiektów. Natomiast inny jest sposób ich stosowania. O ile w Javie, jawnie trzeba podać, że klasa jest implementacją, o tyle w przypadku Golang jest to automatycznie rozpoznawane przez kompilator. Każdy typ danych, dla którego zaimplementowano funkcje wskazane w definicji interfejsu staje się automatycznie jego implementacją. W narzędziu do importu, o którym mowa został zdefiniowany interfejs Tabela z jedną metodą Params, która zwraca tablicę wartości dowolnego typu. Każda struktura, która implementuje interfejs może być zastosowana w metodzie dodaj(ps *sql.Stmt, t Tabela, spr bool), która wykonując metodę Params pobiera wartości ze struktury w takiej kolejności, które powinny być zastosowane jako parametry polecenia SQL reprezentowanego przez inny interfejs Stmt zdefiniowany w bibliotece standardowej Golang.
W tym krótkim opisie trudno wskazać wszystkie właściwości Go, ja skupiłem się tylko na tych, które były istotne z uwagi na problem, który musiałem rozwiązać. W następnym poście opisałem, jak "zmusić" sterownik Go do obsługi danych geometrycznych zapisanych w przestrzennej bazie danych.

wtorek, 15 stycznia 2013

Budowanie wykazów nazw

Ostatnimi czasy dużo się działo w kwestii QAZP2. Ostatnie poprawki błędów, niekiedy dość poważnych, nowe funkcjonalności - na przykład wykonywanie skryptów modyfikujących zawartość bazy danych - co może mieć znaczenie, gdy osoba odpowiadająca za techniczny aspekt bazy połączonej z QAZP2 nie ma do niej bezpośredniego dostępu. W takim wypadku wystarczy spreparować skrypt SQL i wysłać do użytkownika, który za pomocą interfejsu graficznego aplikuje przygotowane zmiany. Rzecz jasna taki mechanizm jest pewnym zagrożeniem dla stanu bazy danych, jednak jest to koszt, który można ponieść, pamiętając, by nie stosować skryptów z niepewnego źródła. Między innymi z tego powodu trudno było mi znaleźć czas i spełnić obietnicę, że nowe artykuły będą wprowadzane conajmniej raz na tydzień.

Ostatnimi czasy na blogu była poruszana kwestia wykazów pojęć archeologicznych, których używa się do klasyfikacji kulturowo-funkcjonalno-historycznej. W QAZP2 wykorzystywane są do tego wykazy przygotowane w Narodowym Instytucie Dziedzictwa i uzupełnione o nazwy, których obecności wymaga praktyka badań archeologicznych. Ich konstrukcję próbowałem opisać w poprzednim artykule, natomiast dzisiaj chciałbym przedstawić inne podejście, które chociaż nie zostało wdrożone, to wydaje się ciekawą alternatywą dla wyżej wspomnianego sposobu budowania wykazów.


niedziela, 30 grudnia 2012

Klasyfikacja kulturowo-historyczna: kodowanie pojęć

W poprzednim artykule opisałem organizację wykazów do kodowania informacji o klasyfikacji kulturowo-historycznej. Dla przypomnienia: na ekranie aplikacji, albo na karcie AZP pokazywane są informacje o tym, z jakiego okresu dziejów (epoka kamienia, średniowiecze, ...), zdaniem archeologa, pochodzi badane stanowisko, jaka była jego funkcja (osada, cmentarzysko, ...), czy sposób i tradycję wykonania znalezionych przedmiotów (kultura pucharów lejkowatych, kultura łużycka, ...). Nazwy wykorzystywane do opisu są przechowywane w tabelach-wykazach: OKRESY_DZIEJOW, JEDNOSTKI, FUNKCJE. Kluczem podstawowym każdej krotki w tabeli wykazu jest ciąg alfanumeryczny kodujący informację, która jest zapisana w rekordzie. W przypadku wykazu funkcji kod ma następującą strukturę ABCCD, gdzie kolejne litery oznaczają jego segmenty. W tym przypadku obowiązkowe jest podanie tylko segmentu A, w którym określa się ogólną funkcję: np. obrzędową literą B, obronną literą O, gospodarczą G, itd. Zatem gdyby w opisie funkcji stanowiska podać kod składający się z litery G, oznaczałoby to tylko tyle, że pełniło ono w przeszłości funkcję gospodarczą. Kolejne segmenty kodu służą do zapisu bardziej szczegółowej informacji. Jeżeli kod S oznacza funkcję sepulkralną (związaną z grzebaniem zmarłych), to SL będzie oznaczało cmentarzysko ciałopalne, SL03 - cmentarzysko ciałopalne płaskie, a SL03J - cmentarzysko ciałopalne płaskie z grobami jamowymi, które to pojęcie jest przykładem najbardziej szczegółowej informacji w wykazie funkcji. Oczywiście sposób konstruowania kodu, opisany na przykładzie funkcji, został zastosowany w wykazie okresów i jednostek kulturowych. 
Jak z każdym kodowaniem informacji, z tym także wiążą się określone zyski i straty, których bilans powinien decydować o jego zastosowaniu do naszego projektu. Do oczywistych zalet oczywiście należy spójna i czytelna reprezentacja informacji w bazie danych. Zamiast w każdym rekordzie charakteryzującym funkcję stanowiska pisać cmentarzysko ciałopalne płaskie z grobami jamowymi można po prostu wstawić kod SL03J i liczyć na to, że będzie on zrozumiały dla odbiorcy. Po drugie znacząco może ułatwić wyszukiwanie informacji o stanowiskach przy pomocy operatora SQL LIKE. Listę stanowisk z funkcją gospodarczą można utworzyć stosując polecenie SELECT * FROM FAKTY WHERE FUNKCJA LIKE 'G%', które uzwględni kod G, GI, GP13 i inne, które pasują do podanego wzorca. Szybkość wykonania takiego polecenia nie jest najwyższa, ale można je zoptymalizować na przykład przez utworzenie odpowiedniego indeksu na kolumnie FUNKCJA. Stosowanie wzorców nie zawsze będzie miało pożądanych skutek, ponieważ np. polecenie SELECT * FROM FAKTY WHERE FUNKCJA LIKE '%04%' zwróci stanowiska z funkcją osada otoczona rowem/rowami (MS04) a także grób szkieletowy katakumbowy (SS04).
Stosowanie kodów wymusza też na autorach pewną ścisłość w charakteryzowaniu stanowisk. Można to postrzegać jako zaletę, gdyż podwyższa to wartość bazy jako źródła archeologicznego, a także jako wadę, gdyż procesy społeczne nie zawsze można wtłoczyć w zmatematyzowany schemat. Jeżeli wykaz można rozszerzać o nowe pojęcia, to w przypadku, gdy brakuje odpowiedniego, można je dodać do tabeli. Natomiast w przypadku, gdy uzupełnianie wykazu jest niemożliwe, to trzeba próbować wykorzystać już istniejące, co może budzić oczywisty sprzeciw wobec utraty informacji.

niedziela, 16 grudnia 2012

Klasyfikacja funkcjonalno-kulturowo-chronologiczna: wykazy

Ostatnio sporo się działo w kwestii rozwoju QAZP2. Z radością donoszę, że wtyczka ma już zaimplementowane wszystkie funkcje, których wymagał program badawczy, w ramach którego aplikacja jest realizowana. Tym samym na podstawie zawartości bazy danych można wygenerować karty AZP zgodne ze specyfikacją Ministra Kultury i Dziedzictwa Narodowego. 

Jednym z najważniejszych elementów karty AZP jest określenie dla znalezionych śladów działalności człowieka  konotacji kulturowo-historycznej, czyli innymi słowy dokonanie klasyfikacji funkcjonalno-kulturowo-chronologicznej w oparciu o zebrane fakty, czyli na przykład fragmenty ceramiki, znalezione narzędzia i inne przedmioty, które archeologowi pozwalają określić wiek badanych osad, cementarzysk, itp. Aby przekaz był uniwersalny i czytelny dla każdego naukowca w Polsce do jego formułowania posługujemy się wykazami pojęć opracowanymi w Narodowym Instytucie Dziedzictwa. Taka standaryzacja ma niebagatelne znaczenie, gdyż czyni bazę danych uniwersalnym źródłem informacji nie tylko w ramach projektu, z którego pochodzi, ale dla wszystkich zainteresowanych analizą wydarzeń, które miały miejsce w przeszłości na terenach, z których pochodzą zebrane dane. 

Opracowano trzy zbiory zawierające pojęcia służące do określania chronologii (okresu dziejów, z których pochodzi obiekt osadniczy - na przykład epoka kamienia, epoka brązu, średniowiecze, nowożytność); jednostki kulturowej, która informuje, że dany przedmiot wykazuje podobieństwo w ramach pewnej grupy wskaźników; funkcji - określenie roli obiektu - na przykład cmentarzysko, osada, grodzisko, itd. Każdy z wykazów jest zapisywany w osobnej tabeli, gdyż ich struktura jest odmienna. Konstrukcja schematu bazy danych obsługiwanego przez QAZP2 wynika z tego, że ma ona dwa podstawowe zadania: 
  1. dostarczać informacje w celu ich wyświetlania,
  2. dostarczać informacje w celu ich przetwarzania i analizy.
Określenia każdej z właściwości (chornologii, jednostki kulturowej i funkcji) można dokonać na kilku poziomach szczegółowości. Na przykładzie chronologii wyróżnić można takie dwa: pierwszy poziom - epoka - na przykład epoka kamienia, epoka żelaza oraz drugi poziom - okres epoki - paleolit (czyli starsza epoka kamienia), II okres epoki brązu, Halsztad C (okres epoki żelaza). Użytkownik zgodnie ze swoimi umiejętnościami, wiedzą i możliwościami określa w ten sposób chronologię dla każdego znalezionego przedmiotu używając pojęć z pierwszego poziomu (mniej szczegółowo) albo drugiego (bardziej szczegółowo). Ma to znaczenie z uwagi na analizę danych, gdyż okres wpływów rzymskich różni się od okresu halsztackiego. Natomiast w przypadku wyświetlania, zwłaszcza w formie karty KEZA, która w dobie współczesnych technologii jest już tylko wyrazem zacofania polskich służb konserwatorskich, jest mniej znaczące. Stąd w każdej tabeli wykazów znajduje się pole skrót zawierajace wartość, która potem jest umieszczana na wydruku. Z kolei w kolumnie NAZWA zapisuje się wartości, które nie są pełną nazwą okresu chronologicznego, ale wyświetlona jest zrozumiała dla archeologa. Na przykład pisząc wartość HA C domyślamy się, że chodzi o Epokę żelaza - okres halsztacki C, z kolei nazwa Grupa mątewska wskazuje na neolityczną kulturę pucharów lejkowatych i to jest trzeci poziom dokładności w określeniu jednostki kulturowej. 
Taka konstrukcja jest wygodna w analizie danych, gdyż wszukując wszystkie ślady związane z okresem Neolitu nie trzeba znać ich szczegółowego oznaczenia, czyli zbędna jest wiedza, czy osada wiąże się z kulturą pucharów lejkowatych, kulturą amform kulistych, czy grupą radziejowską, gdyż wszystkie mieszczą się w zbiorze Neolit. Z kolei szukając faktów dotyczących grupy mątewskiej nie zajmujemy się kulturą ceramiki wstęgowej, ani pozostałymi grupami kultury pucharów lejkowatych.

sobota, 24 listopada 2012

Drukowanie rozbudowanej tabeli w Qt4

Tydzień temu pisałem o drukowaniu dokumentów w Pythonie stosując metody biblioteki Qt4. Wszystko w kontekście tworzenia Kart Ewidencji Zabytków Archeologicznych (KEZA), które wypełnia się przede wszystkim na okoliczność prowadzenia badań w ramach projektu Archeologicznego Zdjęcia Polski.
Przypatrując się wzorcowej karcie KEZA można zauważyć, że faktycznie jest to bardzo rozbudowana tabela ze scalonymi komórkami. Eksperyment przeprowadzony przy pomocy Excela wykazał, że podobny efekt można osiągnąć stosując tabelę z 60 kolumnami i 35 wierszami równej wysokości, która wypełnia arkusz A4.

 Wstawianie tabeli

To okazało się szczęśliwym zrządzeniem losu, ponieważ dzięki temu i wykorzystaniu klas QTextDocument i QTextCursor nie musiałem implementować własnoręcznie funkcji rysującej tabelę. Zamiast tego mogłem wykorzystać metodę insertTable(wiersze, kolumny, format) klasy QTextCursor. Znaczenie dwóch pierwszych parametrów powinno być oczywiste. W pierwszym podaje się liczbę wierszy, w drugim liczbę kolumn. W przypadku tworzenia karty KEZA istotny jest trzeci, za pomocą którego określa się właściwości tabeli, takie jak obramowanie (border-style), odległość między obramowaniem a zawartością komórki (cellpadding). Te i inne parametry określa się w obiekcie klasy QTextTableFormat, podawanym jako trzeci argument metody insertTable. Po wykonaniu zwraca ona obiekt klasy QTextTable.

Przykład

Kod programu Pythona rozpoczynając od inicjalizacji klasy QTextDocument do wstawienia nowej tabeli mógłby wyglądać następująco:

doc = QTextDocument()
cur = QTextCursor(doc)
fmt = QTextTableFormat()
fmt.setCellPadding(1)
fmt.setBorderStyle(QTextFrameFormat.BorderStyle_Solid)
keza = cur.insertTable(35,60,fmt)

W sześciu liniach została utworzona duża tabela, zawierająca ponad 2100 komórek. Teraz kwestią pozostaje ich scalenia w taki sposób, żeby po wszystkim przypominała wzór karty KEZA. Do połączenia grupy komórek można zastosować metodę mergeCells(y, x, wysokosc, szerokosc) klasy QTextTable, gdzie argumenty y oraz x  oznaczają lokalizację pierwszej komórki w grupie łączonych (licząc od lewego górnego narożnika), a wysokość i szerokość to odpowiednio liczba komórek w pionie i w poziomie, które mają być scalone. Chcąc połączyć 6 komórek w górnym lewym rogu tabeli o wymiarach 3 x 2 trzeba wykonać polecenie keza.mergeCells(0,0,2,3). W przypadku generowania karty KEZA takich operacji jest zbyt dużo, aby każdą z osobna zapisywać jako wywołanie powyższej funkcji, dlatego zamiast tego stosuję prosty schemat w postaci pliku CSV, który zawiera definicję każdej docelowej komórki.

Formatowanie komórek

Na koniec pozostaje problem, jak odwołać się do wybranej komórki i wstawić do niej zawartość. Za pomocą metody cellAt(y,x) klasy QTextTable uzyskuje się referencję do komórki o podanych współrzędnych, którą reprezentuje klasa QTextTableCell. Metodą firstCursorPosition() można ustawić w niej kursor (dla przypomnienia reprezentuje go klasa QTextCursor) a następnie użyć go do wstawienia np. tekstu przy pomocy insertText(tekst). To nie wszystko każdą z komórek można formatować. Do tego potrzeba uzyskać informacje o jej bieżącym wyglądzie przy pomocy metody format() klasy QTextTableCell, a następnie stosując odpowiednie metody zmienić formatowanie. Na przykład metoda setBackground(Qt.yellow) zmieni tło komórki z białego na żółty. Na koniec należy to formatowanie jawnie zaplikować do komórki wywołując metodę setFormat. Bez tego zmiana tła będzie bezskuteczna.

Kontynuacja przykładu

keza.mergeCells(0,0,2,3)
grupa = keza.cellAt(0,0) # pobiera scaloną przed chwilą grupę komórek
gf = grupa.format() # formatowanie komórek
gf.setFont(QFont('Times',8,QFont.DemiBold))
grupa.setFormat(gf) # jawne wprowadzenie formatowania
grupa.firstCursorPosition().insertText('QAZP2') # zawartość komórki

drukarka = QPrinter()
doc.print_(drukarka) # wydrukowanie dokumentu na urządzeniu.

niedziela, 18 listopada 2012

Programowanie w Qt4: drukowanie tabel

Obecnie na "tapecie" mam problem generowania Kart Ewidencji Zabytków Archeologicznych (w skrócie KEZA), która jest formą archiwizowania informacji pochodzących z badań archeologicznych. Jej koncepcja wiąże się z początkami programu Archeologicznego Zdjęcia Polski, którego celem jest inwentaryzacja śladów osadnictwa w celu zapewnienia im ochrony konserwatorskiej. Jej wzór zmieniał się z biegiem lat, przy czym najważniejszym założeniem było to, by wszystkie informacje mieściły się na jednej kartce A4, co miało uzasadnienie w czasach "analogowych" metod archwizowania danych (to znaczy polegających na maszynowym wypełnianiu kart i wkładaniu do teczek czy segregatorów). Ponieważ do sprawozdania z badań archeologicznych muszą zawsze być dostarczone wydrukowane karty KEZA, to oczywiste jest, że QAZP2 musi także udostępniać taką funkcjonalność.
W najprostszej postaci wszystko czego potrzebujemy do drukowania przy pomocy Qt4 to dwie klasy: QPainter oraz QPrinter. Przykład ich zastosowania może wyglądać następująco:
drukarka = QPrinter()
drukarka.setOutputFormat(QPrinter.PdfFormat) # rodzaj drukarki
drukarka.setOutputFileName("nowy_plik.pdf")
painter = QPainter()
painter.begin(drukarka)
painter.drawText(10, 10, 'Test') # wydrukowanie tekstu
drukarka.newPage() # wysuniecie pierwszej strony
painter.drawText(10, 10, 'Test 2') # tekst na drugiej stronie
painter.end()

W w takiej formie drukowanie nie wiąże się z żadną filozofią: klasa QPrinter reprezentuje uniwersalny interfejs urządzenia, który umożliwia drukowanie do pliku PDF, na kartkach papieru i inne. Z kolei QPainter wykorzystując ten kanał wspomaga programistę w pisaniu na "urządzeniu" tekstu, rysowaniu figur geometrycznych albo drukowaniu obrazków.
Ponieważ karta KEZA to faktycznie tabela, to powższy kod byłby znacząco bardziej skomplikowany i zwiększający prawodopodobnieństwo wystąpienia błędów. Aby procedura drukowania była trochę bardziej abstrakcyjna, to QAZP2 zamiast klasy QPainter została wykorzystana inna - QTextDocument, która jak sama nazwa wskazuje jest używana do reprezentowania dokumentów. Te mogą być tworzone przez użytkownika, który wpisuje zdania w polu tekstowym, albo automatycznie przy pomocy klasy QTextCursor, która służy do określania miejsca, w którym bieżący dokument jest edytowany i wstawiania do niego różnych obiektów - ciągów znaków, tabel, obrazków, których kształ można określać za pomocą znaczników HTML. Gdy dokument jest już gotowy wystarczy wywołać funkcję print_(drukarka) klasy QTextDocument do wysłania go na urządzenie wskazane w parametrze drukarka. W tej metodzie zawartość dokumentu jest tłumaczona na ciąg poleceń takich jak w przykładzie powyżej.
To podejście w odróżnieniu od "niskopoziomowego" ma tą zaletę, że pozwala się skupić na zawartości dokumentu i jego wyglądzie. To w jaki sposób zostanie ona przełożona na papier albo plik PDF pozostaje w gestii klasy QTextDocument. Jak zostało ono wykorzystane w przypadku generowania karty KEZA opiszę następnym razem.

sobota, 20 października 2012

Kontekst

Zanim zagłębię się w problemy technologiczne, chciałbym krótko nakreślić ich kontekst, czyli powód dla którego jest rozwijany program QAZP2. Historia rozpoczyna się w 2010 roku, kiedy w związku z rozpoczęciem projektu naukowego w Instytucie Prahistorii UAM, finansowanego ze środków Narodowego Instytutu Dziedzictwa, pojawiła się potrzeba ewidecjonowania wyników badań w relacyjnej bazie danych.  Ważnym składnikiem zapisywanych w niej informacji jest tak zwany komponent przestrzenny, czyli współrzędne geograficzne. W ten sposób wyniki badań mogą być analizowane w kontekście środowiska i krajobrazu, co ma się przyczyniać do lepszego wyjaśniania decyzji podejmowanych przez ludzi w przeszłości.
Jako kontener do przechowywania danych został wybrany system PostgreSQL wyposażony w rozszerzenie PostGIS, które to umożliwia zapisywanie informacji przestrzennych.
Biorąc pod uwagę marny stan finansów polskiej nauki i instytucji zainteresowanych wykorzystywaniem takich informacji do ochrony zabytków w Polsce podjęto decyzję, że wszystkie narzędzia powinny być bezpłatne i tym samym obniżyć próg wejścia. Dlatego do gromadzenia danych jest używany wspomniany PostgreSQL+PostGIS, a do ich wyświetlania program QuantumGIS (QGIS). Ta aplikacja umożliwia proste wprowadzanie danych przestrzennych i tekstowych, jednak ten mechanizm jest niewystarczający do wprowadzania szczegółowych informacji pochodzących z propspekcji terenowej. Rozbudowany formularz do wprowadzenia danych jest realizowany właśnie jako QAZP2.
Zgodnie z aktualnymi założeniami ma umożliwiać wprowadzanie informacji o miejscach, czyli punktach rejestrowanych za pomocą odbiornika GPS; trasach - czyli zapisu drogi, która została pokonana na ziemii albo w powietrzu w czasie wykonywania zdjęć lotniczych; stanowiskach - czyli odnalezionych śladach działalności człowieka - np. osadach, obozowiskach, osadach itp. Oprócz "świeżych" danych w bazie mają się znaleźć także archiwalne pochodzące z badań AZP prowadzonych na przestrzenii lat, które mniej więcej od ostatniej dekady XX wieku są zapisywane w postaci elektronicznej. Ważne w tym wszystkim jest niedestrukcyjny charakter badań, czyli to, że nie prowadzą one do zniszczenia śladów osdanictwa w trakcie wykopalisk, a główną przesłanką do ich prowadzenia, oprócz wyjaśniania przeszłości, jest ich efektywna ochrona przed zniszczeniem.
W obecnej wersji 0.6, która jest dostępna od Poniedziałku do bazy danych można już wprowadzać wszystkie zakładane typy informacji, czyli miejsca, trasy i stanowiska.