Capítulo 4. Usando PostGIS

Índice

4.1. Objetos de GIS
4.1.1. Padrões de OpenGIS WKB e WKT
4.1.2. Padrões de PostGISEWKB, EWKT e Formas Canônicas
4.1.3. SQL-MM Parte 3
4.2. Usando Padrões de OpenGIS
4.2.1. Tabela de Sistemas de Referências Espacial (SPATIAL_REF_SYS)
4.2.2. Tabela de Colunas Geométricas (GEOMETRY_COLUMNS)
4.2.3. Criando uma Tabela Espacial
4.2.4. Assegurando-se conforme a geometria de OpenGIS
4.3. Carregando Dados de GIS
4.3.1. Usando SQL
4.3.2. Usando o Carregador
4.4. Recuperando Dados de GIS
4.4.1. Usando SQL
4.4.2. Usando o Descarregador
4.5. Construindo Índices
4.5.1. Índices GiST
4.5.2. Usando Índices
4.6. Queries Complexas
4.6.1. Vantagens dos Índices
4.6.2. Exemplos de SQL Espacial
4.7. Usando Mapserver
4.7.1. Uso Básico
4.7.2. Perguntas Mais Frequentes
4.7.3. Uso Avançado
4.7.4. Exemplos
4.8. Clientes Java (JDBC)
4.9. Clientes C (libpq)
4.9.1. Cursores de Texto
4.9.2. Cursores Binários

4.1. Objetos de GIS

Suporte PostGIS a objetos de GIS são "Simple Features" (Características Simples) definidas pelo OpenGIS Consortium (OGC). Note que PostGIS suporta atualmente as características e a representação de APIs, mas não as várias comparações e operadores de convolução cedidos na especificação OGC "Simple Features for SQL".

PostGIS estende o padrão com suport para coordenadas 3DZ, 3DM e 4D.

4.1.1. Padrões de OpenGIS WKB e WKT

A especificação OpenGIS define dois caminhos padrões de objeto espacial de expressão: a forma Well-Known Text (WKT) e a forma Well-Known Binary (WKB). Ambos, WKT and WKB, incluem informação sobre o tipo do objeto e as coordenadas a qual forma o objeto.

Exemplos das representações de texto das características são como segue:

  • POINT(0 0)

  • LINESTRING(0 0,1 1,1 2)

  • POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))

  • MULTIPOINT(0 0,1 2)

  • MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))

  • MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))

  • GEOMETRYCOLLECTION(POINT(2 3),LINESTRING((2 3,3 4)))

A especificação de OpenGIS requer também que o formato de armazenamento interno de objetos espaciais inclui um identificador de sistema referenciado espacial (SRID). O SRID é requerido ao criar objetos espaciais para a inserção no banco de dados.

Input/Output desses formatos está disponível usando as seguintes relações:

	bytea WKB = asBinary(geometry);
text WKT = asText(geometry);
geometry = GeomFromWKB(bytea WKB, SRID);
geometry = GeometryFromText(text WKT, SRID);

Por exemplo, uma declaração válida de inserção para criar e inserir um objeto espacial de OGC seria::

	INSERT INTO SPATIALTABLE (
THE_GEOM,
THE_NAME
)
VALUES (
GeomFromText('POINT(-126.4 45.32)', 312),
'A Place'
)

4.1.2. PostGIS Padrões EWKB, EWKT e Formas Canônicas

Somente o formato OGC suporta geometria 2d, e o SRID associado *nunca* faz parte das respresentações do input/output.

Formatos de extensão Postgis são atualmente superset de um OGC(cada WKB/WKT válido é um EWKB/EWKT válido), mas mas isto pôde variar no futuro, especificamente se OGC saísse com um formato novo que opõe a nossas extensões. Assim você NÃO DEVE confiar nesta característica!

Postgis EWKB/EWKT soma o suport a coordenadas 3dm,3dz,4d e faz parte das informações SRID.

Exemplos das representações do texto (EWKT) dos objetos espaciais estendidos das características são como segue:

  • POINT(0 0 0) -- XYZ

  • SRID=32632;POINT(0 0) -- XY with SRID

  • POINTM(0 0 0) -- XYM

  • POINT(0 0 0 0) -- XYZM

  • SRID=4326;MULTIPOINTM(0 0 0,1 2 1) -- XYM with SRID

  • MULTILINESTRING((0 0 0,1 1 0,1 2 1),(2 3 1,3 2 1,5 4 1))

  • POLYGON((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0))

  • MULTIPOLYGON(((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0)),((-1 -1 0,-1 -2 0,-2 -2 0,-2 -1 0,-1 -1 0)))

  • GEOMETRYCOLLECTIONM(POINTM(2 3 9),LINESTRINGM((2 3 4,3 4 5)))

Input/Output desses formatos são usados conforme a interface a seguir:

	bytea EWKB = asEWKB(geometry);
text EWKT = asEWKT(geometry);
geometry = GeomFromEWKB(bytea EWKB);
geometry = GeomFromEWKT(text EWKT);

Por exemplo, uma declaração válida de inserção para criar e inserir um objeto espacial seria:

	INSERT INTO SPATIALTABLE (
THE_GEOM,
THE_NAME
)
VALUES (
GeomFromEWKT('SRID=312;POINTM(-126.4 45.32 15)'),
'lugar'
)

A "canonical form" (forma canônica ) de um tipo PostgreSQL são as representações que pega com uma simples "query" (sem uma chamada de função) e no qual é garantido para ser aceito com uma inserção simples, atualização ou cópia. Para o postgis tipo 'geometry' são esses:

	- Output -
binary: EWKB
ascii: HEXEWKB (EWKB in hex form)

- Input -
binary: EWKB
ascii: HEXEWKB|EWKT

Para o exemplo esta indicação lê EWKT e retorna HEXEWKB no processo do input/output canônico do ascii:

	=# SELECT 'SRID=4;POINT(0 0)'::geometry;
geometry
----------------------------------------------------
01010000200400000000000000000000000000000000000000
(1 row)

4.1.3. SQL-MM Part 3

A especificação Espacial de Aplicações de Multimedia do SQL estende as simples características para especificações do SQL, definindo um número de curvas inseridas circularmente.
As definições SQL-MM incluem  coordenadas 3dm, 3dz e 4d, mas não permite embutir informação SRID.
The well-known text extensions are not yet fully supported. Examples of some simple curved geometries are shown below:
As extensões de texto conhecidas não são suportadas ainda por completo. Os exemplos de algumas geometrias curvadas simples são mostrados abaixo:

  • CIRCULARSTRING(0 0, 1 1, 1 0)

  • COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 1 0),(1 0, 0 1))

  • CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1))

  • MULTICURVE((0 0, 5 5),CIRCULARSTRING(4 0, 4 4, 8 4))

  • MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1)),((10 10, 14 12, 11 10, 10 10),(11 11, 11.5 11, 11 11.5, 11 11)))

