Package org.locationtech.udig.tools.edit.commands

Source Code of org.locationtech.udig.tools.edit.commands.SelectFeaturesAtPointCommand$IntersectTestingIterator

/* uDig - User Friendly Desktop Internet GIS client
* http://udig.refractions.net
* (C) 2004, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*/
package org.locationtech.udig.tools.edit.commands;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

import org.locationtech.udig.project.ILayer;
import org.locationtech.udig.project.command.AbstractCommand;
import org.locationtech.udig.project.command.UndoableComposite;
import org.locationtech.udig.project.command.UndoableMapCommand;
import org.locationtech.udig.project.internal.ProjectPlugin;
import org.locationtech.udig.project.ui.AnimationUpdater;
import org.locationtech.udig.project.ui.render.displayAdapter.MapMouseEvent;
import org.locationtech.udig.project.ui.tool.IToolContext;
import org.locationtech.udig.tool.edit.internal.Messages;
import org.locationtech.udig.tools.edit.EditPlugin;
import org.locationtech.udig.tools.edit.EditToolHandler;
import org.locationtech.udig.tools.edit.support.EditBlackboard;

import org.eclipse.core.runtime.IProgressMonitor;
import org.geotools.data.FeatureSource;
import org.geotools.data.FeatureStore;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;

/**
* Searches a layer for an intersection between a mouse click and a feature and selects the features
* if found.
* <p>
* This command makes use of its own small framework of:
* <ul>
* <li>{@link SelectionParameter}
* <li>{@link SelectionStratagy}
* <li>{@link DeselectionStratagy}
* </ul>
* @author Jesse
* @since 1.1.0
*/
public class SelectFeaturesAtPointCommand extends AbstractCommand implements UndoableMapCommand {

    // The size of the box that is searched.  This is a 7x7 box of pixels. 
    private static final int SEARCH_SIZE = 7;
    private EditToolHandler handler;
    private final Set<Class< ? extends Geometry>> acceptableClasses = new HashSet<Class< ? extends Geometry>>();
    private MapMouseEvent event;
    private Class<? extends Filter> filterType;

    private UndoableMapCommand command;
    private final SelectionParameter parameters;
    // boolean indicating that transformation problems have been reported so don't want to fill logs with the same
    // report
    boolean warned = false;

    public SelectFeaturesAtPointCommand( SelectionParameter parameterObject ) {
        this.parameters = parameterObject;
        this.handler = parameterObject.handler;
        this.event = parameterObject.event;
        this.acceptableClasses.addAll(Arrays.asList(parameterObject.acceptableClasses));

        this.filterType = parameterObject.filterType;
    }

    public void run( IProgressMonitor monitor ) throws Exception {
        if (command != null) {
            // indicates a redo
            command.run(monitor);
        } else {
            IToolContext context = handler.getContext();
            ILayer editLayer = handler.getEditLayer();

            EditBlackboard editBlackboard = handler.getEditBlackboard(editLayer);
            editBlackboard.startBatchingEvents();
            BlockingSelectionAnim animation = new BlockingSelectionAnim(event.x, event.y);
            AnimationUpdater.runTimer(context.getMapDisplay(), animation);
            FeatureIterator<SimpleFeature> iter = getFeatureIterator();
            try {

                if (iter.hasNext()) {
                    runSelectionStrategies(monitor, iter);
                } else {
                    runDeselectionStrategies(monitor);
                }

                setAndRun(monitor, command);
      } finally {
        try {
          if (iter != null) {
            iter.close();
          }
        } finally {
          if (animation != null) {
            animation.setValid(false);
            animation = null;
          }
        }
        editBlackboard.fireBatchedEvents();
      }
        }
    }

    /**
     * Gets a feature iterator on the results of a BBox query.   BBox is used because intersects occasionally throws a
     * Side-conflict error so it is not a good query. 
     *
     * However maybe a better way is to try intersects then if that fails do a bbox?
     * For now we do bbox and test it with intersects
     *
     * @return Pair of an option containing the first feature if it exists, and an iterator with the rest
     */
    private FeatureIterator<SimpleFeature> getFeatureIterator() throws IOException {
        ILayer editLayer = parameters.handler.getEditLayer();
        FeatureStore<SimpleFeatureType, SimpleFeature> store = getResource(editLayer);
       
        // transforms the bbox to the layer crs
        ReferencedEnvelope bbox = handler.getContext().getBoundingBox(event.getPoint(), SEARCH_SIZE);
        try {
          bbox = bbox.transform(parameters.handler.getEditLayer().getCRS(), true);
        } catch (TransformException e) {
          logTransformationWarning(e);
        } catch (FactoryException e) {
          logTransformationWarning(e);
        }
        // creates a bbox filter using the bbox in the layer crs and grabs the features present in this bbox
        Filter createBBoxFilter = createBBoxFilter(bbox, editLayer, filterType);
        FeatureCollection<SimpleFeatureType, SimpleFeature> collection = store.getFeatures(createBBoxFilter);

        FeatureIterator<SimpleFeature> reader = new IntersectTestingIterator(bbox, collection.features());
       
        return reader;
    }

