11.1.0 版新增功能。
地理空间数据或“地理数据”指定地球表面上的点和几何对象。 使用地理数据类型,您可以创建查询来检查给定点是否包含在形状中。 例如,您可以查找指定点 15 公里范围内的所有咖啡店。
在版本 11.6.1 中进行了更改: Atlas Device Sync 支持的地理空间数据
Realm .NET SDK 版本 11.16.1 及更高版本增加了对 Atlas Device Sync 中地理空间数据的支持。 这允许您订阅同步 Realm 中的地理空间查询。 如果您尝试使用旧版本的 SDK 订阅地理空间查询,您将收到带有补偿写入的服务器错误。 有关托管同步订阅的更多信息,请参阅托管 Flexible Sync 订阅 - .NET SDK。
有关使用Device Sync查询地理空间数据的更多信息,请参阅App Services文档中的地理空间数据。
地理空间数据类型
SDK 支持使用以下数据类型进行地理空间查询:
GeoPoint
GeoCircle
GeoBox
GeoPolygon
SDK 提供这些地理空间数据类型是为了简化地理空间数据的查询。 您无法直接持久化这些数据类型。
有关如何保存地理空间数据的信息,请参阅本页的保存GeoPoint 数据部分。
GeoPoint
GeoPoint定义了地球表面的特定位置。 所有地理空间数据类型都使用 GeoPoints来定义其位置。
注意
在采用GeoPoint的方法中,您也可以提供一个双精度元组,其中第一个双精度值是纬度,第二个双精度值是经度。 SDK 将这些元组解释为GeoPoints 。 本页上的示例演示了这两种方法。
GeoCircle
GeoCircle定义了地球表面上的一个圆。 您可以通过为圆的中心提供GeoPoint和指定圆的半径的Distance对象来定义GeoCircle 。
注意
您可以以公里、英里、度或弧度为单位定义半径。
以下代码显示了创建圆形的两个示例:
var circle1 = new GeoCircle((47.8, -122.6), Distance.FromKilometers(44.4)); var circle2 = new GeoCircle( new GeoPoint(latitude: 47.3, longitude: -121.9), Distance.FromDegrees(0.25));

GeoBox
GeoBox在地球表面定义了一个矩形。 您可以通过指定左下(西南)角和右上角(东北)角来定义矩形。 以下示例将创建2框:
var box1 = new GeoBox(bottomLeftCorner: (47.3, -122.7), topRightCorner: (48.1, -122.1)); var box2 = new GeoBox(new GeoPoint(47.5, -122.4), new GeoPoint(47.9, -121.8));

GeoPolygon
GeoPolygon定义了地球表面上的多边形。 由于多边形是闭合形状,因此必须提供至少4个点: 3个点用于定义多边形的形状,以及第四个点用于闭合形状。
重要
多边形中的第四个点必须与第一个点相同。
您还可以通过定义一个或多个“孔”来排除多边形内的区域。 孔洞是指其边界完全位于外部多边形内的另一个多边形。 以下示例创建了 3 个多边形:第一个是具有 5 个点的基本多边形,第一个是具有单孔的相同多边形,第三个是具有两个孔的相同多边形:
var basicPolygon = new GeoPolygon((48, -122.8), (48.2, -121.8), (47.6, -121.6), (47.0, -122.0), (47.2, -122.6), (48, -122.8)); // Create a polygon with a single hole var outerRing = new GeoPoint[] { (48, -122.8), (48.2, -121.8), (47.6, -121.6), (47.0, -122.0), (47.2, -122.6), (48, -122.8) }; var hole1 = new GeoPoint[] { (47.8, -122.6), (47.7, -122.2), (47.4, -122.6), (47.6, -122.5), (47.8, -122.6) }; var polygonWithOneHole = new GeoPolygon(outerRing, hole1); // Add a second hole to the polygon var hole2 = new GeoPoint[] { (47.55, -122.05), (47.5, -121.9),(47.3, -122.1), (47.55, -122.05) }; var polygonWithTwoHoles = new GeoPolygon(outerRing, hole1, hole2);

持久化 GeoPoint 数据
重要
无法保留地理空间数据类型
目前,您只能保留地理空间数据。 地理空间数据类型无法直接持久化。 例如,您不能声明类型为GeoBox的属性。
这些类型只能用作地理空间查询的参数。
如果要持久保存GeoPoint 数据,该数据必须符合GeoJSON规范 。
创建与 GeoJSON 兼容的类
要创建符合 GeoJSON 规范的类,您需要:
创建嵌入式 Realm 对象(从IEmbeddedObject继承的类)。
至少添加 GeoJSON 规范要求的两个字段:
类型为
IList<double>的字段,映射到 Realm 模式中的“坐标”(区分大小写)属性。类型为
string的字段,映射到“类型”属性。 此字段的值必须是“Point”。
以下示例显示了一个名为 "CustomGeoPoint" 的嵌入式类,用于持久保存 GeoPoint 数据:
public partial class CustomGeoPoint : IEmbeddedObject { [] public IList<double> Coordinates { get; } = null!; [] private string Type { get; set; } = "Point"; public CustomGeoPoint(double latitude, double longitude) { Coordinates.Add(longitude); Coordinates.Add(latitude); } }
使用嵌入式类
然后,您可以在 域 模型中使用自定义 GeoPoint 类,如以下示例所示:
public partial class Company : IRealmObject { [] [] public Guid Id { get; private set; } = Guid.NewGuid(); public CustomGeoPoint? Location { get; set; } public Company() { } }
然后,您可以像任何其他 Realm 模型一样将类的实例添加到 Realm:
realm.WriteAsync(() => { realm.Add(new Company { Location = new CustomGeoPoint(47.68, -122.35) }); realm.Add(new Company { Location = new CustomGeoPoint(47.9, -121.85) }); });
下图显示了创建这两个公司对象的结果。

查询地理空间数据
要查询地理空间数据,可以使用GeoWithin方法,也可以将geoWithin操作符与RQL结合使用。 GeoWithin方法采用嵌入式对象的“坐标”属性(定义我们正在查询的点)和地理空间形状之一来检查该点是否包含在该形状中。
注意
无论地理数据地区的形状如何,查询地理空间数据的格式都是相同的。
以下示例显示了使用GeoWithin方法和 RQL 进行查询之间的区别:
var GeoWthinExample = realm.All<Company>() .Where(c => QueryMethods.GeoWithin(c.Location, circle1)); var RQLExample = realm.All<Company>() .Filter("Location geoWithin $0", circle2);
以下示例展示了如何查询各种形状以返回形状内的公司列表:
GeoCircle
var companiesInCircle = realm.All<Company>() .Where(c => QueryMethods.GeoWithin(c.Location, circle1)); var companiesInSmallerCircle = realm.All<Company>() .Where(c => QueryMethods.GeoWithin(c.Location, circle2));

GeoBox
var companiesInBox1 = realm.All<Company>() .Where(c => QueryMethods.GeoWithin(c.Location, box1)); var companiesInBox2 = realm.All<Company>() .Where(c => QueryMethods.GeoWithin(c.Location, box2));

GeoPolygon
var companiesInBasicPolygon = realm.All<Company>() .Where(c => QueryMethods .GeoWithin(c.Location, basicPolygon)); var companiesInPolygon = realm.All<Company>() .Where(c => QueryMethods .GeoWithin(c.Location, polygonWithTwoHoles));