Nota

Atualmente, PostGIS não pode suportar o uso de curvas compostas (Compound Curves) em um polígono curvo (Curve Polygon).

Nota

           Todas as comparações do ponto flutuante dentro da implementação de SQL-MM são executadas para uma tolerância especificada, atualmente 1E-8.

4.2. Usando Padrões de OpenGIS

O OpenGIS "Simple Features Specification for SQL" define tipos de objetos padrão GIS, as funções requeridas para manipulá-las e uma especificação de tabela de meta-dados. Para asse- gurar que os meta-dados permaneçam consistentes, operações como criar e remover uma coluna espacial são carregadas fora através da definição procedures especiais por OpenGIS.
Existem duas tabelas de meta-dados OpenGIS: SPATIAL_REF_SYS e GEOMETRY_COLUMNS. A tabela SPATIAL_REF_SYS carrega os identificadores numéricos e descrições textuais de sistemas de coordenada usadas no banco de dados espacial.

4.2.1. Tabela de Sistemas de Referências Espacial (SPATIAL_REF_SYS)

A definição da Tabela de Sistemas de Referências Espacial (SPATIAL_REF_SYS) é como segue:

CREATE TABLE SPATIAL_REF_SYS (
SRID INTEGER NOT NULL PRIMARY KEY,
AUTH_NAME VARCHAR(256),
AUTH_SRID INTEGER,
SRTEXT VARCHAR(2048),
PROJ4TEXT VARCHAR(2048)
)

As colunas SPATIAL_REF_SYS são como segue:

SRID

Um valor inteiro que exclusivamente identifica o Sistema de Referência Espacial (Spacial Referencing System - SRS) dentro do banco de dados.

AUTH_NAME

Nome do padrão ou corpo de padrões que estão sendo citados para este sistema de referência. Por exemplo, "EPSG" seria um AUTH_NAME válido.

AUTH_SRID

O ID do Sistema de Referência Espacial  (SRID) como definido pela autoridade citada no AUTH_NAME. No caso de EPSG, é onde o código de projeção EPSG ficaria.

SRTEXT

Representação de Well-Known Text do Sistema de Referência Espacial (WKT SRS). Um exemplo de uma representação WKT SRS é:

PROJCS["NAD83 / UTM Zone 10N",
GEOGCS["NAD83",
DATUM["North_American_Datum_1983",
SPHEROID["GRS 1980",6378137,298.257222101]
],
PRIMEM["Greenwich",0],
UNIT["degree",0.0174532925199433]
],
PROJECTION["Transverse_Mercator"],
PARAMETER["latitude_of_origin",0],
PARAMETER["central_meridian",-123],
PARAMETER["scale_factor",0.9996],
PARAMETER["false_easting",500000],
PARAMETER["false_northing",0],
UNIT["metre",1]
]

Para uma listagem de códigos de projeção Grupo de Exame Europeu do Petróleo (EPSG - European Petroleum Survey Group) e suas correspondentes representações, veja http://www.opengis.org/techno/interop/EPSG2WKT.TXT. Para uma discussão de WKT em geral, veja OpenGIS "Coordinate Transformation Services Implementation Specification" em http://www.opengis.org/techno/specs.htm. Para informações do Grupo de Exame Europeu do Petróleo (EPSG - European Petroleum Survey Group) e seu banco de dados de sistemas de referência espacial, veja: http://epsg.org/.

PROJ4TEXT

PostGIS usa a biblioteca Proj4 para fornecer potencialidades de transformaçãocoordenadas . A coluna de PROJ4TEXT contem a string de definição de coordenada Proj4 para um SRID particular. Por exemplo:

+proj=utm +zone=10 +ellps=clrk66 +datum=NAD27 +units=m

Para mais informações a respeito, veja a página de Proj4 em http://www.remotesensing.org/proj. O arquivo spatial_ref_sys.sql contém ambas definições, SRTEXT and PROJ4TEXT,para todas as projeções.

4.2.2. Tabela de Colunas Geométricas (GEOMETRY_COLUMNS)

A definição de Tabela de Colunas Geométricas (GEOMETRY_COLUMNS) é como segue:

CREATE TABLE GEOMETRY_COLUMNS (
F_TABLE_CATALOG VARCHAR(256) NOT NULL,
F_TABLE_SCHEMA VARCHAR(256) NOT NULL,
F_TABLE_NAME VARCHAR(256) NOT NULL,
F_GEOMETRY_COLUMN VARCHAR(256) NOT NULL,
COORD_DIMENSION INTEGER NOT NULL,
SRID INTEGER NOT NULL,
TYPE VARCHAR(30) NOT NULL
)

As colunas são como segue:

F_TABLE_CATALOG, F_TABLE_SCHEMA, F_TABLE_NAME

Nome completamente qualificado da característica tabela contendo a coluna geométrica. Note que as condições "catalog" e "schema" são Oracle-ish.
Não existe análogo de "catalog" PostgreSQL de forma que a coluna é espaço em branco a esquerda - para "schema" o nome de banco de dados PostgreSQL é usado. (public é o default).

F_GEOMETRY_COLUMN

O nome da coluna geométrica na tabela característica

COORD_DIMENSION

Dimensão de espaço (2, 3 ou 4 dimensional) da coluna.

SRID

Identificador do sistema de referência espacial usado para a coordenada geométrica nesta tabela. É uma chave de referência estrangeira para o SPATIAL_REF_SYS.

TYPE

Tipo do objeto espacial. Restringir a coluna espacial a um único tipo, usar um:

POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION or corresponding XYM versions POINTM, LINESTRINGM, POLYGONM, MULTIPOINTM, MULTILINESTRINGM, MULTIPOLYGONM, GEOMETRYCOLLECTIONM. Para coleções heterogêneas (mixed-type), você pode usar "GEOMETRY" como tipo.

Nota

Este atributo não é (provavelmente) parte da especificação OpenGIS, mas é requerido para homogeneidade de tipo assegurado.

4.2.3. Criando uma Tabela Espacial

Criação de uma tabela com dados espaciais é feito em duas fases:

  • Criar uma tabela normal , ou seja, sem dados espacias.

    Por exemplo: CREATE TABLE ROADS_GEOM ( ID int4, NAME varchar(25) )

    Acrescentar uma coluna espacial para a tabela que usa a função OpenGIS "AddGeometryColumn."

    A sintaxe é:

    AddGeometryColumn(<schema_name>, <table_name>,
    <column_name>, <srid>, <type>,
    <dimension>)

    ou, usando "schema" corrente:

    AddGeometryColumn(<table_name>,
    <column_name>, <srid>, <type>,
    <dimension>)

    Exemplo1: SELECT AddGeometryColumn('public', 'roads_geom', 'geom', 423, 'LINESTRING', 2)

    Exemplo2: SELECT AddGeometryColumn( 'roads_geom', 'geom', 423, 'LINESTRING', 2)

