Package org.locationtech.udig.tools.edit.support

Source Code of org.locationtech.udig.tools.edit.support.GeometryCreationUtil$Bag

/* 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.support;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.locationtech.udig.core.internal.GeometryBuilder;
import org.locationtech.udig.tool.edit.internal.Messages;
import org.locationtech.udig.tools.edit.EditPlugin;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.swt.widgets.Display;
import org.geotools.data.shapefile.shp.JTSUtilities;
import org.opengis.feature.type.GeometryDescriptor;

import com.vividsolutions.jts.algorithm.CGAlgorithms;
import com.vividsolutions.jts.algorithm.RobustCGAlgorithms;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;

/**
* Some helper methods for creating geometries.
*
* @author jones
* @since 1.1.0
*/
public class GeometryCreationUtil {
    /**
     * Used to hold a list of JTS Geometries associated with an EditGeom.
     * <p>
     * EditGeom is used for display and holds the feature id.
     */
    public static class Bag {
        public EditGeom geom;
        public List<Geometry> jts = new ArrayList<Geometry>();
        public Bag( EditGeom geom ) {
            this.geom = geom;
        }
    }

    /**
     * Searches an EditBlackboard and creates 1 geometry for each EditGeom in the Blackboard. Only
     * simple geoms are created. IE no MultiPolygons. That processing must come later. The way the
     * type of geometry is determined is as follows:
     * <ul>
     * <li>If the geometry has the same FID as the currentGeom then its type will be of type
     * geomToCreate.</li>
     * <li>Otherwise the ShapeType of the EditGeom will be compared to the geomAttribute and if that
     * type is legal for that attribute then that is the type of geometry that will be created</li>
     * <li>If ShapeType is UNKOWN and it does not have the same FID as the curentGeom then the
     * geomAttribute is used to determine the geometry type.</li>
     * <li>Finally if the geomType is geometry then a Polygon will be created... unless the
     * endpoints are not the same. In that case a Line will be created. Unless it is a single point.
     * </li>
     *</ul>
     *
     * @param currentGeom the shape that will be created as a geomToCreate type.
     * @param geomToCreate the type of geometry that will be created for the currentShape in the
     *        handler. Must be one of Point, LineString, LinearRing or Polygon.
     * @param geomAttribute The AttributeDescriptor of the geometry attribute that will be assist in
     *        determining the type of geometry created.
     * @param showErrors TODO
     * @return a mapping between the FeatureID of a bag of geoms that map to that id. This mapping
     *         can be used to later create complex geometries such as multigeoms.
     */
    @SuppressWarnings("unchecked")
    public static Map<String, GeometryCreationUtil.Bag> createAllGeoms( EditGeom currentGeom,
            Class geomToCreate, GeometryDescriptor geomAttribute, boolean showErrors ) {
        EditBlackboard blackboard = currentGeom.getEditBlackboard();
        List<EditGeom> editGeoms = blackboard.getGeoms();
        Map<String, GeometryCreationUtil.Bag> idToGeom = new HashMap<String, GeometryCreationUtil.Bag>();
        for( EditGeom editGeom : editGeoms ) {
            if (editGeom.isChanged()) {
                if (!idToGeom.containsKey(editGeom.getFeatureIDRef().get()))
                    idToGeom.put(editGeom.getFeatureIDRef().get(), new GeometryCreationUtil.Bag(
                            editGeom));
            }
        }
        for( EditGeom editGeom : editGeoms ) {
            if (!idToGeom.containsKey(editGeom.getFeatureIDRef().get()))
                continue; // has not been changed - skip!

            if (idToGeom.containsKey(editGeom.getFeatureIDRef().get())) {
                if (editGeom.getShell().getNumPoints() > 0) {
                    Bag bag = idToGeom.get(editGeom.getFeatureIDRef().get());
                    Class geometryType = determineGeometryType(currentGeom, editGeom, geomToCreate,
                            geomAttribute);
                    Geometry createGeom = createGeom(geometryType, editGeom.getShell(), showErrors);
                    bag.jts.add(createGeom);
                }
            }
        }
        return idToGeom;
    }

