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

Source Code of org.locationtech.udig.tools.edit.commands.DifferenceFeatureCommand

/* 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.awt.Rectangle;
import java.awt.geom.NoninvertibleTransformException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.locationtech.udig.core.internal.GeometryBuilder;
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.tool.edit.internal.Messages;
import org.locationtech.udig.tools.edit.EditState;
import org.locationtech.udig.tools.edit.EditToolHandler;
import org.locationtech.udig.tools.edit.animation.GeometryOperationAnimation;
import org.locationtech.udig.tools.edit.support.EditBlackboard;
import org.locationtech.udig.tools.edit.support.EditGeom;
import org.locationtech.udig.tools.edit.support.IsBusyStateProvider;
import org.locationtech.udig.tools.edit.support.Point;
import org.locationtech.udig.tools.edit.support.PrimitiveShape;
import org.locationtech.udig.tools.edit.support.PrimitiveShapeIterator;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.filter.IllegalFilterException;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.spatial.BBOX;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.MathTransform;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;

/**
* Splits a feature based on the current shape in the handler.
* <p>
* After the command the current shape will be set to null and
* the edit blackboard will be cleared.
*
* @author jones
* @since 1.1.0
*/
public class DifferenceFeatureCommand extends AbstractCommand implements UndoableMapCommand {

    private EditToolHandler     handler;
    private PrimitiveShape      shape;
    private EditState           state;
    private ILayer              layer;
    private ArrayList<EditGeom> geoms;
    private EditState           endState;
    private UndoableComposite   writeCommand;
    private boolean             addedEndVertex = false;

    /**
     * @param handler
     */
    public DifferenceFeatureCommand( EditToolHandler handler, EditState endState ) {
        this.handler = handler;
        this.layer = handler.getEditLayer();
        this.endState = endState;
    }

    @SuppressWarnings("unchecked")
    public void run( IProgressMonitor monitor ) throws Exception {
        monitor.beginTask(Messages.DifferenceFeatureCommand_runTaskMessage, 10);
        monitor.worked(1);
        this.state = handler.getCurrentState();
        this.shape = handler.getCurrentShape();
        handler.setCurrentShape(null);
        List<UndoableMapCommand> commands = new ArrayList<UndoableMapCommand>();

        //check that start point is same as end point
        Point startPoint = shape.getPoint(0);
        if (!startPoint.equals(shape.getPoint(shape.getNumPoints() - 1))) {
            addedEndVertex = true;
            shape.getEditBlackboard().addPoint(startPoint.getX(), startPoint.getY(), shape);
        }
        GeometryOperationAnimation indicator = new GeometryOperationAnimation(
                PrimitiveShapeIterator.getPathIterator(shape).toShape(), new IsBusyStateProvider(
                        handler));
        try {
            AnimationUpdater.runTimer(handler.getContext().getMapDisplay(), indicator);
            handler.setCurrentState(EditState.BUSY);

            if (writeCommand == null) {
                EditBlackboard editBlackboard = handler.getEditBlackboard(layer);
                this.geoms = new ArrayList<EditGeom>(editBlackboard.getGeoms());
                geoms.remove(shape.getEditGeom());

                editBlackboard.clear();

                FeatureCollection<SimpleFeatureType, SimpleFeature>  features = getFeatures(monitor);
                if( features == null ){                   
                    return; // did not hit anything
                }
                try {
                    List<Geometry> geoms = new ArrayList<Geometry>();
                    geoms.add(createReferenceGeom());
                   
                    SimpleFeature first = runDifferenceOp(features.features(), geoms);
                   
                    if (first == null)
                        return;
                   
                    createAddFeatureCommands(commands, geoms, first);
                } finally {
                    monitor.worked(2);
                }
                this.writeCommand = new UndoableComposite(commands);
            }
            writeCommand.setMap(getMap());
            handler.setCurrentState(EditState.COMMITTING);
            writeCommand.execute(new SubProgressMonitor(monitor, 5));
        } finally {
            indicator.setValid(false);
            handler.setCurrentState(endState);
            monitor.done();
        }
    }

