package org.openlca.geo.parameter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.geotools.data.DataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.opengis.feature.simple.SimpleFeature;
import org.openlca.geo.kml.FeatureType;
import org.openlca.geo.kml.KmlFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Calculates the parameter values for a given feature from intersecting shapes.
*/
class FeatureCalculator {
private Logger log = LoggerFactory.getLogger(getClass());
private DataStore dataStore;
private Map<String, Double> defaults;
public FeatureCalculator(DataStore dataStore, Map<String, Double> defaults) {
this.dataStore = dataStore;
this.defaults = defaults;
}
public Map<String, Double> calculate(KmlFeature feature,
List<String> parameters, Map<String, Double> shares) {
FeatureType type = feature.type;
if (type == null
|| type == FeatureType.EMPTY
|| type == FeatureType.MULTI_GEOMETRY) {
log.warn("cannot calculate parameter values for type {}", type);
return Collections.emptyMap();
}
return calculate(parameters, shares);
}
private Map<String, Double> calculate(List<String> parameters,
Map<String, Double> shares) {
try (SimpleFeatureIterator iterator = getIterator()) {
Map<SimpleFeature, Double> _shares = new HashMap<>();
while (iterator.hasNext()) {
SimpleFeature shape = iterator.next();
if (shares.containsKey(shape.getID()))
_shares.put(shape, shares.get(shape.getID()));
}
return fetchValues(_shares, parameters);
} catch (Exception e) {
log.error("failed to fetch parameters for feature", e);
return null;
}
}
private Map<String, Double> fetchValues(Map<SimpleFeature, Double> shares,
List<String> params) {
Map<String, Double> parameterResults = new HashMap<>();
for (String param : params) {
ValSet vals = new ValSet(param);
for (Entry<SimpleFeature, Double> entry : shares.entrySet()) {
Double val = getValue(entry.getKey(), param);
Double share = entry.getValue();
vals.add(val, share);
}
parameterResults.put(param, vals.getValue());
}
return parameterResults;
}
private Double getValue(SimpleFeature shape, String param) {
if (shape == null || param == null)
return null;
Object obj = shape.getAttribute(param);
if (!(obj instanceof Number))
return null;
Number number = (Number) obj;
double val = number.doubleValue();
return Val.isNaN(val) ? null : val;
}
private SimpleFeatureIterator getIterator() throws Exception {
String typeName = dataStore.getTypeNames()[0];
SimpleFeatureCollection collection = dataStore.getFeatureSource(
typeName).getFeatures();
return collection.features();
}
/**
* Set of values and shares of a parameter. A value of null means 'not
* available'.
*/
private class ValSet {
String parameter;
ArrayList<Double> values = new ArrayList<>();
ArrayList<Double> shares = new ArrayList<>();
int nanCount = 0;
ValSet(String parameter) {
this.parameter = parameter;
}
void add(Double value, Double share) {
values.add(value);
shares.add(share);
if (value == null) {
nanCount++;
}
}
double getValue() {
if (nanCount == values.size()) {
Double v = defaults.get(parameter);
return v == null ? 0 : v;
}
double shareSum = 0;
double total = 0;
for (int i = 0; i < values.size(); i++) {
Double val = values.get(i);
if (val == null)
continue;
Double s = shares.get(i);
double share = s == null ? 0 : s;
total += val * share;
shareSum += share;
}
if (nanCount == 0)
return total;
return shareSum == 0 ? 0 : total / shareSum;
}
}
}