地理空間データ - Kotlin SDK
項目一覧
バージョン 1.11.0 の新機能。
地理空間データ(「geodata」)では、地表の点と幾何学的オブジェクトを指定します。
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 は、次のデータ型を使用する地理空間クエリをサポートしています。
地理的ポイント
Geo循環
GeoBox
GeoPolygon
SDK はこれらの地理空間データ型を提供し、地理空間データのクエリを簡素化します。 これらのデータ型を直接永続化することはできません。
地理空間データを永続化する方法の詳細については、このページの「 永続的な地理空間データ」セクションを参照してください。
地理的ポイント
GeoPointは、地上の特定のロケーションを定義します。 すべての地理空間データ型は、ロケーションを定義するために GeoPoints
を使用します。
Geo循環
Georoundは、地球の表面上の円を定義します。 円の中心にGeoPoint
を指定し、円の半径を指定するために距離オブジェクトを指定して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) )
GeoBox
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) )
GeoPolygon
GeoPolygonは、地球の表面上の多角形を定義します。
多角形は閉じた形状であるため、少なくとも 4 つのポイントを指定する必要があります。つまり、多角形の形状を定義するための 3 ポイントと、その形状を閉じるための 4 つ目のポイントです。
重要
多角形内の 4 番目の点は最初の点と同じである必要があります。
1 つ以上の「穴」を定義して、多角形内の領域を除外することもできます。 穴は、境界が外側の多角形内に完全に収まる別の多角形です。 穴は相互にネストすることもできます。 奇数の円に含まれている場合、ロケーションは多角形内と見なされます。
次の例では、3 つの多角形を作成しています。
5 つの点を持つ基本的な多角形
穴が 1 つある同じ多角形
2 つの穴を持つ同じ多角形
// 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)
永続的な地理空間データ
重要
地理空間データ型を永続化できません
現在、永続化できるのは地理空間データのみです。 地理空間データ型を直接永続化することはできません。 たとえば、タイプGeoBox
のプロパティを宣言することはできません。
これらの型は、地理空間クエリの引数としてのみ使用できます。
地理空間データを永続化する場合は、 GeoJSON 仕様 に準拠する必要があります。
Kotlin SDK でアクセスできるようにするには、GeoJSON と互換性のある埋め込みクラスを作成し、データモデルで使用します。
GeoJSON 互換クラスの作成
GeoJSON 仕様に準拠するクラスを作成するには、次の手順に従います。
埋め込み Realm オブジェクト(埋め込み RealmObjectから継承するクラス)を作成します。
少なくとも、GeoJSON 仕様に必要な 2 つのフィールドを追加します。
"Point"
の値を持つtype
プロパティにマッピングするString
プロパティのフィールド:var type: String = "Point"
緯度と経度のペアを含む Realm スキーマ内の
coordinates
プロパティにマッピングするRealmList<Double>
タイプのフィールド: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" var latitude: Double get() = coordinates[1] set(value) { coordinates[1] = value } var longitude: Double get() = coordinates[0] set(value) { coordinates[0] = value } }
埋め込みクラスの使用
次の例に示すように、Realm モデルでcustomGeoPoint
クラスを使用します。
class Company : RealmObject { 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) } ) }
次の画像には、これら 2 つのCompany
オブジェクトを作成した結果が示されています。
地理空間データのクエリ
地理空間データに対してクエリを実行するには、 RQLとともにGEOWITHIN
演算子を使用できます。 このメソッドは、埋め込みオブジェクトのcoordinates
プロパティを受け取り、その点がそのオブジェクトの地理空間形状内に含まれているかどうかを確認します。
地理空間データをクエリするための形式は、地理データ リージョンの形状に関係なく同じです。
重要
地理空間データでは、パラメーター化されたクエリは使用できません。
次の例では、さまざまなシェイプに対するクエリを実行して、そのシェイプ内の会社のリストを返す方法を示しています。
Geo循環
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
GeoBox
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
GeoPolygon
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