Package org.geomajas.command.feature

Source Code of org.geomajas.command.feature.SearchByLocationCommand

/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2011 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.command.feature;

import java.util.ArrayList;
import java.util.List;

import org.geomajas.annotation.Api;
import org.geomajas.command.Command;
import org.geomajas.command.dto.SearchByLocationRequest;
import org.geomajas.command.dto.SearchByLocationResponse;
import org.geomajas.geometry.Crs;
import org.geomajas.global.ExceptionCode;
import org.geomajas.global.GeomajasException;
import org.geomajas.layer.VectorLayer;
import org.geomajas.layer.VectorLayerService;
import org.geomajas.layer.feature.Feature;
import org.geomajas.layer.feature.InternalFeature;
import org.geomajas.security.SecurityContext;
import org.geomajas.service.ConfigurationService;
import org.geomajas.service.DtoConverterService;
import org.geomajas.service.FilterService;
import org.geomajas.service.GeoService;
import org.opengis.filter.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.vividsolutions.jts.geom.Geometry;

/**
* <p>
* Execute a search for features by location. The location can be any type of geometry. Although this will mostly be a
* coordinate, it is possible to search using a Polygon or LineString as location. The command only expects the location
* to be described using the map's coordinate system. Also, if a buffer is specified, this buffer will be added to the
* location geometry before executing the search.
* </p>
* <p>
* In addition to the location, it is also possible to describe what kind of geometric query to use (supported are:
* intersects, contains, touches and within) and in case of the "intersects" query, it is even possible to describe what
* ratio of intersection is required (number between 0 and 1). The default query will also be an intersection. For
* example, if queryType = 1 (intersects) and ratio = 0.7, then only features whose geometry lies 70% within the given
* location will be accepted.
* </p>
* <p>
* Last but not least, it is required that at least one layer-ID is given to search in. If multiple layers are given, an
* extra parameter comes into play: searchType. This searchType specifies whether to search features in all given
* layers, to to start searching from the first layer, and stop once features are found (can be in the first layer, or
* in the second, ...).
* </p>
* <p>
* It will go over all given layers (provided they're vector layers), and fetch the features, using the location
* geometry and the query type. In case the query type is "intersects", the overlapping ratio is also checked. The
* resulting list of features is added to the command result so it can be send back to the client.
* </p>
*
* @author Pieter De Graef
* @since 1.6.0
*/
@Api
@Component()
@Transactional(readOnly = true, rollbackFor = { Exception.class })
public class SearchByLocationCommand implements Command<SearchByLocationRequest, SearchByLocationResponse> {

  private final Logger log = LoggerFactory.getLogger(SearchByLocationCommand.class);

  @Autowired
  private ConfigurationService configurationService;

  @Autowired
  private GeoService geoService;

  @Autowired
  private DtoConverterService converter;

  @Autowired
  private FilterService filterCreator;

  @Autowired
  private VectorLayerService layerService;

  @Autowired
  private SecurityContext securityContext;

  // -------------------------------------------------------------------------
  // Command implementation:
  // -------------------------------------------------------------------------

  /**
   * The command's execution method. It will go over all given layers (provided they're vector layers), and fetch the
   * features, using the location geometry and the query type. In case the query type is "intersects", the overlapping
   * ratio is also checked. The resulting list of features is added to the command result so it can be send back to
   * the client.
   */
  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");
    }
    String[] layerIds = request.getLayerIds();
    Geometry location = converter.toInternal(request.getLocation());
    int queryType = request.getQueryType();
    double ratio = request.getRatio();
    int searchType = request.getSearchType();
    Crs crs = geoService.getCrs2(request.getCrs());

    // Check if a buffer should be added around the location:
    Geometry geometry = location;
    if (request.getBuffer() > 0) {
      geometry = location.buffer(request.getBuffer());
    }
    log.debug("search by location " + geometry);

    if (layerIds != null && layerIds.length > 0) {
      for (String layerId : layerIds) {
        if (securityContext.isLayerVisible(layerId)) {
          VectorLayer vectorLayer = configurationService.getVectorLayer(layerId);
          if (vectorLayer != null) {
            String geomName = vectorLayer.getLayerInfo().getFeatureInfo().getGeometryType().getName();

            // Transform geometry to layer CRS:
            Geometry layerGeometry = geoService.transform(geometry, crs, vectorLayer.getCrs());
            log.trace("on layer " + layerId + " use " + layerGeometry);

            // Create the correct Filter object:
            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;
            }
            //Set the per layer filter
            if (null != request.getFilter(layerId)) {
              if (null == f) {
                f = filterCreator.parseFilter(request.getFilter(layerId));
              } else {
                f = filterCreator.createAndFilter(
                    filterCreator.parseFilter(request.getFilter(layerId)), f);
              }
            }
            //Set the global filter
            if (null != request.getFilter()) {
              if (null == f) {
                f = filterCreator.parseFilter(request.getFilter());
              } else {
                f = filterCreator.createAndFilter(filterCreator.parseFilter(request.getFilter()), f);
              }
            }

            // Get the features:
            List<InternalFeature> temp = layerService.getFeatures(layerId, crs, f, null, request
                .getFeatureIncludes());
            if (temp.size() > 0) {
              List<Feature> features = new ArrayList<Feature>();

              // Calculate overlap ratio in case of intersects:
              if (queryType == SearchByLocationRequest.QUERY_INTERSECTS && ratio >= 0 && ratio < 1) {
                for (InternalFeature feature : temp) {
                  double minimalOverlap = feature.getGeometry().getArea() * ratio;
                  Geometry overlap = location.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);
                }
              }

              // features.size can again be 0... so check:
              if (features.size() > 0) {
                // We have a response for this layer!
                response.addLayer(layerId, features);

                // If searchType == SEARCH_FIRST_LAYER, we should search no further:
                if (searchType == SearchByLocationRequest.SEARCH_FIRST_LAYER) {
                  break;
                }
              }
            }
          }
        }
      }
    }
  }

  public SearchByLocationResponse getEmptyCommandResponse() {
    return new SearchByLocationResponse();
  }
}
TOP

Related Classes of org.geomajas.command.feature.SearchByLocationCommand

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.