    /**
     * The way the type of geometry is determined is as follows:
     * <ul>
     * <li>If the geometry has the same FID as the currentGeom then its type will be of type
     * geomToCreate.</li>
     * <li>Otherwise the ShapeType of the EditGeom will be compared to the geomAttribute and if that
     * type is legal for that attribute then that is the type of geometry that will be created</li>
     * <li>If ShapeType is UNKOWN and it does not have the same FID as the curentGeom then the
     * geomAttribute is used to determine the geometry type.</li>
     * <li>Finally if the geomType is geometry then a Polygon will be created... unless the
     * endpoints are not the same. In that case a Line will be created. Unless it is a single point.
     * </li>
     *</ul>
     *
     * @param currentGeom the handler's current Geom. If == editGeom then geomToCreate will be
     *        returned
     * @param editGeom the editGeom that will be used to create a geometry.
     * @param geomToCreate A default value to use if nothing else can be decided.
     * @param geomAttribute The geometry attribute type of the feature that will be set using the
     *        created geometry.
     * @return
     */
    public static Class determineGeometryType( EditGeom currentGeom, EditGeom editGeom,
            Class geomToCreate, GeometryDescriptor geomAttribute ) {
        if ((editGeom.getFeatureIDRef().get() == null && currentGeom.getFeatureIDRef().get() == null)
                || editGeom.getFeatureIDRef().get().equals(currentGeom.getFeatureIDRef().get()))
            return geomToCreate;
        ShapeType attributeDefinedType = ShapeType.valueOf(geomAttribute.getType().getBinding());
        ShapeType typeToSwitchOn;
        if (attributeDefinedType != editGeom.getShapeType()
                && attributeDefinedType != ShapeType.UNKNOWN
                || editGeom.getShapeType() == ShapeType.UNKNOWN) {
            typeToSwitchOn = attributeDefinedType;
        } else {
            typeToSwitchOn = editGeom.getShapeType();
        }

        switch( typeToSwitchOn ) {
        case LINE:
            return LineString.class;
        case POINT:
            return Point.class;
        case POLYGON:
            return Polygon.class;
        case UNKNOWN:
            if (geomAttribute.getType().getBinding() == Geometry.class
                    || geomAttribute.getType().getBinding() == GeometryCollection.class) {
                PrimitiveShape shell = editGeom.getShell();
                if (shell.getNumPoints() == 1)
                    return Point.class;
                else if (shell.getPoint(0).equals(shell.getPoint(shell.getNumPoints() - 1))
                        && shell.getNumCoords() != 2)
                    return Polygon.class;
                else
                    return LineString.class;
            }
        }
        return null;
    }

    /**
     * Creates a geometry for a primitive shape.
     *
     * @param geomToCreate the type of geometry to create. Must be one of Point, LineString,
     *        LinearRing or Polygon.
     * @param shape the shape to use. If type is Polygon the shapes EditGeom is used.
     * @param showError TODO
     * @return A geometry of type geomToCreate
     */
    public static <T extends Geometry> T createGeom( Class<T> geomToCreate, PrimitiveShape shape,
            boolean showError ) {
        Geometry geom;
        if (geomToCreate == Polygon.class) {
            geom = createPolygon(shape.getEditGeom());
        } else if (geomToCreate == LinearRing.class) {
            geom = GeometryBuilder.create()
                    .safeCreateGeometry(LinearRing.class, shape.coordArray());
        } else if (geomToCreate == LineString.class) {
            geom = GeometryBuilder.create()
                    .safeCreateGeometry(LineString.class, shape.coordArray());
        } else {
            geom = GeometryBuilder.create().safeCreateGeometry(Point.class, shape.coordArray());
        }

        if (!geom.isValid()) {
            final Display display = Display.getDefault();
            if (showError) {
                display.asyncExec(new Runnable(){
                    public void run() {
                        IStatus errorStatus = new Status(IStatus.ERROR,
                                EditPlugin.ID, IStatus.ERROR,
                                Messages.GeometryCreationUtil_errorMsg, null);
                        ErrorDialog
                                .openError(
                                        display.getActiveShell(),
                                        Messages.GeometryCreationUtil_errorTitle,
                                        Messages.GeometryCreationUtil_errorMsg,
                                        errorStatus);
                    }
                });
                throw new IllegalStateException("Geometry constructed from EditGeom: " //$NON-NLS-1$
                        + shape.getEditGeom().getFeatureIDRef().get()
                        + " resulted in an invalid geometry"); //$NON-NLS-1$
            }
        }
        return geomToCreate.cast(geom);
    }