  @SuppressWarnings("unchecked")
  private FeatureStore<SimpleFeatureType, SimpleFeature> getResource(
      ILayer editLayer) throws IOException {
    FeatureStore<SimpleFeatureType, SimpleFeature> store = editLayer.getResource(FeatureStore.class, null);
    return store;
  }

    private void runDeselectionStrategies( IProgressMonitor monitor ) {

        List<DeselectionStrategy> strategies = parameters.deselectionStrategies;
        UndoableComposite compositeCommand = new UndoableComposite();
        for( DeselectionStrategy strategy : strategies ) {
            strategy.run(monitor, parameters, compositeCommand);
        }
        this.command = compositeCommand;

    }

    private void runSelectionStrategies( IProgressMonitor monitor, FeatureIterator<SimpleFeature> reader ) {
        List<SelectionStrategy> strategies = parameters.selectionStrategies;
        UndoableComposite compositeCommand = new UndoableComposite();
        compositeCommand.setName(Messages.SelectGeometryCommand_name);
       
        SimpleFeature firstFeature = reader.next();
        for( SelectionStrategy selectionStrategy : strategies ) {
          selectionStrategy.run(monitor, compositeCommand, parameters, firstFeature,
              true);
        }
       
       
        while (reader.hasNext()){
          SimpleFeature nextFeature = reader.next();
            for( SelectionStrategy selectionStrategy : strategies ) {
              selectionStrategy.run(monitor, compositeCommand, parameters, nextFeature,
                  false);
            }
        }

        this.command = compositeCommand;
    }

    private void logTransformationWarning( Exception e ) {
        if(!warned){
            EditPlugin.log("Error transforming bbox from viewportmodel CRS to LayerCRS", e); //$NON-NLS-1$
        }
    }

    /**
     * Creates A geometry filter for the given layer.
     *
     * @param boundingBox in the same crs as the viewport model.
     * @return a Geometry filter in the correct CRS or null if an exception occurs.
     */
    public Filter createBBoxFilter( ReferencedEnvelope boundingBox, ILayer layer, Class<? extends Filter> filterType ) {
        FilterFactory2 factory = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
        if (!layer.hasResource(FeatureSource.class))
            return Filter.EXCLUDE;
        try {

            SimpleFeatureType schema = layer.getSchema();
            Name geom = getGeometryAttDescriptor(schema).getName();
           
            Filter bboxFilter =factory.bbox(factory.property(geom), boundingBox);
           

            return bboxFilter;
        } catch (Exception e) {
            ProjectPlugin.getPlugin().log(e);
            return Filter.EXCLUDE;
        }
    }

    private void setAndRun( IProgressMonitor monitor, UndoableMapCommand undoableComposite )
            throws Exception {
        undoableComposite.setMap(getMap());
        undoableComposite.run(monitor);
    }

    public String getName() {
        return Messages.SelectGeometryCommand_name;
    }

    public void rollback( IProgressMonitor monitor ) throws Exception {
        command.rollback(monitor);
    }

    private static GeometryDescriptor getGeometryAttDescriptor( SimpleFeatureType schema ) {
        return schema.getGeometryDescriptor();
    }
   
    private static class IntersectTestingIterator implements FeatureIterator<SimpleFeature>{
      private final FeatureIterator<SimpleFeature> wrappedIter;
      private final ReferencedEnvelope bbox;
      private SimpleFeature next;
     
    public IntersectTestingIterator(ReferencedEnvelope bbox, FeatureIterator<SimpleFeature> wrapped) {
      this.wrappedIter = wrapped;
      this.bbox=bbox;
    }

    public void close() {
      wrappedIter.close();
    }

    public boolean hasNext() {
      if( next!=null ){
        return true;
      }
     
      while (wrappedIter.hasNext() && next==null ){
        SimpleFeature feature=wrappedIter.next();
        if(intersects(feature)){
          next=feature;
        }
      }
     
      // TODO Auto-generated method stub
      return next!=null;
    }

      private boolean intersects( SimpleFeature feature ) {
          GeometryDescriptor geomDescriptor = getGeometryAttDescriptor(feature.getFeatureType());
         
          Geometry bboxGeom = new GeometryFactory().toGeometry(bbox);

          Geometry geom = (Geometry) feature.getAttribute(geomDescriptor.getName());

          try{
              return geom.intersects(bboxGeom);
          }catch (Exception e) {
              // ok so exception happened during intersection.  This usually means geometry is a little crazy
              // what to do?...
              EditPlugin.log("Can't do intersection so I'm assuming they intersect", e); //$NON-NLS-1$
              return false;
          }
      }
    public SimpleFeature next() throws NoSuchElementException {
      if(!hasNext()){
        throw new NoSuchElementException();
      }
      SimpleFeature f = next;
      next=null;
      return f;
    }
     
    }
}
TOP

Related Classes of org.locationtech.udig.tools.edit.commands.SelectFeaturesAtPointCommand$IntersectTestingIterator

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.