Technical Article

GeoPDF u Delphi-ju: Geospatne koordinate s PDFlibPas-om

Ve?ina programera misli o PDF stranici kao o listu papira s tekstom i slikama na njemu. Georeferencirani PDF je vi?e od toga. On nosi dovoljno informacija da uzme to?ku na stranici, izmjerenu u obi?nim jedinicama stranice, i prijavi geografsku ?irinu i du?inu na kojoj se nalazi u stvarnom svijetu. Ta jedina ?injenica je ono ?to pretvara PDF u koristan nosa? za topografsku kartu, katastarski plan, prikaz poplavne zone ili bilo koji GIS izvoz koji se mora ispisati i dalje imati smisla. Geometrija je tamo u datoteci; jedino je pitanje ?ita li je va? u?itava?

Razlog za?to se to propu?ta jest taj ?to se GeoPDF otvara i ispisuje to?no kao i svaki drugi PDF. Ni?ta na prikazanoj stranici ne najavljuje da je karta registrirana u koordinatnom sustavu. Registracija ?ivi u rje?nicima koji vise s objekta stranice, nikada se ne crtaju, a preglednik koji ih zanemaruje svejedno vam prikazuje kartu. Da biste radili bilo ?to prostorno s datotekom - o?itanja koordinata izmjere, reprojekciju, preklapanje s drugim slojevima - morate sami pro?i kroz te rje?nike

Dva standarda žive u divljini

?ita? koji ?eli rukovati datotekama iz stvarnog svijeta mora se nositi s dvije sheme georegistracije, jer su obje u optjecaju i odre?ena datoteka mo?e koristiti bilo koju. Starija je OGC kodiranje opisano u OGC 08-139r2, koje stranici pridru?uje LGIDict (rje?nik geoprostorne registracije). Ona prethodi bilo kakvom ISO blagoslovu i bila je de facto format za rane GeoPDF izlaze, tako da veliko tijelo naslije?enih karata nosi nju i ni?ta drugo

Moderna shema je ona koju je ISO standardizirao u ISO 32000-1 ?8.8.2. Umjesto jednog rje?nika na razini stranice, ona modelira geoprostorne podatke kao Viewport (vidni okvir) stranice s prilo?enim rje?nikom Measure (mjera), a rje?nik mjera imenuje geografski koordinatni sustav. To je kodiranje koje pi?u Acrobat i trenutni GIS izvoznici. Robusni uvoznik provjerava oboje: ?ita vidne okvire za ISO model i vra?a se na (ili dodatno provjerava) LGIDict za datoteke koje nose samo naslije?enu registraciju

Vidni okviri i njihove granice

U ISO modelu jedinica georegistracije je vidni okvir, a stranica ih mo?e imati nekoliko. Veliki list mo?e postaviti glavnu kartu u jedan pravokutnik, umetak u drugom mjerilu u drugi, a plo?u s legendom koja uop?e nije georeferencirana u tre?i. Svaki vidni okvir nosi BBox, pravokutnik na stranici kojim vidni okvir upravlja, tako da ?ita? zna na koji se dio lista primjenjuje odre?eni koordinatni sustav. Provjera pogotka kliknute to?ke na te okvire je na?in na koji preglednik odlu?uje koji rje?nik mjera koristiti

PDFlibPas izla?e vidne okvire odabrane stranice direktno. GetPageViewPortCount vra?a koliko ih ima, GetPageViewPortID pretvara indeks baziran na jedinici u ViewPortID ru?ku, a GetViewPortBBox ?ita grani?ni pravokutnik jednu po jednu dimenziju. Argument Dimension odabire koji rub ili opseg ?elite: 0 je Left, 1 je Top, 2 je Width, 3 je Height, 4 je Right, i 5 je Bottom

var
  Pdf: TPDFlib;
  vpCount, i, vpID: Integer;
  Left, Top, Width, Height: Double;
