Docs 菜单

Docs 主页开发应用程序Atlas Device SDKs

地理空间数据 - Kotlin SDK

在此页面上

  • 地理空间数据类型
  • GeoPoint
  • GeoCircle
  • GeoBOX
  • GeoPolygon
  • 保留地理空间数据
  • 创建与 GeoJSON 兼容的类
  • 使用嵌入式类
  • 查询地理空间数据
  • GeoCircle
  • GeoBOX
  • GeoPolygon

1.11.0 版本中的新增功能

地理空间数据指定地球表面上的点和几何对象。

Kotlin SDK 版本 1.11.0 及更高版本添加了实验性地理空间 API,支持使用地理空间数据进行查询。 这些查询可以检查给定点是否包含在形状中。例如,您可以查找指定点 15 公里范围内的所有咖啡店。

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

Kotlin SDK 版本 1.13.0 及更高版本增加了对 Atlas Device Sync 中地理空间数据的支持。 这允许您订阅同步 Realm 中的地理空间查询。 如果您尝试使用旧版本的 SDK 订阅地理空间查询,您将收到带有补偿写入的服务器错误。

有关托管同步订阅的更多信息,请参阅托管同步订阅 - Kotlin SDK。

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

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

  • GeoPoint

  • GeoCircle

  • GeoBOX

  • GeoPolygon

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

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

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

GeoCircle定义了地球表面上的一个圆。您可以通过为圆的中心提供GeoPoint和指定圆的半径的Distance对象来定义GeoCircle

注意

您可以以公里、英里、度或弧度为单位定义半径。

以下示例创建了 2 个圆形:

val circle1 = GeoCircle.create(
center = GeoPoint.create(47.8, -122.6),
radius = Distance.fromKilometers(44.4)
)
val circle2 = GeoCircle.create(
center = GeoPoint.create(47.3, -121.9),
radius = Distance.fromDegrees(0.25)
)
两个 GeoCircle
点击放大

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

以下示例将创建2框:

val box1 = GeoBox.create(
bottomLeft = GeoPoint.create(47.3, -122.7),
topRight = GeoPoint.create(48.1, -122.1)
)
val box2 = GeoBox.create(
bottomLeft = GeoPoint.create(47.5, -122.4),
topRight = GeoPoint.create(47.9, -121.8)
)
2 GeoBox
点击放大

GeoPolygon定义了地球表面上的多边形。

由于多边形是闭合形状,因此必须至少提供 4 个点:3 个点用于定义多边形的形状,第 4 个点用于闭合该形状。

重要

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

您还可以通过定义一个或多个“孔”来排除多边形内的区域。 孔洞是指其边界完全位于外部多边形内的另一个多边形。 孔也可以相互嵌套。 如果一个位置包含在奇数个环中,则该位置被视为位于多边形内部。

以下示例创建了 3 个多边形:

  • 具有 5 个点的基本多边形

  • 具有单孔的相同多边形

  • 有两个孔的同一多边形

// Create a basic polygon
val basicPolygon = GeoPolygon.create(
listOf(
GeoPoint.create(48.0, -122.8),
GeoPoint.create(48.2, -121.8),
GeoPoint.create(47.6, -121.6),
GeoPoint.create(47.0, -122.0),
GeoPoint.create(47.2, -122.6),
GeoPoint.create(48.0, -122.8)
)
)
// Create a polygon with a single hole
val outerRing = listOf(
GeoPoint.create(48.0, -122.8),
GeoPoint.create(48.2, -121.8),
GeoPoint.create(47.6, -121.6),
GeoPoint.create(47.0, -122.0),
GeoPoint.create(47.2, -122.6),
GeoPoint.create(48.0, -122.8)
)
val hole1 = listOf(
GeoPoint.create(47.8, -122.6),
GeoPoint.create(47.7, -122.2),
GeoPoint.create(47.4, -122.6),
GeoPoint.create(47.6, -122.5),
GeoPoint.create(47.8, -122.6)
)
val polygonWithOneHole = GeoPolygon.create(outerRing, hole1)
// Add a second hole to the polygon
val hole2 = listOf(
GeoPoint.create(47.55, -122.05),
GeoPoint.create(47.5, -121.9),
GeoPoint.create(47.3, -122.1),
GeoPoint.create(47.55, -122.05)
)
val polygonWithTwoHoles = GeoPolygon.create(outerRing, hole1, hole2)
3 GeoPolygons
点击放大