    @SuppressWarnings("unchecked")
    private void createAddFeatureCommands( List<UndoableMapCommand> commands, List<Geometry> geoms, SimpleFeature first ) throws IllegalAttributeException {
        SimpleFeatureType featureType = first.getFeatureType();
        if ((geoms.size() > 1 && !featureType.getGeometryDescriptor().getType().getBinding()
                .isAssignableFrom(MultiPolygon.class))
                || !featureType.getGeometryDescriptor().getType().getBinding().isAssignableFrom(
                        MultiPolygon.class)) {
            for( Geometry geom : geoms ) {
                SimpleFeature newFeature = SimpleFeatureBuilder.copy(first);
                newFeature.setDefaultGeometry(geom);
                commands.add(handler.getContext().getEditFactory()
                        .createAddFeatureCommand(newFeature, layer));
            }
        } else {
            SimpleFeature newFeature = SimpleFeatureBuilder.copy(first);
            GeometryFactory factory = new GeometryFactory();

            newFeature.setDefaultGeometry(factory.createMultiPolygon(geoms
                    .toArray(new Polygon[geoms.size()])));
            commands.add(handler.getContext().getEditFactory().createAddFeatureCommand(
                    newFeature, layer));
        }
    }

    /**
     * Collect the provided geometries into a single geometry.
     *
     * @param geometryCollection
     * @return A single geometry which is the union of the provided geometryCollection
     */
    static Geometry combineIntoOneGeometry( Collection<Geometry> geometryCollection ){
        //GeometryFactory factory = FactoryFinder.getGeometryFactory( null );
        GeometryFactory factory = new GeometryFactory();
       
      Geometry combined = factory.buildGeometry( geometryCollection );
        return combined.union();
    }
   
    /**
     * @param iter
     * @param geoms the geometry to remove the features in iter from.  IE the geometries that will be diffed.  Is
     * also the list of resulting geometries.
     * @return
     */
    public static SimpleFeature runDifferenceOp( FeatureIterator<SimpleFeature> iter, List<Geometry> geoms ) {
      Geometry createdGeometry = combineIntoOneGeometry( geoms );     
      Geometry differenceGeometry = createdGeometry;
      SimpleFeature first=null;
      try {

          Set<Geometry> featureGeoms = new HashSet<Geometry>();
          while( iter.hasNext() ) {
              SimpleFeature f = iter.next();
             
              if (first == null){
                  first = f;
              }
              Geometry featureGeometry = (Geometry) f.getDefaultGeometry();
              featureGeoms.add( featureGeometry );
          }
          Geometry existingGeometry = combineIntoOneGeometry( featureGeoms );
          if( existingGeometry!=null ){
              differenceGeometry = createdGeometry.difference( existingGeometry );
          }
        } finally{
            if( iter!=null )
                iter.close();
        }
        geoms.clear();
        for( int i=0; i<differenceGeometry.getNumGeometries(); i++){
          geoms.add( differenceGeometry.getGeometryN(i) );
        }
        return first;
    }

