์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ - Kotlin SDK
์ด ํ์ด์ง์ ๋ด์ฉ
๋ฒ์ 1.11.0์ ์๋ก์ด ๊ธฐ๋ฅ.
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ๋๋ "์ง๋ฆฌ ๋ฐ์ดํฐ"๋ ์ง๊ตฌ ํ๋ฉด์ ์ง์ ๊ณผ ๊ธฐํํ์ ๊ฐ์ฒด๋ฅผ ์ง์ ํฉ๋๋ค.
Kotlin SDK ๋ฒ์ 1.11.0 ์ด์์๋ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ฟผ๋ฆฌ๋ฅผ ์ง์ํ๋ ์คํ์ ์ง๋ฆฌ ๊ณต๊ฐ์ API๊ฐ ์ถ๊ฐ๋์์ต๋๋ค. ์ด๋ฌํ ์ฟผ๋ฆฌ๋ ์ฃผ์ด์ง ์ ์ด ๋ํ ๋ด์ ํฌํจ๋์ด ์๋์ง ํ์ธํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ง์ ๋ ์ ์์ 15km ์ด๋ด์ ์๋ ๋ชจ๋ ์ปคํผ์์ ์ฐพ์ ์ ์์ต๋๋ค.
๋ฒ์ 1.13.0์์ ๋ณ๊ฒฝ๋จ : Atlas Device Sync์์ ์ง์๋๋ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ
Kotlin SDK ๋ฒ์ 1.13.0 ์ด์์๋ Atlas Device Sync์์ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ์ ๋ํ ์ง์์ด ์ถ๊ฐ๋์์ต๋๋ค. ์ด๋ฅผ ํตํด ๋๊ธฐํ๋ ์์ญ์์ ์ง๋ฆฌ ๊ณต๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ๋ ํ ์ ์์ต๋๋ค. ์ด์ ๋ฒ์ ์ SDK์์ ์ง๋ฆฌ ๊ณต๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ๋ ํ๋ ค๊ณ ํ๋ฉด ๋ณด์ ์ฉ ์ฐ๊ธฐ์ ํจ๊ป ์๋ฒ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋๊ธฐํ ๊ตฌ๋ ๊ด๋ฆฌ์ ๋ํ ์์ธํ ๋ด์ฉ์ ๋๊ธฐํ ๊ตฌ๋ ๊ด๋ฆฌ - Kotlin SDK๋ฅผ ์ฐธ์กฐํ์ธ์.
Device Sync ๋ฅผ ์ฌ์ฉํ์ฌ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฟผ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์ธํ ๋ด์ฉ์ App Services ๋ฌธ์์์ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ ํ
Kotlin SDK๋ ๋ค์ ๋ฐ์ดํฐ ์ ํ์ ์ฌ์ฉํ์ฌ ์ง๋ฆฌ์ ๊ณต๊ฐ ์ฟผ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค:
GeoPoint
GeoCircle
GeoBox
GeoPolygon
SDK๋ ์ด๋ฌํ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ ํ์ ์ ๊ณตํ์ฌ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ฟผ๋ฆฌ๋ฅผ ๊ฐ์ํํฉ๋๋ค. ์ด๋ฌํ ๋ฐ์ดํฐ ์ ํ์ ์ง์ ์ ์งํ ์ ๋ ์์ต๋๋ค .
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ์งํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ด ํ์ด์ง์ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ ์ง ์น์ ์ ์ฐธ์กฐํ์ธ์.
GeoPoint
GeoPoint ๋ ์ง๊ตฌ ํ๋ฉด์ ํน์ ์์น๋ฅผ ์ ์ํฉ๋๋ค. ๋ชจ๋ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ ํ์ GeoPoints
๋ฅผ ์ฌ์ฉํ์ฌ ์์น๋ฅผ ์ ์ํฉ๋๋ค.
GeoCircle
GeoCircle ์ ์ง๊ตฌ ํ๋ฉด์ ์์ ์ ์ํฉ๋๋ค. ์์ ์ค์ฌ์ 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๊ฐ, ๋ชจ์์ ๋ซ๋ ๋ฐ ๋ค ๋ฒ์งธ ์ ).
์ค์
๋ค๊ฐํ์ ๋ค ๋ฒ์งธ ์ ์ ์ฒซ ๋ฒ์งธ ์ ๊ณผ ๊ฐ์์ผ ํฉ๋๋ค.
ํ๋ ์ด์์ "ํ"์ ์ ์ํ์ฌ ๋ค๊ฐํ ๋ด์ ์์ญ์ ์ ์ธํ ์๋ ์์ต๋๋ค. ๊ตฌ๋ฉ์ ๊ฒฝ๊ณ๊ฐ ์ธ๋ถ ๋ค๊ฐํ ๋ด์ ์์ ํ ๋ค์ด๊ฐ๋ ๋ ๋ค๋ฅธ ๋ค๊ฐํ์ ๋๋ค. ๊ตฌ๋ฉ์ ์๋ก ์ค์ฒฉ๋ ์๋ ์์ต๋๋ค. ์์น๊ฐ ํ์์ ๋ง์ ํฌํจ๋ ๊ฒฝ์ฐ ์์น๋ ๋ค๊ฐํ ๋ด๋ถ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
๋ค์ ์์ ์์๋ 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)
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ ์ง
์ค์
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ ํ์ ์ง์ํ ์ ์์
ํ์ฌ๋ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ง ์ ์งํ ์ ์์ต๋๋ค. ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ ํ์ ์ง์ ์ ์งํ ์ ์์ต๋๋ค . ์๋ฅผ ๋ค์ด GeoBox
์ ํ์ ์์ฑ์ ์ ์ธํ ์ ์์ต๋๋ค.
์ด๋ฌํ ์ ํ์ ์ง๋ฆฌ๊ณต๊ฐ ์ฟผ๋ฆฌ์ ์ธ์๋ก๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ์งํ๋ ค๋ฉด GeoJSON ์ฌ์์ ์ค์ํด์ผ ํฉ๋๋ค.
Kotlin SDK๋ก ์ด ์์ ์ ์ํํ๋ ค๋ฉด Realm ๋ฐ์ดํฐ ๋ชจ๋ธ์์ ์ฌ์ฉํ ์ ์๋ GeoJSON ํธํ ์๋ฒ ๋๋ ํด๋์ค๋ฅผ ์์ฑํ๋ฉด ๋ฉ๋๋ค.
GeoJSON ํธํ ํด๋์ค ๋ง๋ค๊ธฐ
GeoJSON ์ฌ์์ ์ค์ํ๋ ํด๋์ค๋ฅผ ๋ง๋ค๋ ค๋ฉด ๋ค์์ ์ํํฉ๋๋ค.
ํฌํจ๋ Realm ๊ฐ์ฒด ( EmbeddedRealmObject ๋ฅผ ์์ํ๋ ํด๋์ค)๋ฅผ ๋ง๋ญ๋๋ค.
์ต์ํ GeoJSON ์ฌ์์ ํ์ํ ๋ ๊ฐ์ ํ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
๊ฐ์ด
"Point"
์ธtype
์์ฑ์ ๋งคํ๋๋ ์ ํString
์์ฑ์ ํ๋:var type: String = "Point"
์๋/๊ฒฝ๋ ์์ ํฌํจํ๋ ์์ญ ์คํค๋ง์
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 } }
์๋ฒ ๋๋ ํด๋์ค ์ฌ์ฉ
๋ค์ ์์ ์ ๊ฐ์ด ์์ญ ๋ชจ๋ธ์์ 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) } ) }
๋ค์ ์ด๋ฏธ์ง๋ ๋ ๊ฐ์ Company
๊ฐ์ฒด๋ฅผ ์์ฑํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ค๋๋ค.
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ ์ฟผ๋ฆฌ
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฟผ๋ฆฌํ๋ ค๋ฉด GEOWITHIN
์ฐ์ฐ์๋ฅผ RQL ๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ๋ฉ์๋๋ ๋ด์ฅ๋ ๊ฐ์ฒด์ coordinates
์์ฑ์ ์ฌ์ฉํ์ฌ ํด๋น ์ ์ด ํด๋น ๊ฐ์ฒด์ ์ง๋ฆฌ ๊ณต๊ฐ์ ๋ชจ์ ๋ด์ ํฌํจ๋์ด ์๋์ง ํ์ธํฉ๋๋ค.
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฟผ๋ฆฌํ๋ ํ์์ ์ง๋ฆฌ ๋ฐ์ดํฐ ๋ฆฌ์ ์ ํํ์ ๊ด๊ณ์์ด ๋์ผํฉ๋๋ค.
์ค์
์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฐ์ดํฐ์๋ ๋งค๊ฐ ๋ณ์ํ๋ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ค์ ์์ ์์๋ ๋ค์ํ ํํ์ ๋ํด ์ฟผ๋ฆฌํ์ฌ ํํ ๋ด์ ํ์ฌ ๋ชฉ๋ก์ ๋ฐํํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ ์ค๋๋ค.
GeoCircle
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