Dubai Mall em um smartphone ou como adicionar uma planta baixa de um edifício ao seu aplicativo



Em um artigo anterior, falei sobre como criar um aplicativo móvel com um mapa. Na continuação da série "no joelho", compartilharei com você as ferramentas para implementar as plantas.

A declaração inicial do problema de forma simplificada: quero poder visualizar o diagrama de piso no seu aplicativo móvel e mostrar a localização de uma organização específica nele. Também gostaria de ver a localização do usuário, mas aqui o problema está no plano técnico - você precisa de equipamentos que permitam obter as coordenadas do dispositivo em ambientes fechados. Portanto, deixamos esse aspecto fora do escopo do artigo e focamos na parte do software.

Abaixo, mostrarei várias opções com as quais você pode implementar os requisitos descritos acima. Tudo depende de quais dados você possui e o que exatamente o aplicativo deve ser capaz de fazer. E começaremos com o mais simples.

A primeira opção API pronta com dados


A primeira opção que consideraremos é o uso de um widget pronto do 2GIS. A descrição da API pode ser visualizada em api.2gis.ru. Serve para você se o edifício em que você está interessado já estiver apresentado no 2GIS e se os pisos já foram desenhados no edifício. Ou seja, em termos de dados, tudo já foi feito. E o mais importante, você está pronto para a Internet, pois essa opção funcionará exclusivamente com a Internet.

Para exibir os pisos nesse caso, praticamente nada é necessário para você. Implementação da execução como um widget da Web, que você só precisa colocar no WebView.

<WebView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/am_webview" android:layout_marginTop="160dp" /> 

Este é o contêiner no qual colocaremos nosso widget. Inicializamos da seguinte forma:

 webView = findViewById(R.id.am_webview) webView.settings.javaScriptEnabled = true webView.settings.useWideViewPort = true webView.settings.loadWithOverviewMode = true //webView.settings.setSupportZoom(true) //webView.settings.displayZoomControls = true //webView.settings.builtInZoomControls = true webView.loadUrl("file:///android_asset/map_api.html") webView.webViewClient = object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { super.onPageFinished(view, url) val js = "initMap('13933647002593772');" // The Dubai Mall webView.evaluateJavascript(js, ValueCallback { }) } } 

Nós configuramos o próprio webView, certifique-se de ativar o JavaScript, javaScriptEnabled = true, pois interagiremos com o widget por meio dele. Se necessário, você pode ativar as barras de rolagem e os botões de zoom (consulte o código comentado), mas não funciona muito bem, por isso não recomendo.

O mais importante é carregar HTML com nosso widget webView.loadUrl ("file: ///android_asset/map_api.html") e assinar eventos, se necessário. No exemplo acima, depois de carregar o mapa, chamamos o método initMap definido em map_api.html, passando o identificador do edifício para o qual queremos mostrar os pisos.

HTML é um código bastante simples. O método DG.FloorsWidget.init é chamado , no qual o objeto json que contém os dados para inicializar é passado. Como contêiner, especifique o ID com o qual declaramos uma div na marcação HTML acima. Ajuste a largura, altura. E no initData passamos o edifício na tag complexId e parâmetros adicionais de exibição do widget, que podem ser encontrados na documentação da API. A propósito, o identificador pode ser visto em resposta à consulta de pesquisa, que o 2GIS envia quando você clica no edifício em que está interessado em 2gis.ru. No meu exemplo, usei o Dubai Mall. Mas ninguém se preocupa em indicar outro prédio com piso.

O toque final. Para mudar para uma empresa específica, chame o método showFirm, passando o identificador da empresa

 webView.loadUrl("javascript:showFirm('$firmId')") 


É bem simples. Um exemplo de implementação pronto pode ser visualizado no Github .



Prós da opção considerada:

  • dados prontos com plantas e dados da empresa;
  • implementação leve e pronta para visualização na web;
  • pesquisa pronta de acordo com 2GIS.

Contras:

  • Internet necessária;
  • é necessário conhecimento básico de HTML e JavaScript;
  • apenas dados 2GIS e apenas os edifícios que já possuem pisos.

A segunda opção Planta como uma imagem


Se a opção com dados prontos e API não for adequada para você, você pode usar o seguinte.

Nesse caso, você precisará de uma planta baixa na forma de uma imagem, por exemplo, jpeg ou png. Se a interatividade do tipo “enfiado na imagem - abriu o cartão de objeto” for necessária, também será necessário geocodificar, o que precisará ser implementado de forma independente. Se você encaixar nas coordenadas globais, a imagem deve ser dimensionada corretamente e um dos cantos deve ser puxado para as coordenadas reais, para que você possa calcular os deslocamentos a partir dela. Não vamos nos debruçar sobre essa questão em detalhes, espero que tudo esteja claro aqui.

O mais importante é mostrar esta imagem no aplicativo. E para isso, a biblioteca TileView é ideal para nós. De fato, essa biblioteca permite, em princípio, exibir blocos de mapa. Mas também nos convém, pois fornece a capacidade de mover e aplicar zoom, centralizar em uma posição especificada, exibir marcadores, transformar coordenadas e assinar vários eventos.

