Brincando com ArcObjects
Boa tarde pessoal,
ArcObjects é algo relativamente difícil. É complicado pois temos muitas formas de se fazer o que queremos, a documentação - apesar de razoável, não é excelente (existem detalhes importantes que podem estar escondidos em outras páginas) e não existe uma comunidade forte que trate destas questões.
Gostaria de mostrar um pouco de ArcObjects aos iniciantes, em especial um namespace complicadinho: ESRI.ArcGIS.Geometry. Não tenho domínio do namespace suficiente para dizer que sou um expert, mas consigo me virar.
O namespace Geometry é o responsável por cuidar de todas as operações com as geometrias, sejam elas de quaisquer tipos. Primeiramente gostaria de apresentaar à vocês aos tipos de geometria de alto-nível. Isto é importante pois algumas funções ou interfaces, só estão disponíveis nas geometrias de alto nível, outras somente nas de baixo nível.
Todas as geometrias de alto nível tem à sua disposição um set teórico de operações possíveis, tais como interseção, união, diferença, diferença simétrica, entre outros. Outras interfaces/classes do namespace ESRI.ArcGIS.Geometry são responsáveis por estas operações.
Geometrias de Alto Nível
As geometrias de alto nível são:
- Points;
- Multipoints;
- Polylines;
- Polygons;
- MultiPatches;
Ponto é o tipo de geometria mais simples que podemos encontrar no modelo do ArcGIS. É basicamente composta de uma coordenada X e uma coordenada Y. Opcionalmente os pontos podem ser IdAware, ZAware e MAware, ou seja: podem ter um Id, Z e M. Todas os tipos de geometrias podem ter estes atributos em seus vértices, que em suma, são pontos.
Multipontos é um tipo de geometria representado por uma coleção de pontos. Da mesma maneira que um ponto, cada ponto desta única geometria tem seus atributos.
Polilinhas são composta pela união de diversos paths (uma geometria de nível mais baixo) que são compostos por sua vez de diversos segments, que podem ser dos tipos: linha, arco circular, curva bezier ou arco elíptico.
Polígonos são geometrias compostas por rings, que são compostos por segments, dos tipos citados acima. A ordem de cada ring e o sentido de construção (horário/ante-horário) determinar o comportamento de cada ring. Exemplo: todos os rings externos são ordenados em sentido horário, indicando que o interior dele é o polígono. Caso um ring seja ordenado em anti-horário você está dizendo ao ArcGIS que ele é hole - com área negativa.
No caso dos polígonos, isso pode ocorrer indefinidamente, sendo determinado pela ordem em que cada ring aparece na coleção.
Multipatches são geometrias compostas e são em três dimensões. São geometrias que podem ter múltiplas superfícies, com textura. É a forma como o ArcGIS representa objetos em três dimensões. São compostas de Triangles, TriangleStrips e TriangleFans.
Todas as geometrias de nível mais baixo são construídas necessáriamente por pontos. É o bloco de construção do ArcGIS.
Geometrias de Baixo Nível
- Paths
- Rings
- Segments
- TriangleStrips
- TriangleFans
- Triangles
Pela estrutura que temos aí dá pra entender melhor não?
Vamos começar brincando com os pontinhos, já que são as estruturas básicas de trabalho.
Classes e Interfaces
Para simplificar para os iniciantes, classe é um projeto de um objeto. Quando criamos um novo, aquele projeto é "materializado" na memória do computador.
Interface é um contrato. Quando dizemos que uma classe implementa uma interface, queremos dizer que aquela classe assinou um contrato de funcionalidade com aquela interface - ou seja, tudo que realiza operações na interface ou em algum membro da interface, está também disponível na classe, sendo possível utilizar aquela classe em alguma função que requer a interface.
PointClass
Esta classe implementa diversas interfaces (ou contratos) do namespace Geometry. As interfaces definem as funcionalidades que a PointClass terá. Caso você tenha o Help de desenvolvimento do ArcGIS instalado, abra o mesmo e procure esta URL ms-help://ESRI.EDNv9.3/esriGeometry/html/Point.htm .
Caso não tenha o help instalado
Como criamos um novo ponto? É bem simples, vejam só.
IPoint ponto = new PointClass();
ponto.PutCoords(10,10);
Vamos criar uma novo projeto C# do tipo ArcGIS>Console Application. Adicione as referências:
- ESRI.ArcGIS.Geometry;
- ESRI.ArcGIS.Framework;
- ESRI.ArcGIS.esriSystem;
Você verá que o Visual Studio já criou algumas linhas código para nós. Este é o código para buscar a licença na máquina. Em qualquer tipo de aplicação que você for construir, você deve ter um código similar para buscar uma licença, senão ele é automaticamente desligado.
namespace DesktopConsoleApplication1
{
class Program
{
private static LicenseInitializer m_AOLicenseInitializer = new DesktopConsoleApplication1.LicenseInitializer();
[STAThread()]
static void Main(string[] args)
{
//ESRI License Initializer generated code.
m_AOLicenseInitializer.InitializeApplication(new esriLicenseProductCode[] { esriLicenseProductCode.esriLicenseProductCodeArcView },
new esriLicenseExtensionCode[] { });
//ESRI License Initializer generated code.
//Do not make any call to ArcObjects after ShutDownApplication()
m_AOLicenseInitializer.ShutdownApplication();
}
}
}
Este é como meu código se parece. O método Main é o que executa o programa de verdade. Para demonstrar o funcionamento da interface IPoint e da PointClass, vamos escrever algo bem simples, para ilustrar.
Acima do namespace, adicione as seguintes linhas:
using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Framework;
Elas são necessárias para utilizarmos os objetos contidos nestes namespaces sem qualificá-los totalmente, ex: ESRI.ArcGIS.Geometry.IPoint. Após a adição destas linhas, podemos utilizar somente IPoint, diretamente, pois estes objetos estão à nossa disposição.
Crie um novo método dentro desta classe (isto não é o ideal em código de produção - estude orientação à objetos. este é apenas um exemplo) chamado BuildPoint. Este método deve ser estático (não queremos ter de criar uma outra classe Program para acessá-lo), ou seja, pode ser acessado no "projeto" da classe (ao invés de funcionar no objeto). Neste método, queremos construir um ponto, designar suas coordenadas x, y e z e queremos que esta função nos devolva este ponto.
Ficaria assim:
static IPoint BuildPoint(double x, double y, double z)
{
IPoint ponto = new PointClass();
ponto.PutCoords(x, y);
ponto.Z = z;
return ponto;
}
Sugiro que você não façam somente um Ctrl-C + Ctrl-V dos códigos. Teste isto no Visual Studio. O Intelllisense irá lhe mostrar algumas outras coisinhas interessantes. Não esqueça de consultar a documentação para saber mais sobre cada um dos membros e métodos.
Bem, o que este método faz? Ele simplesmente instancia um novo ponto, atualiza as coordenadas conformes passadas nos argumentos da função e nos devolve o ponto. Para que fazer uma função assim? Bem, são somente 4 linhas de código, mas imagine se você precisa criar 80000 pontos? Certo, então temos nossa primeira função pronta.
O que faremos com ela? Vamos modificar nosso método Main, para ler diversas coordenadas e criar um monte de pontos para nós. Depois iremos pedir para nosso método Main nos mostrar os pontos criados. Além de modificar o Main, vamos construir um segundo método para nos ajudar a criar os pontos.
Vamos lá:
[STAThread()]
static void Main(string[] args)
{
//ESRI License Initializer generated code.
m_AOLicenseInitializer.InitializeApplication(new esriLicenseProductCode[] { esriLicenseProductCode.esriLicenseProductCodeArcView },
new esriLicenseExtensionCode[] { });
//ESRI License Initializer generated code.
//Do not make any call to ArcObjects after ShutDownApplication()
m_AOLicenseInitializer.ShutdownApplication();
// após a inicialização da licença, vamos brincar
string finaliza = "s";
string leitura;
// aqui guardaremos nossos pontos
List listaDePontos = new List();
// enquanto finaliza for diferente de n, repita:
while (finaliza.Substring(0,1).ToLower() != "n")
{
// vamos dizer ao usuário o que precisamos.
Console.WriteLine("Digite as coordenadas de seu ponto. Utilize vírgulas para separá-las");
Console.WriteLine("X,Y,Z");
// leitura guardará o resultado que nosso usuário digitar!
leitura = Console.ReadLine();
// temos uma string. precisamos de um método para quebrá-la
// e nos devolver um ponto - que será inserido na listaDePontos
listaDePontos.Add(TraduzirStringPonto(leitura));
// será que o usuário quer digitar mais pontos?
Console.WriteLine("Você deseja criar mais pontos? n para não");
// vamos alterar o valor de finaliza, que será testa mais à frente.
// note que esta rotina não cobre TODAS AS POSSIBILIDADES
finaliza = Console.ReadLine();
}
// agora que o usuário terminou de criar seus pontos,
// vamos mostrá-los à ele.
Console.WriteLine();
Console.WriteLine("Lista de Pontos:n");
// para cada variável do tipo IPoint em listaDePontos, faça
foreach (IPoint p in listaDePontos)
{
// t é caractere de tabulação.
Console.Write("ID " + p.ID.ToString() + "t");
Console.Write("X " + p.X.ToString() + "t");
Console.Write("Y " + p.Y.ToString() + "t");
Console.Write("Z " + p.Z.ToString() + "t");
Console.WriteLine();
}
// vamos esperar o usuário ler os dados e assim que ele teclar denovo
// finalizamos o programa
Console.WriteLine();
Console.WriteLine("Aperte qualquer botão do teclado para finalizar...");
Console.ReadLine();
}
No meio da função está a lógica do programa. Queremos ler dados, até o usuário dizer não. Note que este programa é bastante simples, não realiza verificação de erros nem os trata. Não deve ser feito assim na vida real!
Mostramos para o usuário algumas propriedades da classse IPoint, algumas setadas por nós, outras não. Viram que todos os IDs são iguais à zero?
Agora vou lhes mostrar a função TraduzirStringPonto. Ela envolve mais programação comum, do que ArcObjects. Vou mostrá-la só para não ficarem no escuro
static IPoint TraduzirStringPonto(string s)
{
// recebemos nesta função uma string e queremos transformá-la em números
// vamos usar o método Split, que tem como argumentos um array de caracteres
// delimitados como as strings, com a exceção de que usamos aspas simples!
string[] arrayDeStrings = s.Split(new Char[]{','},3);
// vamos criar uma array com três posições para receber nossos números!
double[] arrayDeDoubles = new double[3];
// para i = 0 até i = 2
for(int i = 0; i <= 2; i++)
{
// assinale o valor da posição i em arrayDeDoubles
// para ser igual ao valor da posição i em arrayDeStrings,
// convertendo-os para um objeto do tipo Double
arrayDeDoubles[i] = Double.Parse(arrayDeStrings[i]);
}
// vamos criar nosso ponto. lembra de BuildPoint?
IPoint ponto = BuildPoint(arrayDeDoubles[0],arrayDeDoubles[1],arrayDeDoubles[2]);
// nos devolva nosso ponto para que possamos inseri-lo na lista
return ponto;
}
Novamente um aviso: esta função também não tem identificação de erros ou tratamento dos mesmos. Recomendo ao interessado em desenvolver seu método de validação da entrada de dados, pois se inserirmos em nosso programa os valores:
10,eitcha,100
ele irá simplesmente travar - no momento da conversão de string para double.
Esta foi uma gentil introdução à manipulação de geometrias em ArcObjects. Os próximos passos são um pouco mais cabeludos, mas nada que seja impossível.
O que acharam?
Related posts:


