-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Geo-spatial queries #1403
Conversation
# Conflicts: # packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/GeoSpatialTests.kt
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/GeoBox.kt
Outdated
Show resolved
Hide resolved
* This class represents an equatorial distance that can be used in geospatial queries like those | ||
* represented by a [GeoCircle]. | ||
*/ | ||
public data class Distance private constructor( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This distance is the distance on the surface of the earth, isn't it? Could we use a different name like EarthSurfaceDistance
or GeoDistance
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is the distance on the earth. I guess we could have also gone with GeoDistance
, but Distance
was the name used in the technical scope: https://docs.google.com/document/d/1Z7CK79CqebEtVllVHTNEq8neKhoMWeFCDjKBrn_pq1Y/ and I don't think that is particular confusing? And it is shorter than GeoDistance
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It confuses me because it mixed linear and angular distances.
We implicitly use the earth's radius to correlate between them, but we are not explicitly stating in the documentation that we are using it. Instead, we could be explicit:
val distance: Distance = 1.2.earthRadians
val distance: Distance = 1.2.earthDegrees
val distance: Distance = 10.4.km
val distance: Distance = 10.5.miles
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm missing something obvious here, but how could radians
be interpreted in any other way than Earth radians? Like what can it potentially be confused with?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also had the same feeling like Clemente. It isn't at all obvious that radians are "earth radians" as a distance (if such a term even exists!). But once you start interpreting this as "equatorial distance in radians" it starts to be ok to work with. I think it is just something people will need to grasp and then it is ok. I tried to suggest updates to some docs by adding explicit "equatorial distance" here and there to speed up the "learning curve" to make it more clear. Anyway the km
should make it possible to work with it without bothering with the internals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole Geo-Spatial solution is generic, it can work on any sphere. It is this Distance
implementation that tights it to the Earth.
The thing is that this solution works for other spheres too, planets or simulations. If these KM/Miles are used on a different sphere than the earth it would not be correct. Adding a comment about it would be fine.
Here I tried to convert values Distance as a linear distance, that's why I wrote "earthRadians" (radians*earth radius = linear distance ). But we actually require angular distance so forget about it.
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/Distance.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/Distance.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/GeoBox.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/GeoPoint.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/GeoPolygon.kt
Outdated
Show resolved
Hide resolved
packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/GeoSpatialTests.kt
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/Distance.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/Distance.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/Distance.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/GeoBox.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/GeoCircle.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/Distance.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/Distance.kt
Outdated
Show resolved
Hide resolved
packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/GeoSpatialTests.kt
Show resolved
Hide resolved
packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/GeoSpatialTests.kt
Show resolved
Hide resolved
packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/GeoSpatialTests.kt
Show resolved
Hide resolved
Co-authored-by: Claus Rørbech <claus.rorbech@mongodb.com>
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/GeoCircle.kt
Outdated
Show resolved
Hide resolved
* This class represents an equatorial distance that can be used in geospatial queries like those | ||
* represented by a [GeoCircle]. | ||
*/ | ||
public data class Distance private constructor( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It confuses me because it mixed linear and angular distances.
We implicitly use the earth's radius to correlate between them, but we are not explicitly stating in the documentation that we are using it. Instead, we could be explicit:
val distance: Distance = 1.2.earthRadians
val distance: Distance = 1.2.earthDegrees
val distance: Distance = 10.4.km
val distance: Distance = 10.5.miles
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/GeoPolygon.kt
Outdated
Show resolved
Hide resolved
I reworked the API based on our discussions. It should be ready for another round of review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. Only some minor comments here and there.
* @throws IllegalArgumentException if the input polygon break some of the rules outlined | ||
* above. | ||
*/ | ||
public fun create(outerRing: List<GeoPoint>, holes: List<List<GeoPoint>>): GeoPolygon { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to be able to GeoBox
, GeoPolygon
and GeoCircles
as holes? ... But I guess we can always add a subtype to the regional types and an overload method, so nothing for this PR.
public companion object { | ||
|
||
private const val DEGREE_TO_RADIAN: Double = PI / 180.0 | ||
private const val RADIAN_TO_DEGREE: Double = 180.0 / PI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels a bit funny to define both just to be able use multiplication in both conversion. Maybe only define one and then divide in one of the ways.
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/geo/GeoBox.kt
Outdated
Show resolved
Hide resolved
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/geo/GeoPoint.kt
Outdated
Show resolved
Hide resolved
packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/GeoSpatialTests.kt
Outdated
Show resolved
Hide resolved
packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/GeoSpatialTests.kt
Show resolved
Hide resolved
if (outerRing.size < MIN_RING_SIZE) { | ||
throw IllegalArgumentException("The outer ring requires at least $MIN_RING_SIZE points: ${outerRing.size}") | ||
} | ||
if (outerRing.first() != outerRing.last()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Maybe I was not right in suggesting this check. I am a bit confused, though, so don't know what is up and down 🙃. Seems like the general GeoPolygon
class documentation state that there must be four https://github.com/realm/realm-kotlin/pull/1403/files#diff-bb869c11647feb614648b9cdafb62fb3aa3b95c2b18f6d81f3cd714f90cce286R29-R31, but then it is also mentioned that the first and last point is implicitly connected in https://github.com/realm/realm-kotlin/pull/1403/files#diff-bb869c11647feb614648b9cdafb62fb3aa3b95c2b18f6d81f3cd714f90cce286R102-R103. The reason why I suggested the check was just to catch errors before performing the actual queries, but if there is an option to leave out the duplicate first/last point and consider it being implicit I would vote for allowing that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is totally valid as it is required that the first and last points to be the same, otherwise core would throw an exception.
packages/library-base/src/commonMain/kotlin/io/realm/kotlin/types/geo/GeoPolygon.kt
Outdated
Show resolved
Hide resolved
* The recommended approach is encapsulating this inside its own [EmbeddedRealmObject], like this | ||
* | ||
* ``` | ||
* public class Location: EmbeddedRealmObject { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not provide the implementation for this type? We have types for querying but not for persistence. Also, this type could implement GeoPoint
for better integration with the Geo APIs.
It is some temporal code, but having to copy/paste this code makes it hard to discover, and leaves us with no control over it, we cannot deprecate it, or notify the users to move to another "final" type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is because we can't force the type name from the client. E.g. if the server json schema defines the location type as Person_Address_Location
(i.e. automatically generated name for an unnamed embedded object), we will end up with schema mismatch if the user attempts to use the SDK-specified Location
. This is covered in the "Design Alternnatives" section of the Design doc.
In phase 2 we will have a dedicated type both on the client and the server, but this work was deemed quite involved and we didn't want to delay phase 1 because of it.
## Pull Request Info - Document geospatial queries: realm/realm-kotlin#1403 - Update to v1.11.0 > NOTE: API ref links won't work until v1.11.0 refs are published ### Jira - https://jira.mongodb.org/browse/DOCSP-30997 ### Staged Changes - [Geospatial Data - Kotlin SDK](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-30997-geospatial/sdk/kotlin/realm-database/schemas/data-types/geospatials/) - new page ### Reminder Checklist If your PR modifies the docs, you might need to also update some corresponding pages. Check if completed or N/A. - [x] Create Jira ticket for corresponding docs-app-services update(s), if any - [x] Checked/updated Admin API - [x] Checked/updated CLI reference ### Review Guidelines [REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md)
This PR is adding support for Geo-spatial queries. Core doesn't have a specific geo-type (yet), so this is just the first version which relies on duck-typing.
This means that geo queries can be used on any embedded objects that has a
type
andcoordinates
property.This also has the implication that it is slightly awkward to to pass in geo-parameters. The current implementation overrides the
toString()
method which will format the data structures so they can be used from within a query.TODO