Página inicial do Docs → Desenvolver aplicações → Atlas Device SDKs
Geoespacial - React Native SDK
Nesta página
Novo na versão 12.0.0.
Os dados geoespaciais, ou "geodata", especificam pontos e objetos geométricos na superfície da Terra. Com os tipos de dados geográficos, você pode criar consultas que verificam se um determinado ponto está contido dentro de uma forma. Por exemplo, você pode encontrar todos os cafés em um raio de 15 km de um ponto especificado.
Alterado na versão realm@12.3.0
: Dados geoespaciais suportados no Atlas Device Sync
Realm.js v12.3. O 0 e posterior adiciona suporte para dados geoespaciais no Atlas Device Sync. Isto permite que você se inscreva em queries geoespaciais em um domínio sincronizado. Se você tentar se inscrever em uma query geoespacial com uma versão mais antiga do SDK, receberá um erro de servidor com uma gravação compensatória. Para obter mais informações sobre como gerenciar suas assinaturas de sincronização, consulte Geospatial - React Native SDK.
Para obter mais informações sobre como consultar dados geoespaciais com o Device Sync, consulte Dados geoespaciais na documentação do App Services.
Tipos de dados geoespaciais
O SDK suporta query geoespaciais utilizando os seguintes tipos de dados:
GeoPoint
Círculo geográfico
GeoBox
GeoPolygon
O SDK fornece estes tipos de dados geoespaciais para simplificar a query de dados geoespaciais. Você não pode persistir esses tipos de dados diretamente.
Para obter informações sobre como persistir dados geoespaciais, consulte a seção Persistir dados geoespaciais nesta página.
Para query dos dados geoespaciais, você pode usar o operador geoWithin
com RealmQL. O operador geoWithin
pega a propriedade coordinates
de um objeto incorporado que define o ponto que estamos consultando e uma das formas geoespaciais para verificar se esse ponto está contido dentro da forma.
Observação
O formato para consultar dados geoespaciais é o mesmo, independentemente da forma da região de dados geoespaciais.
GeoPoint
Um GeoPoint define um local específico na superfície da Terra. Todos os tipos de dados geoespaciais utilizam GeoPoints
para definir sua localização.
GeoPoint
pode ser um dos três tipos:
Um objeto com:
latitude
: um valor numéricolongitude
: um valor numéricoaltitude
: um valor de número opcional
CanonicalGeoPoint
: uma interface que satisfaz as especificações GeoJSON para um pontoGeoPosition
: uma matriz com longitude, latitude e uma altura opcional
Um GeoPoint é utilizado apenas como um bloco de construção das outras formas: GeoCircle, GeoBox e GeoPolygon. Estas formas, e o tipo GeoPoint, são usadas em query, não para persistência.
Para salvar dados geoespaciais no Realm, consulte Persistir Dados Geoespaciais nesta página.
Círculo geográfico
Um GeoCircle define um círculo na superfície da Terra. Você define um GeoCircle
fornecendo:
Um
GeoPoint
para o centro do círculoUm número para a distância (raio) do círculo
A distância do raio utiliza radianos como unidade de medida. O SDK fornece os métodos kmToRadians
e miToRadians
para converter quilômetros ou milhas para radianos.
O seguinte código mostra dois exemplos de criação de um círculo:
import React from 'react'; import {View, Text} from 'react-native'; import {GeoCircle, GeoPoint, kmToRadians} from 'realm'; import {useQuery} from '@realm/react'; function Geocircle(): JSX.Element { // Define a GeoCircle const smallCircle: GeoCircle = { center: [-121.9, 47.3], // The GeoCircle radius is measured in radians. // This radian distance corresponds with 0.25 degrees. distance: 0.004363323, }; // Realm provides `kmToRadians` and `miToRadians` // to convert these measurements. Import the relevant // convenience method for your app's needs. const radiusFromKm = kmToRadians(44.4); // Define a GeoPoint within a GeoCircle const largeCircleCenter: GeoPoint = { longitude: -122.6, latitude: 47.8, }; const largeCircle: GeoCircle = { center: largeCircleCenter, distance: radiusFromKm, }; // Query geospatial data const companiesInSmallCircle = useQuery( Company, collection => collection.filtered('location geoWithin $0', smallCircle), [smallCircle], ); // Query geospatial data const companiesInLargeCircle = useQuery( Company, collection => collection.filtered('location geoWithin $0', largeCircle), [largeCircle], ); return ( <View> <Text>Small circle: {companiesInSmallCircle.length}</Text> <Text>Large circle: {companiesInLargeCircle.length}</Text> </View> ); }
A imagem a seguir mostra os resultados da criação de dois objetos: um círculo pequeno e um círculo grande.
Query de dados geoespaciais retornam Objeto de Realm dentro das formas que você define. No exemplo acima, este é o resultado de nossa query:
GeoBox
Uma GeoBox define um retângulo na superfície da Terra. Você define o retângulo especificando o canto inferior esquerdo (sudoeste) e o canto superior direito (nordeste). Uma GeoBox se comporta da mesma forma que o GeoPolygon correspondente.
O exemplo a seguir cria 2 caixas:
import React from 'react'; import {View, Text} from 'react-native'; import {GeoBox, GeoPoint} from 'realm'; import {useQuery} from '@realm/react'; function Geobox(): JSX.Element { // Define a GeoBox const largeBox: GeoBox = { bottomLeft: [-122.7, 47.3], topRight: [-122.1, 48.1], }; // Define GeoBox corners const smallBoxBottomLeft: GeoPoint = { longitude: -122.4, latitude: 47.5, }; const smallBoxTopRight: GeoPoint = { longitude: -121.8, latitude: 47.9, }; const smallBox: GeoBox = { bottomLeft: smallBoxBottomLeft, topRight: smallBoxTopRight, }; // Query geospatial data const companiesInLargeBox = useQuery( Company, collection => collection.filtered('location geoWithin $0', largeBox), [largeBox], ); // Query geospatial data const companiesInSmallBox = useQuery( Company, collection => collection.filtered('location geoWithin $0', smallBox), [smallBox], ); return ( <View> <Text>Small box: {companiesInSmallBox.length}</Text> <Text>Large box: {companiesInLargeBox.length}</Text> </View> ); }
A imagem a seguir mostra os resultados da criação de dois objetos: uma caixa pequena e uma caixa grande.
Query de dados geoespaciais retornam Objeto de Realm dentro das formas que você define. No exemplo acima, este é o resultado de nossa query:
GeoPolygon
Um GeoPolygon define um polígono na superfície da Terra. Como um polígono é uma forma fechada, você deve fornecer um mínimo de 4 pontos: 3 pontos para definir a forma do polígono e um quarto para fechar a forma.
Importante
O quarto ponto em um polígono deve ser igual ao primeiro ponto.
Você também pode excluir áreas dentro de um polígono definindo um ou mais "furos". Um orifício é outro polígono cujos limites se encaixam completamente dentro do polígono externo. O exemplo abaixo cria 3 polígonos: um é um polígono básico com 5 pontos, um é o mesmo polígono com um único orifício e o terceiro é o mesmo polígono com dois orifícios:
import React from 'react'; import {View, Text} from 'react-native'; import {GeoPolygon, GeoPoint} from 'realm'; import {useQuery} from '@realm/react'; function Geopolygon(): JSX.Element { // Define a basic GeoPolygon const basicPolygon: GeoPolygon = { outerRing: [ [-122.8, 48.0], [-121.8, 48.2], [-121.6, 47.6], [-122.0, 47.0], [-122.6, 47.2], [-122.8, 48.0], ], }; // Define a GeoPolygon with one hole const outerRing: GeoPoint[] = [ [-122.8, 48.0], [-121.8, 48.2], [-121.6, 47.6], [-122.0, 47.0], [-122.6, 47.2], [-122.8, 48.0], ]; const hole: GeoPoint[] = [ [-122.6, 47.8], [-122.2, 47.7], [-122.6, 47.4], [-122.5, 47.6], [-122.6, 47.8], ]; const polygonWithOneHole: GeoPolygon = { outerRing: outerRing, holes: [hole], }; // Add a second hole to the GeoPolygon const hole2: GeoPoint[] = [ { longitude: -122.05, latitude: 47.55, }, { longitude: -121.9, latitude: 47.55, }, { longitude: -122.1, latitude: 47.3, }, { longitude: -122.05, latitude: 47.55, }, ]; const polygonWithTwoHoles: GeoPolygon = { outerRing: outerRing, holes: [hole, hole2], }; // Query geospatial data const companiesInBasicPolygon = useQuery( Company, collection => collection.filtered('location geoWithin $0', basicPolygon), [basicPolygon], ); // Query geospatial data const companiesInPolygonWithTwoHoles = useQuery( Company, collection => collection.filtered('location geoWithin $0', polygonWithTwoHoles), [polygonWithTwoHoles], ); return ( <View> <Text>Basic polygon: {companiesInBasicPolygon.length}</Text> <Text> Polygon with two holes: {companiesInPolygonWithTwoHoles.length} </Text> </View> ); }
A imagem a seguir mostra os resultados da criação de três objetos: um polígono, um polígono com um orifício e um polígono com dois orifícios.
Query de dados geoespaciais retornam Objeto de Realm dentro das formas que você define. No exemplo acima, este é o resultado de nossa query:
Persistir dados geoespaciais
Importante
Não é possível persistir tipos de dados geoespaciais
Atualmente, você só pode persistir dados geoespaciais. Os tipos de dados geoespaciais não podem ser persistidos diretamente. Por exemplo, você não pode declarar uma propriedade do tipo GeoBox
.
Estes tipos podem ser utilizados somente como argumentos para queries geoespaciais.
Para persistir dados geoespaciais, eles devem estar em conformidade com a especificação GeoJSON.
Criar uma classe compatível com GeoJSON
Para criar uma classe que esteja em conformidade com a especificação GeoJSON, você:
Crie um Objeto de Realm incorporado. Para mais informações sobre objetos incorporados, consulte Objetos incorporados - React Native SDK.
No mínimo, adicione os dois campos exigidos pela especificação GeoJSON:
Um campo do tipo
double[]
que mapeia para uma propriedade de "coordenadas" (diferencia maiúsculas de minúsculas) no esquema do Realm.Um campo do tipo
string
que mapeia para uma propriedade "type". O valor deste campo deve ser "Ponto".
Para simplificar a persistência de geodados, você pode definir um modelo que implementa CanonicalGeoPoint
, que já tem a forma correta. The following example shows an embedded class named MyGeoPoint
that is used to persist geospatial data.
Em seguida, você usa a classe personalizada MyGeoPoint
no seu modelo de Realm, conforme mostrado no exemplo a seguir. You add instances of your class to the realm just like any other Realm model. No entanto, neste exemplo, como a classe MyGeoPoint
não estende Realm.Object
, devemos especificar MyGeoPoint.schema
ao abrir o Realm:
import React from 'react'; import Realm, {ObjectSchema, CanonicalGeoPoint, GeoPosition} from 'realm'; import {RealmProvider} from '@realm/react'; // Implement `CanonicalGeoPoint` // for convenience when persisting geodata. class MyGeoPoint implements CanonicalGeoPoint { coordinates!: GeoPosition; type = 'Point' as const; constructor(long: number, lat: number) { this.coordinates = [long, lat]; } static schema: ObjectSchema = { name: 'MyGeoPoint', embedded: true, properties: { type: 'string', coordinates: 'double[]', }, }; } class Company extends Realm.Object<Company> { _id!: number; location!: MyGeoPoint; static schema: ObjectSchema = { name: 'Company', properties: { _id: 'int', location: 'MyGeoPoint', }, primaryKey: '_id', }; } export const Geospatial = () => { return ( <View> {/* `MyGeoPoint` does not extend `Realm.Object`, so you pass only the `.schema` when opening the realm. */} <RealmProvider schema={[Company, MyGeoPoint.schema]}> <WriteGeospatialObjects /> </RealmProvider> </View> ); };
Gravar a classe incorporada
Dentro de RealmProvider
, crie seus objetos geoespaciais combinando a classe embarcada com classes que estendem Realm.Object
.
import React from 'react'; import {View} from 'react-native'; import {useEffect} from 'react'; import {useRealm, useQuery} from '@realm/react'; function WriteGeospatialObjects(): JSX.Element { const realm = useRealm(); const companies = useQuery(Company); useEffect(() => { if (!companies.length) { // Add geospatial objects to realm. writeNewCompany({_id: 6, location: new MyGeoPoint(-122.35, 47.68)}); writeNewCompany({_id: 9, location: new MyGeoPoint(-121.85, 47.9)}); } }, []); type CompanyProps = { _id: number; location: MyGeoPoint; }; const writeNewCompany = ({_id, location}: CompanyProps) => { // Add geospatial object to realm. realm.write(() => { realm.create(Company, { _id, location, }); }); }; return ( <View> <Geocircle /> <Geobox /> <Geopolygon /> </View> ); }
A imagem a seguir mostra os resultados da criação desses dois objetos de empresa.