begin
  Pdf := TPDFlib.Create;
  try
    if Pdf.LoadFromFile('topo_sheet.pdf', '') <> 1 then
      raise Exception.Create('load failed');
    Pdf.SelectPage(1);

    vpCount := Pdf.GetPageViewPortCount;
    for i := 1 to vpCount do
    begin
      vpID := Pdf.GetPageViewPortID(i);
      Left   := Pdf.GetViewPortBBox(vpID, 0);
      Top    := Pdf.GetViewPortBBox(vpID, 1);
      Width  := Pdf.GetViewPortBBox(vpID, 2);
      Height := Pdf.GetViewPortBBox(vpID, 3);
      // Left/Top/Width/Height describe the map area for this viewport
    end;
  finally
    Pdf.Free;
  end;
end;

ViewPortID s vrijedno??u nula iz GetPageViewPortID zna?i da se vidni okvir na tom indeksu nije mogao prona?i, pa ga provjerite prije proslje?ivanja ru?ke dalje

Unutar rječnika mjera

Geometrija koja registrira stranicu u svijet ?ivi u rje?niku mjera pridru?enom vidnom okviru. GetViewPortMeasureDict vra?a MeasureDictID za zadani ViewPortID, ili nulu kada vidni okvir nema rje?nik mjera, ?to je uobi?ajen slu?aj za legendu ili plo?u s naslovom. Rje?nik mjera sadr?i tri stvari koje vrijedi pro?itati: koordinatne sustave na koje se odnosi, nizove koji povezuju to?ke stranice s geografskim to?kama i jedinicu u kojoj su izra?eni podaci o to?kama

Sama registracija su dva paralelna niza. GPTS is the array of geographic points, latitude and longitude pairs given in the geographic coordinate system. LPTS is the array of page-space points, expressed as fractions of the viewport's BBox so they survive scaling. Item n u LPTS-u i stavka n u GPTS-u imenuju istu fizi?ku lokaciju, jednom u koordinatama stranice i jednom na globusu. Tri ili vi?e takvih parova odre?uju afinu, ili u op?em slu?aju projektivnu, transformaciju koja preslikava bilo koju koordinatu stranice unutar vidnog okvira u svjetsku koordinatu. Njihovo ?itanje je stvar istovremenog prolaska kroz oba niza

var
  measID, gptsCount, lptsCount, j: Integer;
  lat, lon, px, py: Double;
begin
  measID := Pdf.GetViewPortMeasureDict(vpID);
  if measID <> 0 then
  begin
    gptsCount := Pdf.GetMeasureDictGPTSCount(measID);
    lptsCount := Pdf.GetMeasureDictLPTSCount(measID);
    // GPTS holds lat/lon pairs; LPTS holds the matching page fractions.
    // Both arrays are read with one-based item indices.
    j := 1;
    while j < gptsCount do
    begin
      lat := Pdf.GetMeasureDictGPTSItem(measID, j);
      lon := Pdf.GetMeasureDictGPTSItem(measID, j + 1);
      px  := Pdf.GetMeasureDictLPTSItem(measID, j);
      py  := Pdf.GetMeasureDictLPTSItem(measID, j + 1);
      // (px, py) on the page corresponds to (lat, lon) on the ground
      Inc(j, 2);
    end;
  end;
end;

Rje?nik mjera tako?er izvje?tava o svojim jedinicama prikaza putem GetMeasureDictPDU, koji uzima UnitIndex s vrijedno??u 1 za linearne, 2 za povr?inske ili 3 za kutne jedinice i vra?a kod koji identificira odre?enu jedinicu, na primjer metar ili me?unarodnu stopu za linearnu kategoriju. Niz Bounds, ?itan s GetMeasureDictBoundsItem, opisuje ?etverokut unutar vidnog okvira koji mjerenje zapravo pokriva, ?to nije uvijek puni pravokutnik

WKT naspram EPSG-a

Geografska ?irina i du?ina u GPTS-u su besmislene bez znanja kojem geografskom koordinatnom sustavu pripadaju, budu?i da koordinata 51.5, -0.1 slije?e na drugo fizi?ko mjesto pod WGS 84 nego pod starijim nacionalnim datumom. Rje?nik mjera odgovara na to kroz rje?nik koordinatnog sustava, do kojeg se dolazi s GetMeasureDictGCSDict za geografski sustav. PDF opisuje taj sustav na jedan od dva me?usobno zamjenjiva na?ina, a ?ita? mora prihvatiti bilo koji

