org.integratedmodelling.engine.geospace.utils.ThiessenLocator Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (C) 2007, 2015:
*
* - Ferdinando Villa
* - integratedmodelling.org
* - any other authors listed in @author annotations
*
* All rights reserved. This file is part of the k.LAB software suite,
* meant to enable modular, collaborative, integrated
* development of interoperable data and model components. For
* details, see http://integratedmodelling.org.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Affero General Public License
* Version 3 or any later version.
*
* This program is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* Affero General Public License for more details.
*
* You should have received a copy of the Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* The license is also available at: https://www.gnu.org/licenses/agpl.html
*******************************************************************************/
package org.integratedmodelling.engine.geospace.utils;
import java.util.ArrayList;
import java.util.List;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.collections.Pair;
import org.integratedmodelling.common.space.IGeometricShape;
import org.integratedmodelling.engine.geospace.Geospace;
import org.integratedmodelling.engine.geospace.extents.SpaceExtent;
import org.integratedmodelling.engine.geospace.literals.ShapeValue;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.triangulate.VoronoiDiagramBuilder;
/**
* An object initialized with a raster spatial scale and a set of geometric shapes whose centroids
* lie in or around that area. Will produce a set of Thiessen polygons describing the influence
* zone of each shape, cut to the area, and it will create an index so that it can be queried for
* the index of the shape selected to describe each cell in the raster.
*
* @author Ferd
*
*/
public class ThiessenLocator {
List> pairs = new ArrayList<>();
short[] index;
List objects;
/*
* this isn't null only when we have a single object to distribute. Then we use that without
* any polygons.
*/
T object = null;
public ThiessenLocator(IScale scale, List objects) {
if (scale.getSpace() == null || scale.getSpace().getGrid() == null) {
throw new KlabRuntimeException("illegal spatial extent for ThiessenLocator: only grids are supported");
}
this.objects = objects;
SpatialDisplay debug = new SpatialDisplay((SpaceExtent) scale.getSpace());
if (objects.size() == 1) {
object = objects.get(0);
} else if (objects.size() > 0) {
/*
* generate object influence polygons and associate them to the objects in the order identified.
*/
VoronoiDiagramBuilder db = new VoronoiDiagramBuilder();
ArrayList sites = new ArrayList<>();
for (IGeometricShape s : objects) {
Point point = s.getGeometry().getCentroid();
sites.add(new Coordinate(point.getX(), point.getY()));
debug.add(new ShapeValue(s.getGeometry(), Geospace.get().getDefaultCRS()));
}
db.setSites(sites);
Geometry diag = db.getDiagram(new GeometryFactory());
/*
* attribute objects to polygons
*/
int pols = 0;
for (pols = 0; pols < diag.getNumGeometries(); pols++) {
Geometry g = diag.getGeometryN(pols);
debug.add(new ShapeValue(g, Geospace.get().getDefaultCRS()), "original");
for (int s = 0; s < objects.size(); s++) {
if (g.intersects(objects.get(s).getGeometry()) && g instanceof Polygon) {
pairs.add(new Pair<>((Polygon) g, objects.get(s)));
}
}
}
/*
* build index of which object is where. Drop those that fall out of
* the context shape in the process.
*/
GeometryFactory pm = new GeometryFactory();
index = new short[(int) scale.getSpace().getMultiplicity()];
for (int i = 0; i < scale.getSpace().getMultiplicity(); i++) {
double[] xy = scale.getSpace().getGrid().getCoordinates(i);
Point point = pm.createPoint(new Coordinate(xy[0], xy[1]));
for (int j = 0; j < pairs.size(); j++) {
if (pairs.get(j).getFirst().intersects(point)) {
index[i] = (short) (j + 1);
break;
}
}
}
}
}
public T get(int offset) {
return object == null ? (index == null ? null : pairs.get(index[offset] - 1).getSecond()) : object;
}
}