Para que a biblioteca funcione da maneira mais eficiente possível, é necessário preparar a imagem original cortando-a em ladrilhos. Há uma instrução bastante simples para isso . Eu recomendo um script no final da página especificada que criará 4 conjuntos de peças. Adicionamos o resultado obtido aos ativos e exibimos nossa imagem na atividade com um código simples:

 tileView.setSize(floorWidth, floorHeight) tileView.setShouldRenderWhilePanning(true) tileView.addDetailLevel(1f, "tiles/floors1/1000/%d_%d.jpg") tileView.addDetailLevel(0.500f, "tiles/floors1/500/%d_%d.jpg") tileView.addDetailLevel(0.250f, "tiles/floors1/250/%d_%d.jpg") tileView.addDetailLevel(0.125f, "tiles/floors1/125/%d_%d.jpg") tileView.defineBounds(0.0, 0.0, floorWidth.toDouble(), floorHeight.toDouble()) tileView.setScaleLimits(0f, 5f) tileView.setMinimumScaleMode(ZoomPanLayout.MinimumScaleMode.FIT) 

Tudo, a tela está pronta. Você pode se inscrever em eventos e adicionar a lógica necessária. Por exemplo, um marcador pode ser exibido assim:

 tileView.setMarkerAnchorPoints(-0.5f, -0.5f) tileView.addMarker(imageView, x, floorHeight - y, null, null) 

Um exemplo completo está disponível no Github .



Prós:

  • a capacidade de fazer completamente offline;
  • preparação de dados relativamente simples, planta baixa na forma de uma imagem.

Contras:

  • falta de estilo dinâmico.

A terceira opção. Dados vetoriais


Esta opção é a mais avançada e a mais difícil. Pressupõe que você tenha preparado dados vetoriais, ou seja, pisos completamente desenhados no vetor. Você precisará de vários tipos de objetos. Áreas de organizações, estacionamentos, praças de alimentação, palcos, pistas de skate e assim por diante. Objetos lineares - principalmente paredes, direções de fluxo. Objetos pontuais: entradas / saídas, elevadores, caixas eletrônicos e similares.

Veja como é uma planta baixa em Fiji, sistema interno 2GIS:



Bem, para a visualização deles, o mecanismo vetorial, sobre o qual falei no artigo anterior , o mapsforge-vtm é adequado para nós.

Para demonstrar a abordagem, preparei dados de teste: um conjunto de quadrados e linhas para vários andares usando o exemplo de um edifício na ensolarada ilha de Chipre. Para a preparação, peguei a geometria original do edifício e a cortei em pedaços correspondentes aos componentes da geometria, apenas por simplicidade. Como você sabe, a parte mais difícil é a preparação de dados de qualidade. O resto é uma questão de tecnologia. Você precisará de botões para alternar pisos, estilos preparados para renderizar quadrados e linhas diferentes e uma sobreposição para renderizá-los.

Veja o código completo aqui .

A classe FloorData contém o código de dados geográficos de teste para nossos pisos e a classe FloorsManager foi projetada para renderizá-los.

No construtor, definimos estilos para quadrados e paredes:

 styles.put(ObjectType.Floor, org.oscim.layers.vector.geometries.Style.builder() .fillColor(Color.GRAY) .build()); 

E no método drawFloor , determinamos a lógica de adicionar objetos às camadas no mapa:

 public void drawFloor(int floorId) { hideFloors(); indoorLayer = new CustomVectorLayer(this.map); List<GeoData> geoObjects = this.floorData.getFloorData(floorId); for (GeoData geo: geoObjects) { indoorLayer.add(geo.getGeometry(), styles.get(geo.getObjectType())); } this.map.layers().add(indoorLayer); indoorLayer.update(); } 

Tudo é elementar aqui. Crie uma nova camada indoorLayer , adicione dados de piso pré-preparados com os estilos necessários e adicione a camada ao mapa this.map.layers (). Add (indoorLayer) .

Resta adicionar botões para mudar de piso. Para fazer isso, existe um FloorPickerControl baseado no RecyclerView , que faz exatamente o que você precisa. Não vamos perder tempo com isso, veja a fonte.

E aqui está o Dubai Mall em nossa aplicação. Também implementou a edição de objetos geográficos.



Prós:

  • novamente, a capacidade de fazer completamente offline;
  • imagem de alta qualidade;
  • a possibilidade de uma variedade de estilização dinâmica;
  • a capacidade de implementar um editor de dados.

Contras:

  • preparação de dados complexos.

No final do artigo, quero dizer que a tarefa de exibir plantas baixas no aplicativo não é tão terrível quanto parece à primeira vista. Você tem várias opções com seus prós e contras, dentre as quais é possível escolher a mais adequada para resolver seu problema.

Todas as referências em um só lugar:

Artigo sobre o mapa no celular
API 2GIS
Exemplo da API 2GIS
Biblioteca TileView
Exemplo TileView
Um exemplo no mapsforge-vtm

Source: https://habr.com/ru/post/pt476816/


All Articles