    /**
     * Grab some features from the layer using shape bounds.
     *
     * @param monitor
     * @return
     * @throws IOException
     * @throws NoninvertibleTransformException
     * @throws IllegalFilterException
     */
    private FeatureCollection<SimpleFeatureType, SimpleFeature>  getFeatures(IProgressMonitor monitor) throws IOException, NoninvertibleTransformException, IllegalFilterException {
        FeatureSource<SimpleFeatureType, SimpleFeature> source =layer.getResource(FeatureSource.class, new SubProgressMonitor(monitor,2));
        SimpleFeatureType schema = layer.getSchema();
        Rectangle bounds = shape.getBounds();
        double[] toTransform = new double[]{bounds.getMinX(), bounds.getMinY(),
                bounds.getMaxX(), bounds.getMaxY()};
        handler.getContext().worldToScreenTransform().inverseTransform(toTransform, 0,
                toTransform, 0, 2);
        ReferencedEnvelope transformedBounds = new ReferencedEnvelope(toTransform[0], toTransform[2],
                toTransform[1], toTransform[3], handler.getContext().getCRS());

        FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
        ReferencedEnvelope layerBounds;
        try {
            MathTransform transform = layer.mapToLayerTransform();
            layerBounds = new ReferencedEnvelope(JTS.transform(transformedBounds, transform), layer.getCRS());
        } catch (Exception e) {
            layerBounds = transformedBounds;
        }
        String geomAttributeName = layer.getSchema().getGeometryDescriptor().getLocalName();
//        Geometry boundsAsGeom = new GeometryFactory().toGeometry(layerBounds);
//       
//        Intersects filter = filterFactory.intersects(filterFactory.literal(boundsAsGeom),  filterFactory.property(geomAttributeName));
        String srs;
        try {
            srs = CRS.lookupIdentifier(layerBounds.getCoordinateReferenceSystem(), false);
        } catch (FactoryException e) {
            // we cannot convert our request to the data CRS
            // so we cannot return any features
            ProjectPlugin.getPlugin().log(e);
            return null;
        }
        BBOX filter = filterFactory.bbox(geomAttributeName, layerBounds.getMinX(),
            layerBounds.getMinY(), layerBounds.getMaxX(), layerBounds.getMaxY(), srs);
        Query query=new DefaultQuery(schema.getName().getLocalPart(), filter);

        return source.getFeatures(query);
    }

    /**
     * @return
     */
    private Geometry createReferenceGeom() {
        LinearRing ring = GeometryBuilder.create().safeCreateGeometry(LinearRing.class,
                shape.coordArray());
        GeometryFactory fac = new GeometryFactory();
        return fac.createPolygon(ring, new LinearRing[0]);

    }
    public void rollback( IProgressMonitor monitor ) throws Exception {
        GeometryOperationAnimation indicator = new GeometryOperationAnimation(
                PrimitiveShapeIterator.getPathIterator(shape).toShape(), new IsBusyStateProvider(
                        handler));
        try {
            monitor.beginTask(Messages.DifferenceFeatureCommand_undoTaskMessage, 10);
            monitor.worked(1);

            AnimationUpdater.runTimer(handler.getContext().getMapDisplay(), indicator);

            handler.setCurrentState(EditState.BUSY);

            SubProgressMonitor submonitor = new SubProgressMonitor(monitor, 5);
            writeCommand.rollback(submonitor);
            submonitor.done();

            EditBlackboard bb = handler.getEditBlackboard(layer);
            bb.clear();
            for( EditGeom geom : geoms ) {
                addGeom(bb, geom);
            }
            PrimitiveShape shell = addGeom(bb, shape.getEditGeom()).getShell();
            handler.setCurrentShape(shell);
            if (addedEndVertex) {
                bb.removeCoordinate(shape.getNumCoords() - 1, shape
                        .getCoord(shape.getNumCoords() - 1), shell);
            }
            handler.setCurrentState(state);
        } catch (Exception e) {
            handler.setCurrentState(EditState.NONE);
            throw e;
        } finally {
            indicator.setValid(false);
            monitor.done();
        }
    }

    /**
     * @param bb
     * @param geom
     * @return
     */
    private EditGeom addGeom( EditBlackboard bb, EditGeom geom ) {
        EditGeom newGeom = bb.newGeom(geom.getFeatureIDRef().get(), geom.getShapeType());
        newGeom.setChanged(geom.isChanged());
        for( PrimitiveShape shape : geom ) {
            PrimitiveShape newShape = newGeom.getShell();
            if (shape != geom.getShell())
                newShape = newGeom.newHole();
            Coordinate[] coords = shape.coordArray();
            for( int i = 0; i < coords.length; i++ ) {
                bb.addCoordinate(coords[i], newShape);
            }
        }
        return newGeom;
    }

    public String getName() {
        return Messages.DifferenceFeatureCommand_name;
    }
}
TOP

Related Classes of org.locationtech.udig.tools.edit.commands.DifferenceFeatureCommand

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.