Docs 菜单
Docs 主页
/ /
Atlas Device SDKs
/ / /

地理空间 — React Native SDK

在此页面上

  • 地理空间数据类型
  • GeoPoint
  • GeoCircle
  • GeoBox
  • GeoPolygon
  • 保留地理空间数据
  • 创建与 GeoJSON 兼容的类
  • 编写嵌入式类

版本 12.0.0 中的新增内容

地理空间数据或“地理数据”指定地球表面上的点和几何对象。 使用地理数据类型,您可以创建查询来检查给定点是否包含在形状中。 例如,您可以查找距离指定点15公里范围内的所有咖啡店。

在版本 realm@12.3.0中进行了更改:Atlas Device Sync 支持地理空间数据

Realm .js v 12.3.0及更高版本添加了对Atlas Device Sync中地理空间数据的支持。 这允许您订阅同步域中的地理空间查询。 如果您尝试使用旧版本的 SDK订阅地理空间查询,您将收到带有补偿写入的服务器错误。 有关管理 Sync 订阅的更多信息,请参阅地理空间 - React Native SDK。

有关使用 查询地理空间数据的更多信息,请参阅Device Sync Atlas App Services文档中的 地理空间数据 。

SDK 支持使用以下数据类型进行地理空间查询:

  • GeoPoint

  • GeoCircle

  • GeoBox

  • GeoPolygon

SDK 提供这些地理空间数据类型是为了简化地理空间数据的查询。 您无法直接持久化这些数据类型。

有关如何保存地理空间数据的信息,请参阅本页的保存地理空间数据部分。

要查询地理空间数据,可以将geoWithin操作符与RQL结合使用。 geoWithin操作符采用嵌入式对象的coordinates属性(定义我们正在查询的点)和地理空间形状之一来检查该点是否包含在该形状中。

注意

无论地理数据区域的形状如何,查询地理空间数据的格式都是相同的。

GeoPoint定义了地球表面的特定位置。 所有地理空间数据类型都使用GeoPoints来定义其位置。

GeoPoint 可以是以下三种类型之一:

  • 一个对象:

    • latitude:一个数值

    • longitude:一个数值

    • altitude:可选数值

  • CanonicalGeoPoint:满足点的 GeoJSON 规范的接口

  • GeoPosition:具有经度、纬度和可选海拔高度的数组

GeoPoint 仅用作其他形状的构建基块:GeoCircle、GeoBox 和 GeoPolygon。 这些形状和 GeoPoint 类型用于查询,而不是用于持久性。

要将地理空间数据保存到域,请参阅本页的持久地理空间数据。

GeoCircle定义了地球表面上的一个圆。 您可以通过提供以下内容来定义GeoCircle

  • 代表圆心的GeoPoint

  • 表示圆的距离(半径)的数字

半径距离使用弧度作为测量单位。 SDK 提供了方法kmToRadiansmiToRadians将公里或英里转换为弧度。

以下代码显示了创建圆形的两个示例:

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>
);
}

下图显示了创建两个对象的结果:一个小圆圈和一个大圆圈。

两个 GeoCircle
点击放大

对地理空间数据的查询会返回您定义的形状内的 Realm 对象。在上面的示例中,这是我们的查询结果:

查询 GeoCircle 示例。
点击放大

GeoBox在地球表面定义了一个矩形。 您可以通过指定左下(西南)角和右上角(东北)角来定义矩形。 GeoBox 的行为与相应的 GeoPolygon 相同。

以下示例将创建2框:

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>
);
}

下图显示了创建两个对象的结果:一个小方框和一个大方框。

2 GeoBox
点击放大

对地理空间数据的查询会返回您定义的形状内的 Realm 对象。在上面的示例中,这是我们的查询结果:

查询 GeoBox 示例。

GeoPolygon定义了地球表面上的多边形。 由于多边形是闭合形状,因此必须提供至少4个点: 3个点用于定义多边形的形状,以及第四个点用于闭合形状。

重要

多边形中的第四个点必须与第一个点相同。

您还可以通过定义一个或多个“孔”来排除多边形内的区域。 孔洞是指其边界完全位于外部多边形内的另一个多边形。 以下示例创建了 3 个多边形:第一个是具有 5 个点的基本多边形,第一个是具有单孔的相同多边形,第三个是具有两个孔的相同多边形:

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>
);
}

下图显示了创建三个对象的结果:一个多边形、一个带一个孔的多边形和一个带两个孔的多边形。

3 GeoPolygons
点击放大

对地理空间数据的查询会返回您定义的形状内的 Realm 对象。在上面的示例中,这是我们的查询结果:

查询 GeoPolygon 示例。
点击放大

重要

无法保留地理空间数据类型

目前,您只能保留地理空间数据。 地理空间数据类型无法直接持久化。 例如,您不能声明类型为GeoBox的属性。

这些类型只能用作地理空间查询的参数。

如果要持久保存地理空间数据,则必须符合 GeoJSON规范

要创建符合 GeoJSON 规范的类,您需要:

  1. 创建嵌入式 Realm 对象。有关嵌入式对象的更多信息,请参阅嵌入式对象 - React Native SDK。

  2. 至少添加 GeoJSON 规范要求的两个字段:

    • 类型为double[]的字段,映射到 Realm 模式中的“坐标”(区分大小写)属性。

    • 类型为string的字段,映射到“类型”属性。 此字段的值必须是“Point”。

为了简化地理数据持久性,您可以定义一个实现CanonicalGeoPoint的模型,该模型已经具有正确的形状。 以下示例显示了一个名为MyGeoPoint的嵌入式类,用于保存地理空间数据。

然后,您可以在 域 模型中使用自定义MyGeoPoint类,如以下示例所示。您可以将类的实例添加到 Realm,就像添加任何其他 Realm 模型一样。但是,在此示例中,由于MyGeoPoint类未扩展Realm.Object ,因此在打开域时必须指定MyGeoPoint.schema

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>
);
};

RealmProvider中,通过将嵌入式类与扩展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>
);
}

下图显示了创建这两个公司对象的结果。

2 个 GeoPoint
点击放大

后退

嵌入式对象