Harti si GIS
 

News  Technical Articles  Romanian Press 

MapInfo şi harta României - din nou în actualitate

Aşa după cum ştiţi probabil din numerele anterioare ale revistei PCReport, Microsoft a lansat odată cu Windows 95 şi noul pachet Office pentru Windows 95 ce conţine pe lângă clasicele Excel, PowerPoint şi Word şi o componentă noua - Schedule. Ceea ce este însă important pentru utilizatorul de Excel este noua capabilitate a acestui program de a ataşa hărţi documentelor cu care se lucrează, cu condiţia ca ele sa aibă un câmp comun de “join”.

Harta administrativa a Romaniei

Cum se ştie, Microsoft nu este un producător software oarecare, ci se află în top în acest domeniu. Ceea ce a făcut ca alegerea software-ului de desktop mapping compatibil cu hărţile ataşate documentelor Excel, să cântărească mult pe piaţa de desktop mapping. Opţiunea celor de la Microsoft a fost firma MapInfo şi formatul lor de reprezentare hărţi şi date şi acest lucru nu a mirat pe nimeni deoarece realizările celor de la MapInfo până acum confirmă poziţia de lider care o au pe piaţa de desktop mapping. După cum (probabil) se ştie, ei au dezvoltat un mediu propriu de scriere aplicaţii MapBasic ce oferă o unealtă deosebit de puternică pentru un programator.

Pentru utilizatorul de Excel din România, un ajutor deosebit de util îl constituie harta României 1 : 1 000 000 (Fig. 1) furnizată de Geo Strategies S.A. din Sibiu, firmă ce are ca obiect de activitate cartografierea digitală. Harta are ca şi informaţii câteva câmpuri utile pentru administraţie, populate deja cu informaţii veridice. Ceea ce vă propun în continuare este ca folosind informaţiile dintr-un spreadsheet Excel să actualizăm tabela MapInfo ce conţine aceasta hartă. (Pentru detalii suplimentare consultaţi articolul din PCReport despre MapBasic).

Idea de la care am pornit a fost să evit toate conversiile posibile de tabele dintr-un format în altul, folosind facilitatea limbajului MapBasic de a schimba date dinamic cu alte aplicaţii Windows (DDE). Astfel, tabela RBS.TAB din format MapInfo va fi deschisă în cadrul aplicaţiei şi se vor scana rând pe rând elementele unei coloane comune de “join” pentru a găsi liniile omoloage din tabela şi din spreadsheet-ul deja deschis în Excel. Cu informaţii din linia omoloagă se va actualiza tabela sub MapInfo.

Funcţiile de schimb dinamic de date folosite au cam aceeaşi sintaxă în orice limbaj de programare sub Windows. Sintaxa lor în MapBasic este următoarea:

 DDEinitiate(application_name,topic)
- returnează handler-ul unui canal de comunicaţii deschis sau 0 daca nu se poate iniţia un schimb de date

DDERequest$(channel, item_name)
- returnează un string reprezentând rezultatul “cererii” item_name de pe canalul channel

DDETerminate channel
- încheie sesiunea ataşată unui canal

DDETerminateAll
- încheie toate sesiunile de comunicare iniţiate anterior

Pentru a putea obţine de la Excel numele spreadsheet-ului deschis trimitem o cerere cu variabila topic =”topics”. Cum rezultatul diferă de la o versiune la alta, vom analiza string-ul obţinut şi vom putea decide asupra versiunii Excel (4, 5, 6 sau 7 - mai jos n-am testat). Cu numele de spreadsheet astfel obţinut se iniţiază o nouă legătură, dar de data aceasta cu tabelul Excel deschis. Vom presupune că pe prima linie a sa, informaţiile arată astfel:

ID NUME_RES JUDETUL POPULATIA COD_POST PREFIX_TEL

Coloana folosită drept cheie pentru join va fi NUME_RES. De aceea vom căuta printre celulele primei linii una care să contină această valoare folosind cereri DDERequest$. Daca se găseşte această coloană, atunci va începe actualizarea propriu-zisă, deschizând mai întâi tabela MapInfo de actualizat RBS.TAB.

Cu o buclă "while" simplă se va cauta apoi pentru fiecare valoare din câmpul NUME_RES din RBS.TAB linia pe care aceasta apare în tabelul Excel. Structura bazei de date a tabelei RBS.TAB este una identică cu cea a documentului Excel. Ceea ce se actualizează în tabel este valoarea câmpului JUDETUL, însă aceasta poate fi foarte uşor schimbată să putem alege orice alt câmp.

Este important de urmărit cum se obţine din spreadsheet-ul Excel curent valoarea unei celule. O simplă cerere (request) către document, menţionând ca topic string-ul ce formează adresa celulei (de ex. R12C4) furnizează informaţia cerută. Daca nu s-ar specifica decât o linie sau o coloană, funcţia va returna conţinutul întregii linii sau coloane respective.

În Figura 2. Se poate urmări listing-ul comentat al aplicaţiei scrise in MapBasic 3.0. După cum se vede, codul este unul foarte apropiat de BASIC, iar secvenţele de lucru cu tabele sunt cele clasice ale unui SQL. El a fost testat cu succes pe tabele mari de date şi a permis o foarte rapidă actualizare, evitând astfel operaţii anevoioase de conversii.

Cu cele arătate până aici reiese uşor că orice tabele existente în MapInfo pot fi actualizate extrem de simplu pe baza informaţiilor din Excel. Trebuie doar puţin efort de scriere a programului şi apoi totul vine de la sine. Dacă mai şi modifici pe ici-pe colo, acesta devine un puternic utilitar nu numai de actualizare dar şi de conversie. Succes!


Fig. 2. Listingul Aplicatiei MapBasic 3.0

! Script pentru actualizarea tabelelor
! din MapInfo cu date din Excel
! Cod sursa MapBasic 3.0 

! Orice program are o functie principala (gen C)
Declare Sub Main 

Sub Main
Dim chan_num, tab_marker, col_number,
       row_number, row_in_rbs as INTEGER
Dim topiclist, topicname, cell,
       path, to_look, to_update as STRING
Dim ready as LOGICAL
path=”C:\EXCEL\ “
chan_num=DDEInitiate("Excel","System")
if chan_num=0 then
         print "Excel not available at this moment "
         print "Check for an Excel instance!"
         End Program
end if
topiclist=DDERequest$(chan_num,"topics")
if topiclist="System" then 
         print "First you must open a valid spreadsheet in Excel!"
else

! In Excel 4 topiclist poate arata astfel:
! ": C:\Excel\romania.xls Sheet1 System"
! In Excel 5,6 si 7 topiclist poate arata astfel: 
! "[Book1]Sheet1 [Book2]Sheet2 ....."
! Vom prelucra sirul pentru a obtine numele spreadsheet-ului

if Left$(topiclist,1)=":" then
         tab_marker=InStr(3,topiclist,chr$(9))
         if tab_marker=0 then
                print "No Excel document in use!"
                End Program
         end if
         topicname=Mid$(topiclist,3,tab_marker-3)
else
         tab_marker=InStr(1,topiclist,chr$(9))
         topicname=Left$(topiclist,tab_marker-1)
end if 
DDETerminate chan_num

! Pina aici s-a gasit numele spreadsheet-ului din care vom citi 
! Acum incepe sesiunea de actualizare tabela
chan_num=DDEInitiate("Excel",topicname)
if chan_num=0 then
         print "There are errors communicating with "+ topicname
         End Program
end if 
ready = 0
col_number = 1

! In Excel pe prima linie sunt scrise numele cimpurilor
! Vom cauta coloana NUME_RES care este comuna tabelelor
cell=DDERequest$(chan_num,"R1C"+str$(col_number))
do while (len(cell)<>2)and not ready 
         if RTrim$(cell)="NUME_RES" then 
                  ready=1
         else
                  col_number=col_number+1
                  cell=DDERequest$(chan_num,"R1C"+str$(col_number))
         end if
loop 
if ready=0 then
         print "The spreadsheet doesn't have the right form"
         End Program
end if

! Acum incepe pentru fiecare linie din tabela MapInfo 
! cautarea sa in spreadsheet-ul Excel .
! Daca s-a gasit valoarea de "join" corecta se va
! face actualizarea coloanei JUDETUL cu valoarea citita din Excel
open table path+"rbs.tab" 
fetch first from rbs
row_in_rbs=1
do while not eot(rbs)
          to_look=rbs.nume_res
          ready=0
          row_number=2
          cell=DDERequest$(chan_num,"R"+str$(row_number)+"C"+str$(col_number))
          do while (len(cell)<>2)and not ready 
                  if RTrim$(cell)=Rtrim$(to_look) then 
                          ready=1
                          to_update=DDERequest$(chan_num,"R"+str$(row_number)+
                                           "C"+str$(col_number+1))
                          update rbs set judetul=to_update where rowid=row_in_rbs
                 else
                          row_number=row_number+1
                          cell=DDERequest$(chan_num,"R"+str$(row_number)+"C"+str$(col_number))
                 end if
          loop 
          row_in_rbs=row_in_rbs+1
          fetch next from rbs
loop 
DDETerminateAll
end if
end sub

 


PC Report
Nr.40, Ianuarie 1996

 


Copyright © Geo Strategies 1995-2004

January 2004