重要

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

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

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

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

要使用 Kotlin SDK 执行此操作,您可以创建一个与 GeoJSON 兼容的嵌入式类,然后在 Realm 数据模型中使用该类。

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

  1. 创建嵌入式 Realm 对象(从EmbeddedRealmObject继承的类)。

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

    • String 类型的属性字段,它映射到一个值为 "Point"type 属性:var type: String = "Point"

    • RealmList<Double>类型为 的字段,映射到 域coordinates 模式中的属性,其中包含纬度/经度对:var coordinates: RealmList<Double> = realmListOf()

以下示例显示了一个名为CustomGeoPoint的嵌入式类,用于保存地理空间数据:

class CustomGeoPoint : EmbeddedRealmObject {
constructor(latitude: Double, longitude: Double) {
coordinates.apply {
add(longitude)
add(latitude)
}
}
// Empty constructor required by Realm
constructor() : this(0.0, 0.0)
// Name and type required by Realm
var coordinates: RealmList<Double> = realmListOf()
// Name, type, and value required by Realm
private var type: String = "Point"
@Ignore
var latitude: Double
get() = coordinates[1]
set(value) {
coordinates[1] = value
}
@Ignore
var longitude: Double
get() = coordinates[0]
set(value) {
coordinates[0] = value
}
}

在 域 模型中使用customGeoPoint类,如以下示例所示:

class Company : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId()
var location: CustomGeoPoint? = null
}

然后,您可以将类的实例添加到 Realm 中:

realm.writeBlocking {
copyToRealm(
Company().apply {
location = CustomGeoPoint(47.68, -122.35)
}
)
copyToRealm(
Company().apply {
location = CustomGeoPoint(47.9, -121.85)
}
)
}

下图显示了创建这两个Company对象的结果:

2 个 GeoPoint
点击放大

要查询地理空间数据,可以将GEOWITHIN操作符与RQL结合使用。 此方法采用嵌入式对象的coordinates属性,并检查该点是否包含在该对象的地理空间形状内。

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

重要

不能对地理空间数据使用参数化查询。

以下示例展示了如何查询各种形状以返回形状内的公司列表。

val companiesInLargeCircle =
realm.query<Company>("location GEOWITHIN $circle1").find()
println("Companies in large circle: ${companiesInLargeCircle.size}")
val companiesInSmallCircle =
realm.query<Company>("location GEOWITHIN $circle2").find()
println("Companies in small circle: ${companiesInSmallCircle.size}")
Companies in large circle: 1
Companies in small circle: 0
查询 GeoCircle 示例
点击放大
val companiesInLargeBox =
realm.query<Company>("location GEOWITHIN $box1").find()
println("Companies in large box: ${companiesInLargeBox.size}")
val companiesInSmallBox =
realm.query<Company>("location GEOWITHIN $box2").find()
println("Companies in small box: ${companiesInSmallBox.size}")
Companies in large box: 1
Companies in small box: 2
查询 GeoBox 示例
val companiesInBasicPolygon =
realm.query<Company>("location GEOWITHIN $basicPolygon").find()
println("Companies in basic polygon: ${companiesInBasicPolygon.size}")
val companiesInPolygonWithHoles =
realm.query<Company>("location GEOWITHIN $polygonWithTwoHoles").find()
println("Companies in polygon with holes: ${companiesInPolygonWithHoles.size}")
Companies in basic polygon: 2
Companies in polygon with holes: 1
查询 GeoPolygon 示例
点击放大
← 关系 — Kotlin SDK