org.integratedmodelling.engine.geospace.contextualizers.PointSampler 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.contextualizers;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.knowledge.IExpression;
import org.integratedmodelling.api.knowledge.IObservation;
import org.integratedmodelling.api.modelling.IActiveSubject;
import org.integratedmodelling.api.modelling.IExtent;
import org.integratedmodelling.api.modelling.IModel;
import org.integratedmodelling.api.modelling.IObservableSemantics;
import org.integratedmodelling.api.modelling.IObserver;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.IState;
import org.integratedmodelling.api.modelling.ISubject;
import org.integratedmodelling.api.modelling.IValueResolver;
import org.integratedmodelling.api.modelling.contextualization.ISubjectInstantiator;
import org.integratedmodelling.api.modelling.resolution.IResolutionScope;
import org.integratedmodelling.api.modelling.scheduling.ITransition;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.monitoring.Messages;
import org.integratedmodelling.api.project.IProject;
import org.integratedmodelling.api.services.annotations.Prototype;
import org.integratedmodelling.api.space.IGrid;
import org.integratedmodelling.api.space.ISpatialExtent;
import org.integratedmodelling.common.beans.ModelArtifact;
import org.integratedmodelling.common.beans.responses.LocalExportResponse;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.kim.expr.GroovyExpression;
import org.integratedmodelling.common.knowledge.Observation;
import org.integratedmodelling.common.knowledge.ObservationGroup;
import org.integratedmodelling.common.model.Models;
import org.integratedmodelling.common.states.States;
import org.integratedmodelling.common.utils.NameGenerator;
import org.integratedmodelling.common.vocabulary.NS;
import org.integratedmodelling.common.vocabulary.ObservableSemantics;
import org.integratedmodelling.engine.geospace.Geospace;
import org.integratedmodelling.engine.geospace.coverage.vector.AbstractVectorCoverage.VectorOutput;
import org.integratedmodelling.engine.geospace.literals.ShapeValue;
import org.integratedmodelling.engine.modelling.runtime.DirectObservation;
import org.integratedmodelling.engine.modelling.runtime.DirectObservation.ArtifactGenerator;
import org.integratedmodelling.engine.visualization.VisualizationFactory;
import org.integratedmodelling.engine.modelling.runtime.Scale;
import org.integratedmodelling.engine.modelling.runtime.Subject;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabUnsupportedOperationException;
import com.google.common.io.Files;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
@Prototype(
id = "gis.sample.points",
published = true,
args = {
"# select",
Prototype.EXPRESSION,
"# fraction",
Prototype.FLOAT,
"# allow-nodata",
Prototype.BOOLEAN,
"# name-prefix",
Prototype.TEXT
},
returnTypes = { NS.SUBJECT_INSTANTIATOR },
argDescriptions = {
"boolean expression to compute whether each point belongs to a feature",
"select the specified fraction of the source-state input",
"create point states with no-data values (default: false)",
"prefix string for name of point features (default: 'p')"
})
public class PointSampler implements ISubjectInstantiator, IValueResolver {
IExpression selector;
IProject project;
IScale scale;
IGrid grid;
private IConcept type;
GeometryFactory gfact = new GeometryFactory();
private IActiveSubject context;
private String prefix = "p";
boolean allowNodata = false;
private IMonitor monitor;
double selectFraction = .01;
public PointSampler() {
}
public PointSampler(IScale scale, IMonitor monitor, boolean computeConvexHull,
boolean ignoreHoles,
boolean createPointFeatures) {
this.scale = scale;
this.monitor = monitor;
}
@Override
public boolean canDispose() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setContext(Map parameters, IModel model, IProject project) {
if (parameters.containsKey("select")) {
this.selector = new GroovyExpression(parameters.get("select")
.toString(), model);
}
if (parameters.containsKey("fraction")) {
this.selectFraction = ((Number) parameters.get("fraction")).doubleValue();
}
if (parameters.containsKey("allow-nodata")) {
this.allowNodata = ((Boolean) parameters.get("allow-nodata"));
}
if (parameters.containsKey("name-prefix")) {
this.prefix = parameters.get("name-prefix").toString();
}
this.project = project;
}
@Override
public void initialize(IActiveSubject context, IResolutionScope resolutionContext, IModel model, Map expectedInputs, Map expectedOutputs, IMonitor monitor)
throws KlabException {
this.scale = context.getScale();
if (!(scale.isSpatiallyDistributed() && scale.getSpace().getGrid() != null
&& ((scale
.isTemporallyDistributed() && scale.getExtentCount() == 2)
|| (!scale
.isTemporallyDistributed()
&& scale.getExtentCount() == 1)))) {
throw new KlabUnsupportedOperationException("feature extraction only works on purely spatial[/temporal] extents");
}
this.grid = this.scale.getSpace().getGrid();
this.type = model.getObservable().getType();
this.context = context;
this.monitor = monitor;
}
@Override
public Map createSubjects(IActiveSubject context, ITransition transition, Map inputs)
throws KlabException {
if (transition != null) {
// TODO - update the states in the points
return null;
}
Map ret = createPoints(inputs, transition);
if (ret.size() > 0) {
/*
* add the corresponding model to the process
*/
String artifactId = NS.getDisplayName(this.type) + " instantiator";
((DirectObservation) context).addOutputModel(NS.getDisplayName(this.type)
+ " instantiator", new ArtifactGenerator() {
@Override
public LocalExportResponse generateArtifact() {
LocalExportResponse ret = new LocalExportResponse();
ret.setModel(true);
String filename = prefix + "data" + NameGenerator.shortUUID()
+ ".shp";
// TODO export .shp fileset
File tmp = Files.createTempDir();
tmp = new File(tmp + File.separator + filename);
ObservationGroup objs = new ObservationGroup(type, context);
objs.collectObservations();
Object output = null;
try {
output = VisualizationFactory.get().persist(objs, tmp);
} catch (KlabException e) {
// do nothing
}
if (output instanceof VectorOutput) {
String modelStatement = Models
.generateObjectModelSource(type, "vector(file=\"data/"
+ filename + "\")", ((VectorOutput)output).getAttributes(), "name");
ret.setModelStatement(modelStatement);
for (File f : ((VectorOutput)output).getFiles()) {
ret.getFiles().add(f.toString());
}
ret.setRelativeExportPath("data");
}
return ret;
}
});
monitor.send(new ModelArtifact(artifactId, "model", ((Observation) context)
.getInternalId()));
}
return ret;
}
private Map createPoints(Map inputs, ITransition transition)
throws KlabException {
Map ret = new HashMap<>();
int skipped = 0;
int done = 0;
Random random = new Random();
for (int n : scale.getIndex(transition)) {
if (!Double.isNaN(selectFraction)) {
if (!scale.isCovered(n) || random.nextFloat() > selectFraction) {
continue;
}
Map values = new HashMap<>();
boolean skip = false;
for (String s : inputs.keySet()) {
Object value = States.get(inputs.get(s), n);
if (!allowNodata && (value == null
|| (value instanceof Number
&& Double.isNaN(((Number) value).doubleValue())))) {
skipped++;
skip = true;
break;
}
values.put(s, value);
}
if (skip) {
skipped++;
continue;
}
int spaceOffset = scale.getExtentOffset(scale.getSpace(), n);
double[] xy = grid.getCoordinates(spaceOffset);
Point point = gfact.createPoint(new Coordinate(xy[0], xy[1]));
done++;
String sid = prefix + done;
ShapeValue shape = new ShapeValue(point, Geospace
.getCRSFromID(scale.getSpace().getCRSCode()));
ISubject subject = context
.newSubject(new ObservableSemantics(type), getScale(shape
.asExtent(), context), sid, KLAB
.p(NS.PART_OF));
for (String s : values.keySet()) {
IState state = ((Subject) subject)
.getState(transition == null
? new ObservableSemantics((ObservableSemantics) inputs
.get(s)
.getObservable().getSemantics())
: inputs.get(s).getObservable().getSemantics());
States.set(state, values.get(s), transition == null ? 0
: transition.getTimeIndex() + 1);
}
ret.put(sid, subject);
}
}
if (skipped > 0) {
monitor.info("skipped " + skipped
+ " features not meeting requirements", Messages.INFOCLASS_MODEL);
}
return ret;
}
private IScale getScale(ISpatialExtent extent, ISubject context)
throws KlabException {
List exts = new ArrayList<>();
for (IExtent e : context.getScale()) {
if (e instanceof ISpatialExtent) {
exts.add(extent);
} else {
exts.add(e);
}
}
return new Scale(exts.toArray(new IExtent[exts.size()]));
}
}