    public final static RobustCGAlgorithms cga = new RobustCGAlgorithms();

    /**
     * Create JTS Geometry from the provided EditGeom.
     *
     * @param currentGeom
     * @return Polygon
     */
    public static Polygon createPolygon( EditGeom currentGeom ) {
        Coordinate[] shellCoords = currentGeom.getShell().coordArray();
        LinearRing shell = GeometryBuilder.create().safeCreateLinearRing(shellCoords);

        try {
            if (CGAlgorithms.isCCW(shellCoords)) {
                shell = JTSUtilities.reverseRing(shell);
            }
        } catch (Exception e) {
            EditPlugin.log("Not a critical problem, just an FYI", e); //$NON-NLS-1$
        }
        List<LinearRing> currentHoles = new ArrayList<LinearRing>();
       
        for( PrimitiveShape shape : currentGeom.getHoles() ) {
            Coordinate[] coordArray = shape.coordArray();

            if (coordArray.length == 0) {
                continue;
            }
            LinearRing hole = GeometryBuilder.create().safeCreateLinearRing(coordArray);
            // FIXME test when the hole has only one coordinate.
            if (!(coordArray.length <= 2) && !CGAlgorithms.isCCW(coordArray)) {
                hole = JTSUtilities.reverseRing((LinearRing) hole);
            }
            currentHoles.add(hole);
        }
        GeometryFactory factory = new GeometryFactory();
        LinearRing[] holes = currentHoles.toArray(new LinearRing[currentHoles.size()]);
        return factory.createPolygon(shell, holes);
    }

    /**
     * Creates a GeometryCollection if the schemaDeclaredType is a subclass of GeometryCollection.
     * Otherwise it will just return the first of the list, or null if we are removing content.
     *
     * @param geoms list of goemtries that will be added to the GeometryCollection.
     * @param schemaDeclaredType The type that the resulting geometry has to be compatible with
     * @return geometry can be assigned to schemaDeclaredType, or null geoms is empty
     */
    public static Geometry ceateGeometryCollection( List<Geometry> geoms,
            Class<Geometry> schemaDeclaredType ) {

        if (geoms.isEmpty()) {
            return null;
        }

        if (schemaDeclaredType.isAssignableFrom(geoms.get(0).getClass()) && geoms.size() == 1)
            return geoms.get(0);

        if (!GeometryCollection.class.isAssignableFrom(schemaDeclaredType)
                && !schemaDeclaredType.isAssignableFrom(GeometryCollection.class))
            return geoms.get(0);

        Geometry geom;
        GeometryFactory factory = new GeometryFactory();
        Class< ? extends Geometry> geomType = geoms.get(0).getClass();
        if (geomType == Polygon.class) {
            geom = factory.createMultiPolygon(geoms.toArray(new Polygon[geoms.size()]));
        } else if (geomType == LinearRing.class) {
            geom = factory.createMultiLineString(geoms.toArray(new LineString[geoms.size()]));
        } else if (geomType == LineString.class) {
            geom = factory.createMultiLineString(geoms.toArray(new LineString[geoms.size()]));
        } else {
            geom = factory.createMultiPoint(geoms.toArray(new Point[geoms.size()]));
        }
        return geom;
    }

}
TOP

Related Classes of org.locationtech.udig.tools.edit.support.GeometryCreationUtil$Bag

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.