From 60469ca8fadf011a58348b3edcad0bc53a2834f1 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Tue, 20 Jun 2017 20:18:06 -0500 Subject: [PATCH 1/4] Add withinPolygon to Query --- Parse/src/main/java/com/parse/ParseQuery.java | 24 +++++++++++++++++++ .../test/java/com/parse/ParseQueryTest.java | 23 ++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/Parse/src/main/java/com/parse/ParseQuery.java b/Parse/src/main/java/com/parse/ParseQuery.java index 9542d6e1c..0e0829717 100644 --- a/Parse/src/main/java/com/parse/ParseQuery.java +++ b/Parse/src/main/java/com/parse/ParseQuery.java @@ -468,6 +468,12 @@ public Builder whereWithin(String key, ParseGeoPoint southwest, ParseGeoPoint return addCondition(key, "$within", dictionary); } + public Builder whereGeoWithin(String key, List points) { + Map> dictionary = new HashMap<>(); + dictionary.put("$polygon", points); + return addCondition(key, "$geoWithin", dictionary); + } + public Builder addCondition(String key, String condition, Collection value) { return addConditionInternal(key, condition, Collections.unmodifiableCollection(value)); @@ -1842,6 +1848,24 @@ public ParseQuery whereWithinGeoBox( return this; } + /** + * Adds a constraint to the query that requires a particular key's + * coordinates be contained within and on the bounds of a given polygon. + * Supports closed and open (last point is connected to first) paths + * + * Polygon must have at least 3 points + * + * @param key + * The key to be constrained. + * @param points + * Array of ParseGeoPoint + * @return this, so you can chain this call. + */ + public ParseQuery whereWithinPolygon( + String key, List points) { + builder.whereGeoWithin(key, points); + return this; + } /** * Add a regular expression constraint for finding string values that match the provided regular * expression. diff --git a/Parse/src/test/java/com/parse/ParseQueryTest.java b/Parse/src/test/java/com/parse/ParseQueryTest.java index 74c63b6c6..3f10560f1 100644 --- a/Parse/src/test/java/com/parse/ParseQueryTest.java +++ b/Parse/src/test/java/com/parse/ParseQueryTest.java @@ -530,6 +530,29 @@ public void testWhereWithinGeoBox() throws Exception { assertTrue(list.contains(pointAgain)); } + @Test + public void testWhereWithinPolygon() throws Exception { + ParseQuery query = new ParseQuery<>("Test"); + ParseGeoPoint point1 = new ParseGeoPoint(10, 10); + ParseGeoPoint point2 = new ParseGeoPoint(20, 20); + ParseGeoPoint point3 = new ParseGeoPoint(30, 30); + + List points = Arrays.asList(point1, point2, point3); + query.whereWithinPolygon("key", points); + + // We generate a state to verify the content of the builder + ParseQuery.State state = query.getBuilder().build(); + ParseQuery.QueryConstraints queryConstraints = state.constraints(); + ParseQuery.KeyConstraints keyConstraints = + (ParseQuery.KeyConstraints) queryConstraints.get("key"); + Map map = (Map) keyConstraints.get("$geoWithin"); + List list = (List) map.get("$polygon"); + assertEquals(3, list.size()); + assertTrue(list.contains(point1)); + assertTrue(list.contains(point2)); + assertTrue(list.contains(point3)); + } + @Test public void testWhereWithinRadians() throws Exception { ParseQuery query = new ParseQuery<>("Test"); From 38f5e3301be519e8bd6285e8115602eb4efd83b3 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Tue, 20 Jun 2017 20:18:06 -0500 Subject: [PATCH 2/4] Add withinPolygon to Query --- Parse/src/main/java/com/parse/ParseQuery.java | 25 +++++++++++++++++++ .../test/java/com/parse/ParseQueryTest.java | 22 ++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/Parse/src/main/java/com/parse/ParseQuery.java b/Parse/src/main/java/com/parse/ParseQuery.java index 652cb3363..23fb40f1b 100644 --- a/Parse/src/main/java/com/parse/ParseQuery.java +++ b/Parse/src/main/java/com/parse/ParseQuery.java @@ -468,6 +468,12 @@ public Builder whereWithin(String key, ParseGeoPoint southwest, ParseGeoPoint return addCondition(key, "$within", dictionary); } + public Builder whereGeoWithin(String key, List points) { + Map> dictionary = new HashMap<>(); + dictionary.put("$polygon", points); + return addCondition(key, "$geoWithin", dictionary); + } + public Builder whereGeoIntersects(String key, ParseGeoPoint point) { Map dictionary = new HashMap<>(); dictionary.put("$point", point); @@ -1848,6 +1854,25 @@ public ParseQuery whereWithinGeoBox( return this; } + /** + * Adds a constraint to the query that requires a particular key's + * coordinates be contained within and on the bounds of a given polygon. + * Supports closed and open (last point is connected to first) paths + * + * Polygon must have at least 3 points + * + * @param key + * The key to be constrained. + * @param points + * Array of ParseGeoPoint + * @return this, so you can chain this call. + */ + public ParseQuery whereWithinPolygon( + String key, List points) { + builder.whereGeoWithin(key, points); + return this; + } + /** * Add a constraint to the query that requires a particular key's * coordinates that contains a {@link ParseGeoPoint}s diff --git a/Parse/src/test/java/com/parse/ParseQueryTest.java b/Parse/src/test/java/com/parse/ParseQueryTest.java index 7177543fb..553cb49f2 100644 --- a/Parse/src/test/java/com/parse/ParseQueryTest.java +++ b/Parse/src/test/java/com/parse/ParseQueryTest.java @@ -530,6 +530,28 @@ public void testWhereWithinGeoBox() throws Exception { assertTrue(list.contains(pointAgain)); } + @Test + public void testWhereWithinPolygon() throws Exception { + ParseQuery query = new ParseQuery<>("Test"); + ParseGeoPoint point1 = new ParseGeoPoint(10, 10); + ParseGeoPoint point2 = new ParseGeoPoint(20, 20); + ParseGeoPoint point3 = new ParseGeoPoint(30, 30); + + List points = Arrays.asList(point1, point2, point3); + query.whereWithinPolygon("key", points); + + // We generate a state to verify the content of the builder + ParseQuery.State state = query.getBuilder().build(); + ParseQuery.QueryConstraints queryConstraints = state.constraints(); + ParseQuery.KeyConstraints keyConstraints = (ParseQuery.KeyConstraints) queryConstraints.get("key"); + Map map = (Map) keyConstraints.get("$geoWithin"); + List list = (List) map.get("$polygon"); + assertEquals(3, list.size()); + assertTrue(list.contains(point1)); + assertTrue(list.contains(point2)); + assertTrue(list.contains(point3)); + } + @Test public void testWherePolygonContains() throws Exception { ParseQuery query = new ParseQuery<>("Test"); From 447d6ad477ce877c1390dc0f75a9e2f34962d237 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Tue, 15 Aug 2017 16:17:22 -0500 Subject: [PATCH 3/4] offline query support for geowithin --- .../java/com/parse/OfflineQueryLogic.java | 20 ++++++++++ .../java/com/parse/OfflineQueryLogicTest.java | 38 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/Parse/src/main/java/com/parse/OfflineQueryLogic.java b/Parse/src/main/java/com/parse/OfflineQueryLogic.java index dd626cb7c..3e0c52e44 100644 --- a/Parse/src/main/java/com/parse/OfflineQueryLogic.java +++ b/Parse/src/main/java/com/parse/OfflineQueryLogic.java @@ -480,6 +480,23 @@ private static boolean matchesGeoIntersectsConstraint(Object constraint, Object return target.containsPoint(point); } + /** + * Matches $geoWithin constraints. + */ + private static boolean matchesGeoWithinConstraint(Object constraint, Object value) + throws ParseException { + if (value == null || value == JSONObject.NULL) { + return false; + } + + @SuppressWarnings("unchecked") + HashMap> constraintMap = + (HashMap>) constraint; + List points = constraintMap.get("$polygon"); + ParsePolygon polygon = new ParsePolygon(points); + ParseGeoPoint point = (ParseGeoPoint) value; + return polygon.containsPoint(point); + } /** * Returns true iff the given value matches the given operator and constraint. * @@ -535,6 +552,9 @@ private static boolean matchesStatelessConstraint(String operator, Object constr case "$within": return matchesWithinConstraint(constraint, value); + case "$geoWithin": + return matchesGeoWithinConstraint(constraint, value); + case "$geoIntersects": return matchesGeoIntersectsConstraint(constraint, value); diff --git a/Parse/src/test/java/com/parse/OfflineQueryLogicTest.java b/Parse/src/test/java/com/parse/OfflineQueryLogicTest.java index 7a77cdad4..f7d84c04f 100644 --- a/Parse/src/test/java/com/parse/OfflineQueryLogicTest.java +++ b/Parse/src/test/java/com/parse/OfflineQueryLogicTest.java @@ -579,6 +579,44 @@ public void testMatchesGeoIntersects() throws ParseException { assertFalse(matches(logic, query, object)); } + @Test + public void testMatchesGeoWithin() throws ParseException { + List smallBox = new ArrayList(); + smallBox.add(new ParseGeoPoint(0,0)); + smallBox.add(new ParseGeoPoint(0,1)); + smallBox.add(new ParseGeoPoint(1,1)); + smallBox.add(new ParseGeoPoint(1,0)); + + List largeBox = new ArrayList(); + largeBox.add(new ParseGeoPoint(0,0)); + largeBox.add(new ParseGeoPoint(0,10)); + largeBox.add(new ParseGeoPoint(10,10)); + largeBox.add(new ParseGeoPoint(10,0)); + + ParseGeoPoint point = new ParseGeoPoint(5,5); + + //ParsePolygon polygon = new ParsePolygon(points); + + ParseObject object = new ParseObject("TestObject"); + object.put("point", point); + + ParseQuery.State query; + OfflineQueryLogic logic = new OfflineQueryLogic(null); + query = new ParseQuery.State.Builder<>("TestObject") + .whereGeoWithin("point", largeBox) + .build(); + assertTrue(matches(logic, query, object)); + + query = new ParseQuery.State.Builder<>("TestObject") + .whereGeoWithin("point", smallBox) + .build(); + assertFalse(matches(logic, query, object)); + + // Non-existant key + object = new ParseObject("TestObject"); + assertFalse(matches(logic, query, object)); + } + //endregion //region compare From ed3ff26e20db6f5d00a6037b43044464f5080e1e Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Tue, 15 Aug 2017 20:31:21 -0500 Subject: [PATCH 4/4] withinPolygon with polygon --- Parse/src/main/java/com/parse/ParseQuery.java | 11 ++++++---- .../test/java/com/parse/ParseQueryTest.java | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Parse/src/main/java/com/parse/ParseQuery.java b/Parse/src/main/java/com/parse/ParseQuery.java index 23fb40f1b..6b72945bd 100644 --- a/Parse/src/main/java/com/parse/ParseQuery.java +++ b/Parse/src/main/java/com/parse/ParseQuery.java @@ -1863,16 +1863,19 @@ public ParseQuery whereWithinGeoBox( * * @param key * The key to be constrained. - * @param points - * Array of ParseGeoPoint + * @param value + * List or ParsePolygon * @return this, so you can chain this call. */ - public ParseQuery whereWithinPolygon( - String key, List points) { + public ParseQuery whereWithinPolygon(String key, List points) { builder.whereGeoWithin(key, points); return this; } + public ParseQuery whereWithinPolygon(String key, ParsePolygon polygon) { + return whereWithinPolygon(key, polygon.getCoordinates()); + } + /** * Add a constraint to the query that requires a particular key's * coordinates that contains a {@link ParseGeoPoint}s diff --git a/Parse/src/test/java/com/parse/ParseQueryTest.java b/Parse/src/test/java/com/parse/ParseQueryTest.java index 553cb49f2..066576afa 100644 --- a/Parse/src/test/java/com/parse/ParseQueryTest.java +++ b/Parse/src/test/java/com/parse/ParseQueryTest.java @@ -552,6 +552,28 @@ public void testWhereWithinPolygon() throws Exception { assertTrue(list.contains(point3)); } + @Test + public void testWhereWithinPolygonWithPolygon() throws Exception { + ParseQuery query = new ParseQuery<>("Test"); + ParseGeoPoint point1 = new ParseGeoPoint(10, 10); + ParseGeoPoint point2 = new ParseGeoPoint(20, 20); + ParseGeoPoint point3 = new ParseGeoPoint(30, 30); + + List points = Arrays.asList(point1, point2, point3); + query.whereWithinPolygon("key", new ParsePolygon(points)); + + // We generate a state to verify the content of the builder + ParseQuery.State state = query.getBuilder().build(); + ParseQuery.QueryConstraints queryConstraints = state.constraints(); + ParseQuery.KeyConstraints keyConstraints = (ParseQuery.KeyConstraints) queryConstraints.get("key"); + Map map = (Map) keyConstraints.get("$geoWithin"); + List list = (List) map.get("$polygon"); + assertEquals(3, list.size()); + assertTrue(list.contains(point1)); + assertTrue(list.contains(point2)); + assertTrue(list.contains(point3)); + } + @Test public void testWherePolygonContains() throws Exception { ParseQuery query = new ParseQuery<>("Test");