Skip to content

Commit 28fd9e1

Browse files
dplewisnatario1
authored andcommitted
Add withinPolygon to Query (#684)
* Add withinPolygon to Query * offline query support for geowithin * withinPolygon with polygon
1 parent 351d54b commit 28fd9e1

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

Parse/src/main/java/com/parse/OfflineQueryLogic.java

+20
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,23 @@ private static boolean matchesGeoIntersectsConstraint(Object constraint, Object
480480
return target.containsPoint(point);
481481
}
482482

483+
/**
484+
* Matches $geoWithin constraints.
485+
*/
486+
private static boolean matchesGeoWithinConstraint(Object constraint, Object value)
487+
throws ParseException {
488+
if (value == null || value == JSONObject.NULL) {
489+
return false;
490+
}
491+
492+
@SuppressWarnings("unchecked")
493+
HashMap<String, List<ParseGeoPoint>> constraintMap =
494+
(HashMap<String, List<ParseGeoPoint>>) constraint;
495+
List<ParseGeoPoint> points = constraintMap.get("$polygon");
496+
ParsePolygon polygon = new ParsePolygon(points);
497+
ParseGeoPoint point = (ParseGeoPoint) value;
498+
return polygon.containsPoint(point);
499+
}
483500
/**
484501
* Returns true iff the given value matches the given operator and constraint.
485502
*
@@ -535,6 +552,9 @@ private static boolean matchesStatelessConstraint(String operator, Object constr
535552
case "$within":
536553
return matchesWithinConstraint(constraint, value);
537554

555+
case "$geoWithin":
556+
return matchesGeoWithinConstraint(constraint, value);
557+
538558
case "$geoIntersects":
539559
return matchesGeoIntersectsConstraint(constraint, value);
540560

Parse/src/main/java/com/parse/ParseQuery.java

+28
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,12 @@ public Builder<T> whereWithin(String key, ParseGeoPoint southwest, ParseGeoPoint
468468
return addCondition(key, "$within", dictionary);
469469
}
470470

471+
public Builder<T> whereGeoWithin(String key, List<ParseGeoPoint> points) {
472+
Map<String, List<ParseGeoPoint>> dictionary = new HashMap<>();
473+
dictionary.put("$polygon", points);
474+
return addCondition(key, "$geoWithin", dictionary);
475+
}
476+
471477
public Builder<T> whereGeoIntersects(String key, ParseGeoPoint point) {
472478
Map<String, ParseGeoPoint> dictionary = new HashMap<>();
473479
dictionary.put("$point", point);
@@ -1848,6 +1854,28 @@ public ParseQuery<T> whereWithinGeoBox(
18481854
return this;
18491855
}
18501856

1857+
/**
1858+
* Adds a constraint to the query that requires a particular key's
1859+
* coordinates be contained within and on the bounds of a given polygon.
1860+
* Supports closed and open (last point is connected to first) paths
1861+
*
1862+
* Polygon must have at least 3 points
1863+
*
1864+
* @param key
1865+
* The key to be constrained.
1866+
* @param value
1867+
* List<ParseGeoPoint> or ParsePolygon
1868+
* @return this, so you can chain this call.
1869+
*/
1870+
public ParseQuery<T> whereWithinPolygon(String key, List<ParseGeoPoint> points) {
1871+
builder.whereGeoWithin(key, points);
1872+
return this;
1873+
}
1874+
1875+
public ParseQuery<T> whereWithinPolygon(String key, ParsePolygon polygon) {
1876+
return whereWithinPolygon(key, polygon.getCoordinates());
1877+
}
1878+
18511879
/**
18521880
* Add a constraint to the query that requires a particular key's
18531881
* coordinates that contains a {@link ParseGeoPoint}s

Parse/src/test/java/com/parse/OfflineQueryLogicTest.java

+38
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,44 @@ public void testMatchesGeoIntersects() throws ParseException {
579579
assertFalse(matches(logic, query, object));
580580
}
581581

582+
@Test
583+
public void testMatchesGeoWithin() throws ParseException {
584+
List<ParseGeoPoint> smallBox = new ArrayList<ParseGeoPoint>();
585+
smallBox.add(new ParseGeoPoint(0,0));
586+
smallBox.add(new ParseGeoPoint(0,1));
587+
smallBox.add(new ParseGeoPoint(1,1));
588+
smallBox.add(new ParseGeoPoint(1,0));
589+
590+
List<ParseGeoPoint> largeBox = new ArrayList<ParseGeoPoint>();
591+
largeBox.add(new ParseGeoPoint(0,0));
592+
largeBox.add(new ParseGeoPoint(0,10));
593+
largeBox.add(new ParseGeoPoint(10,10));
594+
largeBox.add(new ParseGeoPoint(10,0));
595+
596+
ParseGeoPoint point = new ParseGeoPoint(5,5);
597+
598+
//ParsePolygon polygon = new ParsePolygon(points);
599+
600+
ParseObject object = new ParseObject("TestObject");
601+
object.put("point", point);
602+
603+
ParseQuery.State<ParseObject> query;
604+
OfflineQueryLogic logic = new OfflineQueryLogic(null);
605+
query = new ParseQuery.State.Builder<>("TestObject")
606+
.whereGeoWithin("point", largeBox)
607+
.build();
608+
assertTrue(matches(logic, query, object));
609+
610+
query = new ParseQuery.State.Builder<>("TestObject")
611+
.whereGeoWithin("point", smallBox)
612+
.build();
613+
assertFalse(matches(logic, query, object));
614+
615+
// Non-existant key
616+
object = new ParseObject("TestObject");
617+
assertFalse(matches(logic, query, object));
618+
}
619+
582620
//endregion
583621

584622
//region compare

Parse/src/test/java/com/parse/ParseQueryTest.java

+44
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,50 @@ public void testWhereWithinGeoBox() throws Exception {
530530
assertTrue(list.contains(pointAgain));
531531
}
532532

533+
@Test
534+
public void testWhereWithinPolygon() throws Exception {
535+
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
536+
ParseGeoPoint point1 = new ParseGeoPoint(10, 10);
537+
ParseGeoPoint point2 = new ParseGeoPoint(20, 20);
538+
ParseGeoPoint point3 = new ParseGeoPoint(30, 30);
539+
540+
List<ParseGeoPoint> points = Arrays.asList(point1, point2, point3);
541+
query.whereWithinPolygon("key", points);
542+
543+
// We generate a state to verify the content of the builder
544+
ParseQuery.State state = query.getBuilder().build();
545+
ParseQuery.QueryConstraints queryConstraints = state.constraints();
546+
ParseQuery.KeyConstraints keyConstraints = (ParseQuery.KeyConstraints) queryConstraints.get("key");
547+
Map map = (Map) keyConstraints.get("$geoWithin");
548+
List<Object> list = (List<Object>) map.get("$polygon");
549+
assertEquals(3, list.size());
550+
assertTrue(list.contains(point1));
551+
assertTrue(list.contains(point2));
552+
assertTrue(list.contains(point3));
553+
}
554+
555+
@Test
556+
public void testWhereWithinPolygonWithPolygon() throws Exception {
557+
ParseQuery<ParseObject> query = new ParseQuery<>("Test");
558+
ParseGeoPoint point1 = new ParseGeoPoint(10, 10);
559+
ParseGeoPoint point2 = new ParseGeoPoint(20, 20);
560+
ParseGeoPoint point3 = new ParseGeoPoint(30, 30);
561+
562+
List<ParseGeoPoint> points = Arrays.asList(point1, point2, point3);
563+
query.whereWithinPolygon("key", new ParsePolygon(points));
564+
565+
// We generate a state to verify the content of the builder
566+
ParseQuery.State state = query.getBuilder().build();
567+
ParseQuery.QueryConstraints queryConstraints = state.constraints();
568+
ParseQuery.KeyConstraints keyConstraints = (ParseQuery.KeyConstraints) queryConstraints.get("key");
569+
Map map = (Map) keyConstraints.get("$geoWithin");
570+
List<Object> list = (List<Object>) map.get("$polygon");
571+
assertEquals(3, list.size());
572+
assertTrue(list.contains(point1));
573+
assertTrue(list.contains(point2));
574+
assertTrue(list.contains(point3));
575+
}
576+
533577
@Test
534578
public void testWherePolygonContains() throws Exception {
535579
ParseQuery<ParseObject> query = new ParseQuery<>("Test");

0 commit comments

Comments
 (0)