Existe um exemplo de SQL usado para criar tabela e adicionar uma coluna espacial (assumindo que um SRID de 128 já existe):

CREATE TABLE parks ( PARK_ID int4, PARK_NAME varchar(128), PARK_DATE date, PARK_TYPE varchar(2) );
SELECT AddGeometryColumn('parks', 'park_geom', 128, 'MULTIPOLYGON', 2 );

Existe outro exemplo, usando o tipo "geometry" genérico e o indefinido SRID de valor -1:

CREATE TABLE roads ( ROAD_ID int4, ROAD_NAME varchar(128) );
SELECT AddGeometryColumn( 'roads', 'roads_geom', -1, 'GEOMETRY', 3 );

4.2.4. Assegurando-se conforme a geometria de OpenGIS

A maioria das funções executadas pela biblioteca de GEOS confiam na suposição que suas geometrias são válidas como especificadas pela Especificação de Característica Simples de OpenGIS (OpenGIS Simple Feature Specification). Para verificar a validade das geometrias você pode usar a função IsValid():

gisdb=# select isvalid('LINESTRING(0 0, 1 1)'), isvalid('LINESTRING(0 0,0 0)');
isvalid | isvalid
---------+---------
t | f

Por default, PostGIS não aplica esta verificação de validade na entrada da geometria, porque testar a validade necessita lotes de tempo do processador central (CPU) para geometrias complexas, especialmente poligonos. Se não confiar em suas fontes de dados, pode manualmente reforçar tal verificação a suas tabelas, adicionando um confinamento da verificação:

ALTER TABLE mytable ADD CONSTRAINT geometry_valid_check CHECK (isvalid(the_geom));

Se você encontrasse quaisquer mensagens de erro estranhas como "GEOS Intersection() apresentou um erro!" ou "JTS Intersection() apresentou um erro!" quando chamar funções PostGIS com entrada de geometrias válidas, você provavelmente encontrou um erro em PostGIS ou em uma das bibliotecas de uso dele, e você deve contatar os colaboradores de PostGIS. O mesmo é verdadeiro se uma função de PostGIS retornar uma geometria inválida para a entrada válida.

Note

Estritamente as geometrias de OGC não podem ter valores de Z ou de M. A função válida IsValid() não considerará geometrias altamente calculadas as dimensões inválidas! Invocações de AddGeometryColumn() adicionará confinamente, verificando dimensões da geometria, assim como é bastante para especificar.

4.3. Carregando Dados de GIS

Uma vez que você criou uma tabela espacial, você está pronto para atualizar os dados de GIS no banco de dados. Atualmente, existem dois caminhos para entrar com os dados no banco de dados PostGIS/PostgreSQL: usando declarações de SQL formatadas ou usando o carregador/descarregador de arquivo Shape.

4.3.1. Usando SQL

Se você pode converter dados de uma representação de texto, então usando SQL formatado poderia ser o modo mais fácil de entrar com seus dados em PostGIS. Como com Oracle e outros bancos de dados de SQL, os dados podem ser carregados em grandes quantidades e transportados em um grande arquivo de texto SQL cheio de declarações de "INSERT" dentro do terminal SQL.
A carga de um arquivo de dados (roads.sql por exemplo) poderia se parecer como segue:

BEGIN;
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (1,GeomFromText('LINESTRING(191232 243118,191108 243242)',-1),'Jeff Rd');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (2,GeomFromText('LINESTRING(189141 244158,189265 244817)',-1),'Geordie Rd');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (3,GeomFromText('LINESTRING(192783 228138,192612 229814)',-1),'Paul St');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (4,GeomFromText('LINESTRING(189412 252431,189631 259122)',-1),'Graeme Ave');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (5,GeomFromText('LINESTRING(190131 224148,190871 228134)',-1),'Phil Tce');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (6,GeomFromText('LINESTRING(198231 263418,198213 268322)',-1),'Dave Cres');
COMMIT;

O arquivo de dados pode ser transportado facilmente para dentro do PostgreSQL usando o monitor de terminal SQL "psql":

psql -d [database] -f roads.sql

4.3.2. Usando o Carregador

O carregador de dados shp2pgsql converte arquivos ESRI Shape dentro do SQL de maneira correta para inserção em um banco de dados de PostGIS/PostgreSQL. O carregador tem vários modos operacionais distinguidos em linha de comando por parametro:
-d

Exclui a tabela do banco de dados antes de criar uma nova tabela com os dados no arquivo Shape.

-a

Acrescenta dados do arquivo Shape na tabela de banco de dados. Note que, para usar esta opção para carregar arquivos múltiplos, os arquivos têm que ter os mesmos atributos e mesmos tipos de dados.

-c

Cria uma nova tabela e insere dados do arquivo Shape. Este parametro é o modo padrão.

-p

Produz somente o código do SQL da criação da tabela, sem adicionar nenhum dado real. Isto pode ser usado se você necessitar separar completamente as etapas da criação da tabela e do carregamento dos dados.

-D

Cria uma nova tabela e insere dados do arquivo Shape. Este parametro usa o "dump" formato PostgreSQL para os dados de produção e é muito mais rápido carregar que o padrão "insert" formato SQL. Use isto para quantidades grandes de dados. Use o formato do "dump" de PostgreSQL para os dados da saída. Isto pode ser combinado com - a, - o c e - d. É muito mais rápido carregar do que o default de inserção do formato SQL. Use isto para séries de dados muito grandes.

-s <SRID>

Cria e insere tabelas de geometria com o SRID especificado.

-k

Conserva identificadores de caso (coluna, schema e atributos). Note que os atributos em Shapefile são todos UPPERCASE.

-i

Conserva identificadores de caso (coluna, schema e atributos). Note que os atributos em Shapefile são todos UPPERCASE.

-w

Formato de saída WKT, para o uso com versões de PostGISanteriores (0.x). Note que isto introduzirá trações coordenadas e deixará cair valores de M de shapefiles.

-W <encoding>

