All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.integratedmodelling.engine.geospace.extents.SpatialIndex Maven / Gradle / Ivy

The newest version!
package org.integratedmodelling.engine.geospace.extents;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.geotools.geometry.jts.ReferencedEnvelope;
import org.integratedmodelling.api.modelling.IScale.Locator;
import org.integratedmodelling.api.space.IShape.Type;
import org.integratedmodelling.api.space.ISpatialExtent;
import org.integratedmodelling.api.space.ISpatialIndex;
import org.integratedmodelling.collections.Pair;
import org.integratedmodelling.common.space.IGeometricShape;
import org.integratedmodelling.common.vocabulary.GeoNS;
import org.integratedmodelling.engine.geospace.Geospace;
import org.integratedmodelling.engine.geospace.literals.ShapeValue;

import com.infomatiq.jsi.Rectangle;
import com.infomatiq.jsi.rtree.RTree;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.operation.distance.DistanceOp;

import gnu.trove.procedure.TIntProcedure;

public class SpatialIndex implements ISpatialIndex {

    RTree                       rtree  = new RTree();
    Map        ids    = new HashMap<>();
    Map        names  = new HashMap<>();
    Map exts   = new HashMap<>();
    ISpatialExtent              extent;
    int                         nextId = 1;

    public SpatialIndex(ISpatialExtent extent) {
        this.extent = extent;
        this.rtree.init(new Properties());
    }

    @Override
    public void add(ISpatialExtent extent, String name) {
        exts.put(name, extent);
        rtree.add(getRectangle(extent), getId(name));
    }

    private int getId(String name) {
        Integer ret = ids.get(name);
        if (ret == null) {
            ret = nextId++;
            ids.put(name, ret);
            names.put(ret, name);
        }
        return ret;
    }

    private Rectangle getRectangle(ISpatialExtent extent) {
        Geometry shape = ((IGeometricShape) extent.getShape()).getStandardizedGeometry();
        ReferencedEnvelope env = new ShapeValue(shape, Geospace.get().getDefaultCRS()).getEnvelope();
        return new Rectangle((float) env.getMinX(), (float) env.getMinY(), (float) env
                .getMaxX(), (float) env.getMaxY());
    }

    @Override
    public double distanceToNearestObjectFrom(Locator position) {
        return distanceToNearestObjectFrom(extent.locate(position));
    }

    @Override
    public double distanceToNearestObjectFrom(int offset) {

        double[] xy = getCoordinates(offset);
        int id = new FeatureFinder(xy).find();
        return getDistance(xy, exts.get(names.get(id)));
    }

    private double getDistance(double[] xy, ISpatialExtent extent) {

        if (extent == null) {
            return Double.NaN;
        }

        /*
         * we're on the feature, distance is 0. Intersector does check for actual point on
         * actual feature.
         */
        if (!new FeatureIntersector(xy).find().isEmpty()) {
            return 0;
        }

        if (extent.getShape().getGeometryType() == Type.POINT) {
            Point point = (Point) ((IGeometricShape) extent.getShape()).getGeometry();
            return GeoNS
                    .getDistance(new Coordinate(xy[0], xy[1]), new Coordinate(point.getX(), point.getY()))
                    * 1000.0;
        }

        /*
         * complicated intersection finding between extent and extent boundary. Let JTS help.
         */
        Coordinate[] coords = DistanceOp.nearestPoints(ShapeValue
                .makePoint(xy[0], xy[1]), ((IGeometricShape) extent.getShape()).getGeometry());

        if (coords == null || coords.length < 2) {
            return Double.NaN;
        }

        return GeoNS.getDistance(coords[0], coords[1]) * 1000.0;
    }

    @Override
    public Collection> getNearest(Locator position, int maxResults) {
        // TODO Auto-generated method stub
        return null;
    }

    double[] getCoordinates(int ofs) {
        ISpatialExtent loc = extent.getExtent(ofs);
        ShapeValue sh = new ShapeValue(((IGeometricShape) loc.getShape()).getStandardizedGeometry(), Geospace
                .get().getDefaultCRS());
        Point point = ((Point) sh.getCentroid().getGeometry());
        return new double[] { point.getX(), point.getY() };
    }

    @Override
    public ISpatialExtent getExtent() {
        return extent;
    }

    @Override
    public double distanceBetween(int offset, String objectId) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public boolean contains(String objectId) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public double distanceBetween(Locator position, String objectId) {
        // TODO Auto-generated method stub
        return 0;
    }

    class FeatureFinder {

        int                             idx;
        private com.infomatiq.jsi.Point point;

        FeatureFinder(double[] xy) {
            this.point = new com.infomatiq.jsi.Point((float) xy[0], (float) xy[1]);
        }

        int find() {

            rtree.nearest(point, new TIntProcedure() {

                @Override
                public boolean execute(int arg0) {
                    idx = arg0;
                    return true;
                }
            }, Float.POSITIVE_INFINITY);

            return idx;
        }
    }

    class FeatureIntersector {

        Set                    idx = new HashSet<>();
        private com.infomatiq.jsi.Point point;

        FeatureIntersector(double[] xy) {
            this.point = new com.infomatiq.jsi.Point((float) xy[0], (float) xy[1]);
        }

        Set find() {

            rtree.intersects(new Rectangle(point.x, point.y, point.x, point.y), new TIntProcedure() {

                @Override
                public boolean execute(int arg0) {
                    if (ShapeValue.makePoint(point.x, point.y)
                            .overlaps(((IGeometricShape) exts.get(names.get(arg0)).getShape())
                                    .getGeometry())) {
                        idx.add(arg0);
                    }
                    return true;
                }
            });

            return idx;
        }
    }

    @Override
    public int size() {
        return ids.size();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy