SearchByLocationCommand implements CommandHasRequest<SearchByLocationRequest, SearchByLocationResponse> { @Override public void execute(SearchByLocationRequest request, SearchByLocationResponse response) throws Exception { if (null == request.getLayerIds()) { throw new GeomajasException(ExceptionCode.PARAMETER_MISSING, "layerIds"); } String crsCode = request.getCrs(); if (null == crsCode) { throw new GeomajasException(ExceptionCode.PARAMETER_MISSING, "crs"); } Geometry location = converter.toInternal(request.getLocation()); int queryType = request.getQueryType(); double ratio = request.getRatio(); int searchType = request.getSearchType(); Crs crs = geoService.getCrs2(request.getCrs()); Geometry geometry = location; if (request.getBuffer() > 0) { geometry = location.buffer(request.getBuffer()); } log.debug("search by location " + geometry); for (String clientLayerId : request.getLayerIds()) { String serverLayerId = request.getServerLayerId(clientLayerId); if (null == serverLayerId) { throw new GeomajasException(ExceptionCode.PARAMETER_MISSING, "serverLayerId for clientLayerId " + clientLayerId); } if (securityContext.isLayerVisible(serverLayerId)) { VectorLayer vectorLayer = configurationService.getVectorLayer(serverLayerId); if (vectorLayer != null) { String geomName = vectorLayer.getLayerInfo().getFeatureInfo().getGeometryType().getName(); Geometry layerGeometry = geoService.transform(geometry, crs, layerService.getCrs(vectorLayer)); log.trace("on layer " + serverLayerId + " use " + layerGeometry); Filter f = null; switch (queryType) { case SearchByLocationRequest.QUERY_INTERSECTS: f = filterCreator.createIntersectsFilter(layerGeometry, geomName); break; case SearchByLocationRequest.QUERY_CONTAINS: f = filterCreator.createContainsFilter(layerGeometry, geomName); break; case SearchByLocationRequest.QUERY_TOUCHES: f = filterCreator.createTouchesFilter(layerGeometry, geomName); break; case SearchByLocationRequest.QUERY_WITHIN: f = filterCreator.createWithinFilter(layerGeometry, geomName); break; default: throw new IllegalArgumentException("Unknown query type " + queryType); } if (null != request.getFilter(clientLayerId)) { if (null == f) { f = filterCreator.parseFilter(request.getFilter(clientLayerId)); } else { f = filterCreator.createAndFilter( filterCreator.parseFilter(request.getFilter(clientLayerId)), f); } } if (null != request.getFilter()) { if (null == f) { f = filterCreator.parseFilter(request.getFilter()); } else { f = filterCreator.createAndFilter(filterCreator.parseFilter(request.getFilter()), f); } } List<InternalFeature> temp = layerService.getFeatures(serverLayerId, crs, f, null, request .getFeatureIncludes()); if (temp.size() > 0) { List<Feature> features = new ArrayList<Feature>(); if (queryType == SearchByLocationRequest.QUERY_INTERSECTS && ratio >= 0 && ratio < 1) { for (InternalFeature feature : temp) { double minimalOverlap = feature.getGeometry().getArea() * ratio; Geometry overlap = geometry.intersection(feature.getGeometry()); double effectiveOverlap = overlap.getArea(); if (minimalOverlap <= effectiveOverlap) { log.trace("found " + feature); Feature dto = converter.toDto(feature); dto.setCrs(crsCode); features.add(dto); } } } else { for (InternalFeature feature : temp) { log.trace("found " + feature); Feature dto = converter.toDto(feature); dto.setCrs(crsCode); features.add(dto); } } if (features.size() > 0) { response.addLayer(clientLayerId, features); if (searchType == SearchByLocationRequest.SEARCH_FIRST_LAYER) { break; } } } } } } }  @Override SearchByLocationRequest getEmptyCommandRequest(); @Override SearchByLocationResponse getEmptyCommandResponse(); @Override void execute(SearchByLocationRequest request, SearchByLocationResponse response);  }
@Test public void intersectCountriesOnEquator() throws Exception { SearchByLocationRequest request = new SearchByLocationRequest(); request.setCrs("EPSG:4326"); request.setQueryType(SearchByLocationRequest.QUERY_INTERSECTS); request.setSearchType(SearchByLocationRequest.SEARCH_ALL_LAYERS); request.setLayerIds(new String[] {LAYER_ID}); GeometryFactory factory = new GeometryFactory(); LineString equator = factory.createLineString(new Coordinate[] {new Coordinate(0, 0), new Coordinate(-180, 180)}); request.setLocation(converter.toDto(equator)); SearchByLocationResponse response = (SearchByLocationResponse) dispatcher.execute( SearchByLocationRequest.COMMAND, request, null, "en"); Assert.assertFalse(response.isError()); List<Feature> features = response.getFeatureMap().get(LAYER_ID); Assert.assertNotNull(features); Assert.assertEquals(4, features.size()); List<String> actual = new ArrayList<String>(); for (Feature feature : features) { actual.add(feature.getLabel()); } Assert.assertTrue(actual.contains("Country 4")); Assert.assertTrue(actual.contains("Country 3")); Assert.assertTrue(actual.contains("Country 2")); Assert.assertTrue(actual.contains("Country 1")); }
@Test public void intersectCountriesOnEquatorWithFilter() throws Exception { SearchByLocationRequest request = new SearchByLocationRequest(); request.setCrs("EPSG:4326"); request.setQueryType(SearchByLocationRequest.QUERY_INTERSECTS); request.setSearchType(SearchByLocationRequest.SEARCH_ALL_LAYERS); request.setLayerIds(new String[] {LAYER_ID}); request.setFilter("region='Region 1'"); GeometryFactory factory = new GeometryFactory(); LineString equator = factory.createLineString(new Coordinate[] {new Coordinate(0, 0), new Coordinate(-180, 180)}); request.setLocation(converter.toDto(equator)); SearchByLocationResponse response = (SearchByLocationResponse) dispatcher.execute( SearchByLocationRequest.COMMAND, request, null, "en"); Assert.assertFalse(response.isError()); List<Feature> features = response.getFeatureMap().get(LAYER_ID); Assert.assertNotNull(features); Assert.assertEquals(2, features.size()); List<String> actual = new ArrayList<String>(); for (Feature feature : features) { actual.add(feature.getLabel()); } Assert.assertTrue(actual.contains("Country 2")); Assert.assertTrue(actual.contains("Country 1")); }
@Test public void intersectCountriesOnEquatorWithLayerFilter() throws Exception { SearchByLocationRequest request = new SearchByLocationRequest(); request.setCrs("EPSG:4326"); request.setQueryType(SearchByLocationRequest.QUERY_INTERSECTS); request.setSearchType(SearchByLocationRequest.SEARCH_ALL_LAYERS); request.setLayerIds(new String[] {LAYER_ID}); request.setFilter(LAYER_ID, "region='Region 1'"); GeometryFactory factory = new GeometryFactory(); LineString equator = factory.createLineString(new Coordinate[] {new Coordinate(0, 0), new Coordinate(-180, 180)}); request.setLocation(converter.toDto(equator)); SearchByLocationResponse response = (SearchByLocationResponse) dispatcher.execute( SearchByLocationRequest.COMMAND, request, null, "en"); Assert.assertFalse(response.isError()); List<Feature> features = response.getFeatureMap().get(LAYER_ID); Assert.assertNotNull(features); Assert.assertEquals(2, features.size()); List<String> actual = new ArrayList<String>(); for (Feature feature : features) { actual.add(feature.getLabel()); } Assert.assertTrue(actual.contains("Country 2")); Assert.assertTrue(actual.contains("Country 1")); }
@Test public void intersectCountriesOnEquatorWithLayerFilters() throws Exception { SearchByLocationRequest request = new SearchByLocationRequest(); request.setCrs("EPSG:4326"); request.setQueryType(SearchByLocationRequest.QUERY_INTERSECTS); request.setSearchType(SearchByLocationRequest.SEARCH_ALL_LAYERS); final String region1ResultTag = "countries layer region 1"; final String region2ResultTag = "countries layer region 2"; request.addLayerWithFilter(region1ResultTag, LAYER_ID, "region='Region 1'"); request.addLayerWithFilter(region2ResultTag, LAYER_ID, "region='Region 2'"); GeometryFactory factory = new GeometryFactory(); LineString equator = factory.createLineString(new Coordinate[] {new Coordinate(0, 0), new Coordinate(-180, 180)}); request.setLocation(converter.toDto(equator)); String requestToString = request.toString(); Assert.assertTrue(requestToString.length() > 24); SearchByLocationResponse response = (SearchByLocationResponse) dispatcher.execute( SearchByLocationRequest.COMMAND, request, null, "en"); Assert.assertFalse(response.isError()); List<Feature> features; List<String> actual; features = response.getFeatureMap().get(region1ResultTag); Assert.assertNotNull(features); Assert.assertEquals(2, features.size()); actual = new ArrayList<String>(); for (Feature feature : features) { actual.add(feature.getLabel()); } Assert.assertTrue(actual.contains("Country 2")); Assert.assertTrue(actual.contains("Country 1")); features = response.getFeatureMap().get(region2ResultTag); Assert.assertNotNull(features); Assert.assertEquals(2, features.size()); actual = new ArrayList<String>(); for (Feature feature : features) { actual.add(feature.getLabel()); } Assert.assertTrue(actual.contains("Country 4")); }
@Test public void firstLayer() throws Exception { SearchByLocationRequest request = new SearchByLocationRequest(); request.setCrs("EPSG:4326"); request.setQueryType(SearchByLocationRequest.QUERY_INTERSECTS); request.setSearchType(SearchByLocationRequest.SEARCH_FIRST_LAYER); final String region1ResultTag = "countries layer region 1"; final String region2ResultTag = "countries layer region 2"; request.addLayerWithFilter(region1ResultTag, LAYER_ID, "region='Region 1'"); request.addLayerWithFilter(region2ResultTag, LAYER_ID, "region='Region 2'"); request.setLocation(GeometryService.toPolygon(new Bbox(-180, -90, 360, 180))); SearchByLocationResponse response = (SearchByLocationResponse) dispatcher.execute( SearchByLocationRequest.COMMAND, request, null, "en"); Assert.assertFalse(response.isError()); Assert.assertEquals(1, response.getFeatureMap().size()); Assert.assertNotNull(response.getFeatureMap().get(region1ResultTag)); }
@Test public void intersect50percentOverlapExactly() throws Exception { SearchByLocationRequest request = new SearchByLocationRequest(); request.setCrs("EPSG:4326"); request.setQueryType(SearchByLocationRequest.QUERY_INTERSECTS); request.setSearchType(SearchByLocationRequest.SEARCH_ALL_LAYERS); request.setRatio(0.5f); request.setLayerIds(new String[] {LAYER_ID}); GeometryFactory factory = new GeometryFactory(); LinearRing half1 = factory.createLinearRing(new Coordinate[] {new Coordinate(0, 0), new Coordinate(1, 0), new Coordinate(1, 0.5), new Coordinate(0, 0.5), new Coordinate(0, 0)}); Polygon polygon = factory.createPolygon(half1, null); request.setLocation(converter.toDto(polygon)); SearchByLocationResponse response = (SearchByLocationResponse) dispatcher.execute( SearchByLocationRequest.COMMAND, request, null, "en"); Assert.assertFalse(response.isError()); List<Feature> features = response.getFeatureMap().get(LAYER_ID); Assert.assertNotNull(features); List<String> actual = new ArrayList<String>(); for (Feature feature : features) { actual.add(feature.getLabel()); } List<String> expected = new ArrayList<String>(); expected.add("Country 1"); Assert.assertEquals(expected, actual); }
@Test public void intersect50percentOverlapAlmost() throws Exception { SearchByLocationRequest request = new SearchByLocationRequest(); request.setCrs("EPSG:4326"); request.setQueryType(SearchByLocationRequest.QUERY_INTERSECTS); request.setSearchType(SearchByLocationRequest.SEARCH_ALL_LAYERS); request.setRatio(0.5f); request.setLayerIds(new String[] {LAYER_ID}); GeometryFactory factory = new GeometryFactory(); LinearRing half1 = factory.createLinearRing(new Coordinate[] {new Coordinate(0, 0), new Coordinate(1, 0), new Coordinate(1, 0.49), new Coordinate(0, 0.49), new Coordinate(0, 0)}); Polygon polygon = factory.createPolygon(half1, null); request.setLocation(converter.toDto(polygon)); SearchByLocationResponse response = (SearchByLocationResponse) dispatcher.execute( SearchByLocationRequest.COMMAND, request, null, "en"); List<Feature> features = response.getFeatureMap().get(LAYER_ID); Assert.assertNull(features); }