Specify encoding of the input data (dbf file). When used, all attributes of the dbf are converted from the specified encoding to UTF8. The resulting SQL output will contain a SET CLIENT_ENCODING to UTF8 command, so that the backend will be able to reconvert from UTF8 to whatever encoding the database is configured to use internally.

          Especificar codificando os dados de entrada (arquivo dbf). Quando usados, todos os atributos do dbf são convertidos da codificação especificada
          para UTF8. A saída resultante do SQL conterá um comando SET CLIENT_ENCODING para UTF8, de modo que o retorno estará apto para uma     
          conversão de UTF8 para qualquer codificação de banco de dados que é configurado para usar internamente.

Note que - a, - c, - d e - p é mutuamente exclusivo.

Uma sessão de exemplo que usa o carregador para criar um arquivo e carregá-lo poderia ser como segue:

# shp2pgsql shaperoads myschema.roadstable > roads.sql
# psql -d roadsdb -f roads.sql

Podem ser feitos uma conversão e carga de tudo em um único comando, usando caminhos (pipes) como no UNIX:

# shp2pgsql shaperoads myschema.roadstable | psql -d roadsdb

4.4. Recuperando Dados de GIS

Podem ser extraídos dados do banco de dados usando outro SQL ou o arquivo carregador/descarregador Shape. No item SQL discutiremos alguns dos operadores disponível para fazer comparações e selecionar tabelas espaciais.

4.4.1. Usando SQL

Os meios mais diretos de extrair dados do banco de dados são usar um SQL, para selecionar dados e descarregar as colunas resultantes em um arquivo de texto:

db=# SELECT id, AsText(geom) AS geom, name FROM ROADS_GEOM;
id | geom | name
---+-----------------------------------------+-----------
1 | LINESTRING(191232 243118,191108 243242) | Jeff Rd
2 | LINESTRING(189141 244158,189265 244817) | Geordie Rd
3 | LINESTRING(192783 228138,192612 229814) | Paul St
4 | LINESTRING(189412 252431,189631 259122) | Graeme Ave
5 | LINESTRING(190131 224148,190871 228134) | Phil Tce
6 | LINESTRING(198231 263418,198213 268322) | Dave Cres
7 | LINESTRING(218421 284121,224123 241231) | Chris Way
(6 rows)

Porém, haverá restrições que será necessário reduzir o número de campos devolvido. No caso de restrições atributos-baseados, usar exatamente a mesma sintaxe de SQL como normal com uma tabela não espacial. No caso de restrições espaciais, os operadores seguintes são habilitados/completos:

&&

Este operador diz se caixa delimitada de uma geometria sobrepõe caixa delimitada de outra.

~=

Estes operadores testam se duas geometrias são geometricamente idênticas. Por exemplo,se ' POLYGON((0 0,1 1,1 0,0 0)) ' está igual a ' POLYGON((0 0,1 1,1 0,0 0)) '.

=

Este operador é um pequeno mais ingênuo, só testa se as caixas delimitadas para geometrias é o mesmo.

Logo, você pode usar estes operadores em questão. Note que ao especificar geometrias e caixas na linha de comando SQL, você tem que transformar as representações de string explicitamente em geometrias usando a função "GeometryFromText () ". Por exemplo:

SELECT
ID, NAME
FROM ROADS_GEOM
WHERE
GEOM ~= GeomFromText('LINESTRING(191232 243118,191108 243242)',-1);

A "query" anterior devolveria o único registro da tabela "ROADS_GEOM" pela qual a geometria era igual aquele valor.

Ao usar o operador "&& ", pode especificar um outro BOX3D como característica de comparação ou um GEOMETRY. Porém, quando você especifica um GEOMETRY que sua caixa delimitada será usada para a comparação.

SELECT
ID, NAME
FROM ROADS_GEOM
WHERE
GEOM && GeomFromText('POLYGON((191232 243117,191232 243119,191234 243117,191232 243117))',-1);

A "query" anterior usará a caixa delimitada do polígono para propósitos de comparação.

A "query" espacial mais comum provavelmente será uma query "frame-based", usada por cliente de software, como navegador de dados e mapas na web, pegar um valor de dados "map-frame" para exibição. Usando um objeto "BOX3D" para a visualização, como demonstrado como segue:

SELECT
AsText(GEOM) AS GEOM
FROM ROADS_GEOM
WHERE
GEOM && GeomFromText('BOX3D(191232 243117,191232 243119)'::box3d,-1);

Note que o uso do SRID, especifica a projeção do BOX3D. O valor -1 é usado para indicar nenhum SRID especificado.

4.4.2. Usando o Descarregador

O descarregador de tabela pgsql2shp conecta diretamente ao banco de dados e converte uma tabela em um arquivo Shape. A sintaxe básica é:

pgsql2shp [<options>] <database> [<schema>.]<table>
pgsql2shp [<options>] <database> <query>

As opções de linha de comando são:

-f <filename>

Escreva uma saída para um nome de arquivo particular.

-h <host>

O banco de dados do host para conectar.

-p <port>

A porta para conectar ao banco de dados do host.

-P <password>

A senha para usar a conexão do banco de dados.

-u <user>

O nome do usuário para usar a conexão do banco de dados.

-g <geometry column>

No caso de tabelas com colunas de geometria múltiplas, usar a coluna de geometria quando escrever o arquivo Shape.

-b

Use um cursor binário. Isto fará a operação mais rápida, mas não trabalhará se qualquer atributo da NON-geometry na tabela faltar um molde ao texto.

-r

Modalidade pura. Não destrua o campo "gid", ou nomes da coluna "escape".

-d

Para a compatibilidade inversa: escrever um arquivo shape 3-dimensional, quando descarregar do banco de dados de postgis anteriores (pre-1.0.0) - o padrão é escrever um arquivo Shape 2- dimensional neste caso). Inicie de postgis-1.0.0+, as dimensões são codificadas inteiramente.

4.5. Construindo Índices

Índice é o que faz usando um banco de dados espacial para um possível bancos de dados grandes. Sem indexação, nenhuma busca por característica requereria uma procura sequencial de todo registro no banco de dados. Velocidades indexadas para cima procurando os dados organizados em uma árvore de procura que pode ser atravessada para achar um registro rapidamente. PostgreSQL apóia três tipos de índices através do padrão:
Índices B-Trees, índices R-Trees e Índices GiST.

  • B-Trees são usadas para dados que podem ser ordenados ao longo de um eixo; por exemplo, números, cartas, datas. Dados de GIS não podem ser racionalmente ordenados ao longo de um eixo (o qual é maior, (0,0) ou (0,1) ou (1,0)?) assim indexação B-Tree é inútil para nós.

  • R-Trees abre dados em retângulos, sub-retângulos, e sub-sub retângulos, etc. R-Trees são
    usados por alguns bancos de dados espaciais para indexar dados de GIS, mas uma implementação R-Tree PostgreSQL não é como uma implementação robusta de GiST.

  • Índices GiST (Generalized Search Trees) abre dados em "things to one side" (pense por um lado), "things which overlap" (coisas que sobreponham), "things which are inside" (coisas que estão dentro) e podem ser usadas em uma gama extensiva de tipos de dados, inclusive dados de GIS. PostGIS usa um índice de R-Tree implementado em cima de GiST para indexar dados de GIS.

4.5.1. Índices GiST

GiST representa "Generalized Search Tree" e é uma forma generalizada de indexar. Além da da indexação de GIS, GiST é usada para acelerar buscas em todos os tipos de estruturas de dados irregulares (arranjos de números inteiros, dados espectrais, etc) que não são amenos a indexação normal B-Tree.

Uma vez que uma tabela de dados de GIS excede algumas mil linhas, você poderá construir um índice para buscas espaciais de dados (a menos que todas suas buscas estejam baseadas em atributos, pelo qual você queira construir um índice normal nos campos de atributo).

A sintaxe para construir um índice de GiST em uma coluna de geometria é como segue:

CREATE INDEX [indexname] ON [tablename]
USING GIST ( [geometryfield] GIST_GEOMETRY_OPS );

Construindo um índice espacial é um exercício computacionalmente intensivo: em tabelas ao redor de 1 milhão de linhas, em uma máquina de 300MHz Solaris, achamos que com a construção de um índice GiST leva aproximadamente 1 hora. Depois de construir um índice, é importante forçar PostgreSQL a coletar estatísticas de tabela que são usadas para otimizar planos de "query":

VACUUM ANALYZE [table_name] [column_name];

-- This is only needed for PostgreSQL 7.4 installations and below
SELECT UPDATE_GEOMETRY_STATS([table_name], [column_name]);

Índices GiST têm duas vantagens em relação a índices R-Tree em PostgreSQL. Em primeiro lugar, índices GiST são "null safe" (segurança nula), significando que eles podem indexar colunas que incluem valores nulos. Em segundo lugar, indices GiST apóiam o conceito de "lossiness" que é importante quando lidado com objetos de GIS com páginas PostgreSQL de tamanhos maiores que 8K. "Lossiness" permite PostgreSQL armazenar somente a parte impor tante de um objeto em um índice - no caso de objetos de GIS, só a caixa de saltos. Objetos de GIS maiores que 8K causarão índices R-Tree para falhar no processo de ser construído.

4.5.2. Usando Índices

Índices aceleram o acesso de dados: uma vez que o índice é construído, a transparência de planejamento de queries decide quando usar informação de índice para acelerar um plano de "query". Infelizmente, a "query" PostgreSQL não planeja otimizar bem o uso de índices de GiST, às vezes buscas que deveriam usar um índice espacial ao invés do padrão para uma busca sequencial da tabela inteira.

Se você acha que seus índices espaciais não estão sendo usados (ou seus índices de atributo, para aquele assunto) existe um agrupamento de coisas que você pode fazer:

  • Primeiramente, certifique-se que as estatisticas são coletadas sobre o número e distribuições dos valores em uma tabela, proporcionando para o operador de "query", melhor informação de tomada de decisões em torno do uso de índices Para instalações PostgreSQL 7.4 e anteriores, é rodado: update_geometry_stats([table_name, column_name]) (agrupa estatísticas distribuições de valores em uma tabela) e VACUUM ANALYZE [table_name] [column_name] (agrupa estatísticas a respeito do número de valores em uma tabela). Começando com PostgreSQL 8.0 rodando VACUUM ANALYZE fará ambas as operações. Você deveria limpar regularmente seus bancos de dados - muitos DBAs PostgreSQL têm rodado "VACUUM" (vazio) com a carga máxima de trabalho "cron" desligada em bases regulares.

  • Se não limpar seus trabalhos, você pode forçar o operador a usar informação de índice utilizando o comando SET ENABLE_SEQSCAN=OFF. Você com certeza só deveria usar este comando, em queries espacialmente indexadas: em geral, o operador sabe melhor que você o que fazer a respeito, quando usar índices normais de B-Tree. Uma vez que você rodou sua "query", você deveria considerar a situação ENABLE_SEQSCAN atrás ligado, de maneira que outras queries o operador utilizará como normal.

    Nota

    A partir de versão 0.6, não deveria ser necessário forçar o operador a usar o índice com ENABLE_SEQSCAN.

  • Se você encontrar o operador errado sobre o custo de sequencial versus varreduras de índice, tente reduzir o valor de "random_page_cost" em postgresql.conf ou usando SET "random_page_cost"=#. O valor default para o parâmetro é 4, tente ajustá-lo para 1 ou 2. Decremente o valor que faz o operador mais inclinado, usando varreduras de índice.

4.6.  Queries Complexas

A finalidade da existência propriamente para a funcionalidade do banco de dados espacial está em executar queries dentro do banco de dados que deveria requerer funcionalidade contidas em desktop GIS. Usando PostGIS efetivamente requer conhecimento de quais funções espaciais estão disponíveis, e assegura-se que índices apropriados estão em lugar que aprovam bom desempenho.

4.6.1. Vantagens dos Índices

Na construção de uma "query" é importante lembrarmos que os operadores baseados em saltos de caixa tal como &&, pode tirar proveito do índice espacial de GiST. Funções como distance () não pode usar o índice para otimizar suas operações. Por exemplo, a "query" seguinte seria bastante lenta em uma tabela grande:

SELECT the_geom FROM geom_table
WHERE distance( the_geom, GeomFromText( 'POINT(100000 200000)', -1 ) ) < 100

Esta "query" está selecionando todas as geometrias em geom_table que está dentro de 100 unidades do ponto (100000, 200000). Estará lento porque está calculando a distância entre cada ponto na tabela e nosso ponto especificado, ie. distance () calculados para cada linha na tabela. Podemos evitar isto usando o operador && para reduzir o número de cálculos de distância requerido:

SELECT the_geom FROM geom_table
WHERE the_geom && 'BOX3D(90900 190900, 100100 200100)'::box3d
AND distance( the_geom, GeomFromText( 'POINT(100000 200000)', -1 ) ) < 100

Esta "query" seleciona as mesmas geometrias, mas faz isto de um modo mais eficiente. Supondo que existe um índice GiST em the_geom, o operador de "query" reconhecerá que pode usar o índice para reduzir o número de linhas antes de calcular o resultado da função distance ().
Note que a geometria de BOX3D que é usada dentro da operação && é uma caixa quadrada centrada no ponto original unidade 200 - esta é nossa "query box". O operador && usa o índice para reduzir rapidamente o resultado atribuído a essas geometrias, que têm salto de caixas que sobrepõem a "query box". Supondo que nossa "query box" é muito menor que as extensões da tabela de geometria inteira, isto reduzirá drasticamente o número de distância de cálculos que precisam ser feitos.

4.6.2. Exemplos de SQL Espacial

Os exemplos nesta seção utilizarão duas tabelas, uma tabela de estradas lineares, e uma tabela de limites poligonal da municipalidade. As definições de tabela para a tabela dos bc_roads são:

 Column | Type | Description
------------+-------------------+-------------------
gid | integer | Unique ID
name | character varying | Road Name
the_geom | geometry | Location Geometry (Linestring)

A definição de tabela para a tabela do bc_municipality é:

 Column | Type | Description
-----------+-------------------+-------------------
gid | integer | Unique ID
code | integer | Unique ID
name | character varying | City / Town Name
the_geom | geometry | Location Geometry (Polygon)
4.6.2.1. Qual o comprimento total de todas as estradas, expressado nos quilômetros?
4.6.2.2. Qual é a área da cidade de São Paulo, em hectares?
4.6.2.3. Qual é a maior municipalidade na província, por área?
4.6.2.4. Qual é o tamanho completo das estradas contidas inteiramente dentro de cada municipalidade?
4.6.2.5. Críe uma nova tabela com todas as estradas dentro da cidade de São Paulo.
4.6.2.6. Qual é o tamanho em quilômetros, da Avenida dos Autonomistas, em OSASCO?
4.6.2.7. Qual é o maior polígono da municipalidade que tem uma regra?
 
4.6.2.1.

Qual o comprimento total de todas as estradas, expressado nos quilômetros?

Voce pode responder esta questão com uma parte muito simples de SQL:

postgis=# SELECT sum(length(the_geom))/1000 AS km_roads FROM bc_roads;
km_roads
------------------
70842.1243039643
(1 row)
4.6.2.2.

Qual é a área da cidade de São Paulo, em hectares?

Esta "query" combina uma condição do atributo (no nome da municipalidade) com um cálculo espacial (da área):

postgis=# SELECT area(the_geom)/10000 AS hectares FROM bc_municipality
WHERE name = 'SÃO PAULO'
------------------
32657.9103824927
(1 row)
4.6.2.3.

Qual é a maior municipalidade na província, por área?

Esta "query" traz uma medida espacial na condição da "query". Há diversas maneiras de avaliar este problema, mas o mais eficiente está abaixo:

postgis=# SELECT name, area(the_geom)/10000 AS hectares
FROM bc_municipality
ORDER BY hectares DESC
LIMIT 1;
name | hectares
---------------+-----------------
TUMBLER RIDGE | 155020.02556131
(1 row)

Note que a ordem para responder a esta "query", nós temos que calcular a área de cada polígono. Se nós fizéssemos isto muito, teria sentido acrescentar uma coluna da área à tabela, que nós poderíamos separadamente posicionar para o desempenho. Requisitando os resultados em um sentido descendente, e por eles que usam o comando de PostgreSQL "LIMIT", nós podemos facilmente extrair o maior valor, sem usar uma função agregada como o max().

4.6.2.4.

Qual é o tamanho completo das estradas contidas inteiramente dentro de cada municipalidade?

Este é um exemplo de um "spatial join" , porque nós estamos trazendo junto dados de duas tabelas (que fazem juntar), mas estamos usando uma condição de interação espacial ("contained") como a melhor condição de juntar do que a aproximação relacional usual de juntar em uma chave comum:

postgis=# SELECT m.name, sum(length(r.the_geom))/1000 as roads_km
FROM bc_roads AS r,bc_municipality AS m
WHERE r.the_geom && m.the_geom
AND contains(m.the_geom,r.the_geom)
GROUP BY m.name
ORDER BY roads_km;

name | roads_km
----------------------------+------------------
SURREY | 1539.47553551242
VANCOUVER | 1450.33093486576
LANGLEY DISTRICT | 833.793392535662
BURNABY | 773.769091404338
PRINCE GEORGE | 694.37554369147
...

Esta "query" examina porque cada estrada na tabela é sumarizada no resultado final (sobre as estradas 250K para nossa tabela do exemplo particular). Para menores "overlays" (mil registros em cem) a resposta pode ser muito ráapida.

4.6.2.5.

Crie uma nova tabela com todas as estradas dentro da cidade de São Paulo.

Este é um exemplo de um "overlay", que examina em duas tabelas e saídas em uma nova tabela, que consiste espacialmente "clipped" ou do corte de resultados. Ao contrário do "spatial join" demonstrado acima, esta "query" cria realmente novas geometrias. Um "overlay" é como um turbo-carregado de "spatial join", e é útil para um trabalho mais exato da análise:

postgis=# CREATE TABLE pg_roads as
SELECT intersection(r.the_geom, m.the_geom) AS intersection_geom,
length(r.the_geom) AS rd_orig_length,
r.*
FROM bc_roads AS r, bc_municipality AS m
WHERE r.the_geom && m.the_geom
AND intersects(r.the_geom, m.the_geom)
AND m.name = 'SÃO PAULO';
4.6.2.6.

Qual é o tamanho em quilômetros, da Avenida dos Autonomistas, em OSASCO?

postgis=# SELECT sum(length(r.the_geom))/1000 AS kilometers
FROM bc_roads r, bc_municipality m
WHERE r.the_geom && m.the_geom
AND r.name = 'Avenida dos Autonomistas'
AND m.name = 'OSASCO';
kilometers
------------------
4.89151904172838
(1 row)
4.6.2.7.

Qual é o maior polígono da municipalidade que tem uma regra?

postgis=# SELECT gid, name, area(the_geom) AS area
FROM bc_municipality
WHERE nrings(the_geom) > 1
ORDER BY area DESC LIMIT 1;
gid | name | area
-----+--------------+------------------
12 | SPALLUMCHEEN | 257374619.430216
(1 row)

4.7. Usando Mapserver

O Minnesota Mapserver é um servidor Web Map na internet que adapta-se a especificação do Servidor de Mapas na Internet OpenGIS .

4.7.1. Uso Básico

Usar PostGIS com Mapserver, você precisará conhecer como configurar o Mapserver que está além da extensão desta documentação. Esta seção cobrirá distribuição e detalhes de configuração de PostGIS específico.

Usar PostGIS com Mapserver, você precisará:

  • Versão 0.6 ou posterior de PostGIS.

  • Versão 3.5 ou posterior de Mapserver.

Mapserver acessa dados de PostGIS/PostgreSQL como qualquer outro cliente de PostgreSQL- usando libpq. Estes meios que Mapserver pode ser instalado em qualquer máquina com acesso de rede para o servidor de PostGIS, enquanto o sistema tem bibliotecas client de PostgreSQL libpq.
  1. Compile e instale Mapserver, com qualquer opções que você deseje, inclusive a opção de configuração "-with-postgis"

  2. Em seu arquivo de mapas Mapserver, acrescente uma camada de PostGIS. Por exemplo:

    LAYER
    CONNECTIONTYPE postgis
    NAME "widehighways"
    # Connect to a remote spatial database
    CONNECTION "user=dbuser dbname=gisdatabase host=bigserver"
    # Get the lines from the 'geom' column of the 'roads' table
    DATA "geom from roads"
    STATUS ON
    TYPE LINE
    # Of the lines in the extents, only render the wide highways
    FILTER "type = 'highway' and numlanes >= 4"
    CLASS
    # Make the superhighways brighter and 2 pixels wide
    EXPRESSION ([numlanes] >= 6)
    COLOR 255 22 22
    SYMBOL "solid"
    SIZE 2
    END
    CLASS
    # All the rest are darker and only 1 pixel wide
    EXPRESSION ([numlanes] < 6)
    COLOR 205 92 82
    END
    END

    No exemplo acima, as diretivas de especificação do PostGIS são como segue:

    CONNECTIONTYPE

    Para camadas de PostGIS, este é sempre "postgis."

    CONNECTION

    A conexão de banco de dados é governada por uma 'connection string' do qual é um padrão de coleção de chaves e valores como este (com os valores padrões em <>):

    user=<username> password=<password> dbname=<username> hostname=<server> port=<5432>

    Um fio de conexão vazio ainda é válido, e nenhum dos pares de chave/valor podem ser omitido. No mínimo você se proverá do nome e usuário do banco de dados com c conexão.

    DATA

    A forma deste parâmetro é "< column> from <tablename>" onde a coluna é a coluna espacial a ser traduzida no mapa.

    FILTER

    O filtro deve ser uma string SQL válida correspondendo à lógica que normalmente segue da palavra-chave "WHERE" em uma "query" SQL. Por exemplo, assim fazer só estradas com 6 ou mais pistas, use um filtro de "num_lanes >= 6."

  3. Em seu banco de dados espacial, assegure-se que você tem índices espaciais (GiST) construídos para qualquer das camadas que você estará desenhando.

    CREATE INDEX [indexname]
    ON [tablename]
    USING GIST ( [geometrycolumn] GIST_GEOMETRY_OPS );
  4. Se você estivesse examinando suas camadas usando Mapserver você também precisaria de um "oid index."
    Mapserver requer identificadores únicos para cada registro espacial ao fazer queries, e o módulo de Mapserver PostGIS usa o valor oid PostgreSQL para prover estes identificadores únicos. Um efeito colateral disto é que para fazer acesso randômico rápido de registros durante queries, um "oid index" é necessário.

    Construir um "oid index", use o SQL seguinte:

    CREATE INDEX [indexname] ON [tablename] ( oid );
4.7.2.1.

Quando eu uso uma EXPRESSÃO em meu arquivo de mapa, a condição nunca retorna como verdadeira, mesmo que eu saiba os valores existentes em minha tabela.

Ao contrário dos arquivos Shape, os nomes de campo de PostGIS têm que ser referenciado nas expressões usando um caso mais baixo.

EXPRESSION ([numlanes] >= 6)
4.7.2.2.

O FILTRO que eu me uso para meus arquivos Shape não está trabalhando para minha tabela de PostGIS de mesmos dados.

Ao contrário dos arquivos Shape, filtros para camadas de PostGIS usa a sintaxe SQL (são adicionados à declaração do SQL o conector de PostGIS que extrai camadas em Mapserver).

FILTER "type = 'highway' and numlanes >= 4"
4.7.2.3.

A extração da camada de PostGIS é muito mais lenta do que a camada do arquivo Shape, é este normal?

Em geral, espera-se camadas de PostGIS serem 10% mais lenta do que camadas de arquivos Shape, devido o "overhead" extra envolvido em conexões do banco de dados, em transformações de dados e trânsito de dados entre o banco de dados e o Mapserver.

Se você estiver encontrando problemas substanciais de desempenho, é provável que você não tem a configuração, um índice espacial em sua tabela.

postgis# CREATE INDEX geotable_gix ON geotable USING GIST ( geocolumn );
postgis# SELECT update_geometry_stats(); -- For PGSQL < 8.0
postgis# VACUUM ANALYZE; -- For PGSQL >= 8.0
4.7.2.4.

A extração da camada de PostGIS é fina, mas as queries são realmente lentas. O que está errado?

Para que as "queries" sejam rápidas, você deve ter uma chave original para sua tabela espacial e você deve ter um índice nessa chave original.

Você pode especificar que chave original para o Mapserver usar com a cláusula "USING UNIQUE" em sua linha de dados:

DATA "the_geom FROM geotable USING UNIQUE gid"

Se sua tabela não tiver uma coluna original explícita, você pode usar "fake" para uma única coluna usando a linha de PostgreSQL "oid" para sua coluna original. "oid" é a coluna original "default" se você não declarar um, assim que reforçar sua velocidade da "query", um problema de construção em índice no valor "oid" de sua tabela espacial.

postgis# CREATE INDEX geotable_oid_idx ON geotable (oid);

4.7.3. Uso Avançado

A cláusula USING pseudo-SQL é usada para acrescentar alguma informação para ajudar a entender os resultados mapserver de maior complexidade das queries. Mais especificamente, quando uma visão ou um subselect é usado como tabela fonte (a uso certo de "FROM" em uma definição de DATA) é mais difícil para mapserver que automaticamente determina um identifi- cador único para cada linha e também o SRID para a tabela. A cláusula USING pode proporcionar para mapserver estes dois tipos de informação como segue:

DATA "the_geom FROM (SELECT table1.the_geom AS the_geom, table1.oid AS oid, table2.data AS data
FROM table1 LEFT JOIN table2 ON table1.id = table2.id) AS new_table USING UNIQUE oid USING SRID=-1"
USING UNIQUE <uniqueid>

Mapserver requer um id único para cada linha para identificar a linha quando esboça queries. Normalmente, usaria o oid como identificador único, mas views e subselects não tem automaticamente uma coluna "oid". Se você quiser usar a funcionalidade de "query" de Mapserver, você precisa acrescentar uma única coluna para "views" ou "subselects" , e declará-la com USING UNIQUE. Por exemplo, você poderia selecionar um valor para "oid" da própria tabela para este propósito, ou nenhuma coluna que é garantido ser único para o resultado final.

A declaração USING também pode ser muito útil para declarações de dados simples, se você esboçando "queries". Recomendavasse previamente que, para acrescentar um índice na coluna oid das tabelas usadas nas camadas "query-able", em ordem acelara o desempenho de "queries" de mapa. Porém, com a cláusula USING, é possível dizer que para o mapserver usa chave primária em suas próprias tabelas como o identificador de "queries" de mapa, e então necessariamente não ter o mais longo índice adicional.