Prvi je WKT, Well-Known Text, samostalan niz koji u potpunosti definira datum, elipsoid, po?etni meridijan i jedinice. Op?iran je, ali nedvosmislen i ne treba vanjsku tablicu pretra?ivanja. Drugi je EPSG kod, jedan cijeli broj koji indeksira koordinatni sustav u EPSG registru; 4326 je WGS 84, okvir koji koristi ve?ina potro?a?kih GPS podataka. EPSG je kompaktan, ali pretpostavlja da ?ita? mo?e rije?iti kod u odnosu na bazu podataka. Datoteke se pojavljuju s jednim, drugim ili oboma, zbog ?ega API prikazuje sva tri poziva GetCSDictType, GetCSDictEPSG i GetCSDictWKT. GetCSDictType javlja je li sustav geografski (GEOGCS, povratna vrijednost 1) ili projiciran (PROJCS, povratna vrijednost 2), omogu?uju?i vam da ispravno protuma?ite ostatak prije nego ?to mu povjerujete

var
  gcsID, csType, epsg: Integer;
  wkt: WideString;
begin
  gcsID := Pdf.GetMeasureDictGCSDict(measID);
  if gcsID <> 0 then
  begin
    csType := Pdf.GetCSDictType(gcsID);   // 1 = GEOGCS, 2 = PROJCS
    epsg   := Pdf.GetCSDictEPSG(gcsID);   // e.g. 4326 for WGS 84, 0 if absent
    wkt    := Pdf.GetCSDictWKT(gcsID);    // full text description, '' if absent
    // Prefer EPSG when present; fall back to parsing WKT otherwise.
  end;
end;

Čitanje naslijeđenog LGIDict-a

Naslijeđeni OGC model georegistracije ne koristi vidne okvire. LGIDict je rječnik na razini stranice koji sadrži izravne informacije o projekciji i transformacijske parove. Iako je zastario prema ISO standardu, i dalje je prisutan u mnogim GIS izvozima. PDFlibPas pruža pozive za provjeru i čitanje ovog rječnika ako vidni okviri nisu definirani.

var
  lgiCount, k: Integer;
  dictText: WideString;
begin
  lgiCount := Pdf.GetPageLGIDictCount;
  for k := 1 to lgiCount do
  begin
    dictText := Pdf.GetPageLGIDictContent(k);
    // dictText carries the OGC 08-139r2 registration to parse
  end;
end;

Spajanje očitanja

Potpuni uvoznik tretira dvije sheme kao par prolaza preko svake stranice. Odaberite stranicu, zatra?ite od GetPageViewPortCount ISO vidne okvire, i za svaki vidni okvir koji posjeduje rje?nik mjera izvucite njegov BBox, njegove GPTS i LPTS nizove, njegovu jedinicu podataka to?ke i opis GCS-a kroz rje?nik koordinatnog sustava. Zatim provjerite GetPageLGIDictCount za bilo koju naslije?enu registraciju koju prolaz vidnog okvira nije pokrio. Karta koja nosi oboje trebala bi se slagati; karta koja nosi samo jedno i dalje se rje?ava, jer ste tra?ili na oba mjesta. Ru?ke vra?ene usput, ViewPortID, MeasureDictID, CSDictID, obi?ni su cijeli brojevi koji ostaju va?e?i dok je dokument u?itan, tako da je cijeli prolaz nekoliko ugnije??enih petlji preko popisa stranica bez alokacije kojom treba upravljati

Jednom kada mo?ete oporaviti registraciju, stranica postaje izvor podataka, a ne slika. Prate?e tehnike za ?itanje ostatka stranice pokrivene su u ?lanku o ekstrakciji teksta, slika i fontova, a iscrtavanje georeferenciranog lista na ure?aj za mjerenje na zaslonu opisano je u vodi?u kroz kontekst ure?aja za ispis i pregled. Geospatni ?ita? koji je ovdje opisan isporu?uje se kao dio softvera losLab PDF Library za Delphi i C++Builder, zajedno s API-jima za u?itavanje, ekstrakciju i prikazivanje koji su pokriveni drugdje na ovom blogu