Nota

Examinando um mapa (Quering a Map) é a ação de "clicking" em um mapa e questionar informações a respeito de características de mapa naquele local. Não confunda "map queries" com o "query" SQL em uma definição DATA.

USING SRID=<srid>

PostGIS necessita saber qual referenciamento de sistema espacial que está sendo usado pelas geometrias em ordem para que devolva os dados corretos atrás do mapserver. Normalmente é possível encontrar esta informação dentro da tabela "geometry_columns" no banco de dados de PostGIS, porém, isto não é possível para tabelas que são criadas superficialmente como "view"s e "subselects". Assim o USING SRID= opção que permite o correto SRID ser especificado na definição DATA.

Aviso

O parceiro para camadas de PostGIS Mapserver é razoavelmente primitivo, e é caso sensível em algumas áreas. Tenha cuidado para assegurar-se de que todos as palavras chaves do SQL e todas suas cláusulas USING estejam em caso superior, e que sua cláusula USING UNIQUE precede sua cláusula "USING SRID.

4.7.4. Exemplos

Começamos com um exemplo simples e que levanta nosso trabalho. Considere a seguir a definição de camada de Mapserver:

LAYER
CONNECTIONTYPE postgis
NAME "roads"
CONNECTION "user=theuser password=thepass dbname=thedb host=theserver"
DATA "the_geom FROM roads"
STATUS ON
TYPE LINE
CLASS
COLOR 0 0 0
END
END

Esta camada exibirá todas as geometrias de estrada na tabela de estradas com linhas pretas.

Agora dizemos que nós queremos mostrar só as rodovias até que nós conseguirmos fechar a câmara em pelo menos 1:100000 balança – as próximas duas camadas obterão este efeito:

LAYER
CONNECTION "user=theuser password=thepass dbname=thedb host=theserver"
DATA "the_geom FROM roads"
MINSCALE 100000
STATUS ON
TYPE LINE
FILTER "road_type = 'highway'"
CLASS
COLOR 0 0 0
END
END

LAYER
CONNECTION "user=theuser password=thepass dbname=thedb host=theserver"
DATA "the_geom FROM roads"
MAXSCALE 100000
STATUS ON
TYPE LINE
CLASSITEM road_type
CLASS
EXPRESSION "highway"
SIZE 2
COLOR 255 0 0
END
CLASS
COLOR 0 0 0
END
END

A primeira camada é usada quando a balança é maior que 1:100000, e exibe só as estradas de tipo "highway" (rodovia) com linhas pretas. A opção FILTER causa só estradas de TIPO "highway" (rodovia) a ser exibida.

A segunda camada é usada quando a balança é menos que 1:100000, e exibirá rodovias como linhas vermelhas grossas, e outras estradas como linhas pretas regulares.

Assim, nós fizemos um par de coisas interessantes que usam só funcionalidade de mapserver, mas nossa declaração DATA SQL permaneceu simples. Suponha que o nome da estrada é armazenado em outra tabela (por qualquer razão) e nós precisamos fazer um una adquirir isto e etiquetar nossas estradas.

LAYER
CONNECTION "user=theuser password=thepass dbname=thedb host=theserver"
DATA "the_geom FROM (SELECT roads.oid AS oid, roads.the_geom AS the_geom, road_names.name as name
FROM roads LEFT JOIN road_names ON roads.road_name_id = road_names.road_name_id) AS named_roads
USING UNIQUE oid USING SRID=-1"
MAXSCALE 20000
STATUS ON
TYPE ANNOTATION
LABELITEM name
CLASS
LABEL
ANGLE auto
SIZE 8
COLOR 0 192 0
TYPE truetype
FONT arial
END
END
END

Esta camada da anotação adiciona etiquetas verdes a todas as estradas quando a escala começa para baixo a 1:20000 ou menos. Demonstra também como usar um "join" SQL em uma definição DATA.

4.8. Clientes Java (JDBC)

Os clientes de Java podem acessar objetos da "geometria" de PostGIS no banco de dados de PostgreSQL, outros diretamente como representações de texto ou usam os objetos de extensão JDBC empacotados com PostGIS. A fim usar os objetos de extensão, o arquivo "postgis.jar" deve estar em seu CLASSPATH junto com o pacote JDBC de "postgresql.jar".

import java.sql.*;
import java.util.*;
import java.lang.*;
import org.postgis.*;

public class JavaGIS {
public static void main(String[] args)
{
java.sql.Connection conn;
try
{
/*
* Load the JDBC driver and establish a connection.
*/
Class.forName("org.postgresql.Driver");
String url = "jdbc:postgresql://localhost:5432/database";
conn = DriverManager.getConnection(url, "postgres", "");

/*
* Add the geometry types to the connection. Note that you
* must cast the connection to the pgsql-specific connection * implementation before calling the addDataType() method.
*/
((org.postgresql.Connection)conn).addDataType("geometry","org.postgis.PGgeometry");
((org.postgresql.Connection)conn).addDataType("box3d","org.postgis.PGbox3d");

/*
* Create a statement and execute a select query.
*/
Statement s = conn.createStatement();
ResultSet r = s.executeQuery("select AsText(geom) as geom,id from geomtable");
while( r.next() )
{
/*
* Retrieve the geometry as an object then cast it to the geometry type.
* Print things out.
*/
PGgeometry geom = (PGgeometry)r.getObject(1);
int id = r.getInt(2);
System.out.println("Row " + id + ":");
System.out.println(geom.toString());
}
s.close();
conn.close();
}
catch( Exception e )
{
e.printStackTrace();
}
}
}

O objeto "PGgeometry" é um objeto "wrapper" que contem um objeto de geometria topológico específico (subclasses da classe "geometria") dependendo do tipo: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon.

PGgeometry geom = (PGgeometry)r.getObject(1);
if( geom.getType() = Geometry.POLYGON )
{
Polygon pl = (Polygon)geom.getGeometry();
for( int r = 0; r < pl.numRings(); r++ )
{
LinearRing rng = pl.getRing(r);
System.out.println("Ring: " + r);
for( int p = 0; p < rng.numPoints(); p++ )
{
Point pt = rng.getPoint(p);
System.out.println("Point: " + p);
System.out.println(pt.toString());
}
}
}

O JavaDoc para os objetos da extensão fornece uma referência para as várias funções do assessor dos dados nos objetos geométricos.

4.9. Clientes C (libpq)

...

4.9.1. Cursores de Texto

...

4.9.2. Cursores Binários

...