ingo@1115: /*
ingo@1115: * Copyright (c) 2010 by Intevation GmbH
ingo@1115: *
ingo@1115: * This program is free software under the LGPL (>=v2.1)
ingo@1115: * Read the file LGPL.txt coming with the software for details
ingo@1115: * or visit http://www.gnu.org/licenses/ if it does not exist.
ingo@1115: */
ingo@1115:
tim@352: package de.intevation.gnv.state.profile.horizontal;
tim@352:
ingo@1034: import au.com.bytecode.opencsv.CSVWriter;
ingo@1034:
sascha@519: import com.vividsolutions.jts.geom.Coordinate;
tim@352:
tim@352: import de.intevation.artifactdatabase.Config;
sascha@357:
sascha@519: import de.intevation.artifacts.CallContext;
sascha@519:
tim@352: import de.intevation.gnv.artifacts.cache.CacheFactory;
sascha@357:
sascha@519: import de.intevation.gnv.artifacts.context.GNVArtifactContext;
sascha@519:
sascha@519: import de.intevation.gnv.chart.Chart;
sascha@519: import de.intevation.gnv.chart.ChartLabels;
sascha@519: import de.intevation.gnv.chart.HorizontalCrossProfileChart;
sascha@519:
ingo@1034: import de.intevation.gnv.exports.DefaultProfile;
ingo@1034: import de.intevation.gnv.exports.Export;
ingo@1034: import de.intevation.gnv.exports.StringArrayKey;
ingo@1034:
ingo@423: import de.intevation.gnv.geobackend.base.DefaultResult;
ingo@423: import de.intevation.gnv.geobackend.base.DefaultResultDescriptor;
ingo@423: import de.intevation.gnv.geobackend.base.Result;
ingo@423: import de.intevation.gnv.geobackend.base.ResultDescriptor;
sascha@519:
ingo@423: import de.intevation.gnv.geobackend.base.query.QueryExecutor;
ingo@423: import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
sascha@519:
ingo@423: import de.intevation.gnv.geobackend.base.query.exception.QueryException;
sascha@519:
ingo@423: import de.intevation.gnv.math.Interpolation2D;
ingo@423: import de.intevation.gnv.math.LinearMetrics;
ingo@423: import de.intevation.gnv.math.Point2d;
ingo@365:
sascha@440: import de.intevation.gnv.state.InputData;
ingo@1034: import de.intevation.gnv.state.describedata.KeyValueDescibeData;
ingo@1034: import de.intevation.gnv.state.exception.StateException;
sascha@440:
ingo@423: import de.intevation.gnv.utils.DistanceCalculator;
sascha@519: import de.intevation.gnv.utils.StringUtils;
ingo@420: import de.intevation.gnv.utils.WKTUtils;
sascha@439:
ingo@1034: import java.io.IOException;
ingo@1034: import java.io.OutputStream;
ingo@1034: import java.io.OutputStreamWriter;
ingo@1034: import java.io.UnsupportedEncodingException;
ingo@1034:
ingo@1034: import java.text.DateFormat;
ingo@1034: import java.text.ParseException;
ingo@1034: import java.text.SimpleDateFormat;
ingo@1034:
sascha@519: import java.util.ArrayList;
sascha@519: import java.util.Arrays;
sascha@519: import java.util.Collection;
ingo@1034: import java.util.Date;
ingo@1034: import java.util.HashMap;
ingo@1034: import java.util.Iterator;
sascha@519: import java.util.List;
sascha@519: import java.util.Locale;
ingo@1034: import java.util.Map;
sascha@443:
sascha@519: import org.apache.log4j.Logger;
sascha@357:
ingo@365: import org.jfree.chart.ChartTheme;
ingo@365:
sascha@519: import org.w3c.dom.Node;
ingo@423:
tim@352: /**
ingo@811: * This OutputState
is used for 'Horizontalschnitt' products.
sascha@835: *
sascha@780: * @author Tim Englich
sascha@780: * @author Ingo Weinzierl
sascha@780: * @author Sascha L. Teichmann
tim@352: */
sascha@528: public class HorizontalProfileMeshCrossOutputState
ingo@856: extends HorizontalProfileMeshOutputState
sascha@528: {
tim@352:
ingo@1034: /**
ingo@1034: * Constant field which defines the source format of a given datetime.
ingo@1034: */
ingo@1034: public static final String SRC_FORMAT = "yyyy.MM.dd HH:mm:ss";
ingo@1034:
ingo@1034: /**
ingo@1034: * Constant field which defines the target format of a given datetime.
ingo@1034: */
ingo@1034: public static final String DEST_FORMAT = "yyyy-MM-dd HH:mm";
ingo@1034:
ingo@1034: /**
ingo@1034: * Source format.
ingo@1034: */
ingo@1034: public static DateFormat srcFormat = new SimpleDateFormat(SRC_FORMAT);
ingo@1034:
ingo@1034: /**
ingo@1034: * Target format.
ingo@1034: */
ingo@1034: public static DateFormat destFormat = new SimpleDateFormat(DEST_FORMAT);
ingo@1034:
ingo@1034:
ingo@1034: /**
ingo@1034: * This class represents an exporter used for exporting 'Horizontale
ingo@1034: * Schnittprofile' as odv.
ingo@1034: *
ingo@1034: * @author Ingo Weinzierl
ingo@1034: */
ingo@1034: public class HorizontalProfileMeshCrossODVExporter
ingo@1034: implements Export
ingo@1034: {
ingo@1034: private ResultDescriptor rd;
ingo@1034:
ingo@1034: private Collection parameters;
ingo@1034:
ingo@1034: private int dateIdx;
ingo@1034: private int paramIdx;
ingo@1034: private int depthIdx;
ingo@1034: private int valueIdx;
ingo@1034: private int shpIdx;
ingo@1034:
ingo@1034: public HorizontalProfileMeshCrossODVExporter(Collection parameters) {
ingo@1034: this.parameters = parameters;
ingo@1034: }
ingo@1034:
ingo@1034: public void create(
ingo@1034: Profile profile,
ingo@1034: OutputStream outputStream,
ingo@1034: Collection result)
ingo@1034: throws
ingo@1034: IOException,
ingo@1034: UnsupportedEncodingException,
ingo@1034: StateException
ingo@1034: {
ingo@1034: CSVWriter writer = new CSVWriter(
ingo@1034: new OutputStreamWriter(outputStream, profile.getEncoding()),
ingo@1034: profile.getSeparator(),
ingo@1034: profile.getQuoteCharacter(),
ingo@1034: profile.getEscapeCharacter());
ingo@1034:
ingo@1034: writeData(profile, writer, result);
ingo@1034:
ingo@1034: writer.close();
ingo@1034: }
ingo@1034:
ingo@1034: protected void writeData(
ingo@1034: Profile profile,
ingo@1034: CSVWriter writer,
ingo@1034: Collection results)
ingo@1034: {
ingo@1034: log.debug("Put " + results.size() + " elements into odv export.");
ingo@1034:
ingo@1034: // just write header into odv export
ingo@1034: String[] header = profile.getHeader();
ingo@1034: ArrayList headerList = new ArrayList();
ingo@1034: for (int i= 0; i < header.length; i++){
ingo@1034: headerList.add(header[i]);
ingo@1034: }
ingo@1034:
ingo@1034: ArrayList paramids = new ArrayList();
ingo@1034:
ingo@1034: Map> aggregatedRows =
ingo@1034: new HashMap>();
ingo@1034:
ingo@1034: for (Result res: results) {
ingo@1034: if (rd == null) {
ingo@1034: rd = res.getResultDescriptor();
ingo@1034: paramIdx = rd.getColumnIndex("GROUP1");
ingo@1034: depthIdx = rd.getColumnIndex("GROUP2");
ingo@1034: dateIdx = rd.getColumnIndex("GROUP3");
ingo@1034: shpIdx = rd.getColumnIndex("SHAPE");
ingo@1034: valueIdx = rd.getColumnIndex("YORDINATE");
ingo@1034: }
ingo@1034:
ingo@1034: String[] row = generateRow(res);
ingo@1034: StringArrayKey key = new StringArrayKey(row);
ingo@1034: String parameterValue = res.getString(valueIdx);
ingo@1034: String parameterID = res.getString(paramIdx);
ingo@1034:
ingo@1034: if (!paramids.contains(parameterID)) {
ingo@1034: paramids.add(parameterID);
ingo@1034: headerList.add(findParamTitle(parameters, parameterID));
ingo@1034: headerList.add("QF");
ingo@1034: }
ingo@1034:
ingo@1034: Map aggregatedRow = aggregatedRows.get(key);
ingo@1034: if (aggregatedRow != null) {
ingo@1034: aggregatedRow.put(parameterID, parameterValue);
ingo@1034: }
ingo@1034: else{
ingo@1034: Map params = new HashMap();
ingo@1034: params.put(parameterID, parameterValue);
ingo@1034: aggregatedRows.put(key, params);
ingo@1034: }
ingo@1034: }
ingo@1034:
ingo@1034: if (header != null){
ingo@1034: writer.writeNext(headerList.toArray(header));
ingo@1034: }
ingo@1034:
ingo@1034: Iterator rows = aggregatedRows.keySet().iterator();
ingo@1034: int idx = 1;
ingo@1034: while (rows.hasNext()){
ingo@1034: StringArrayKey row = rows.next();
ingo@1034: Map params = aggregatedRows.get(row);
ingo@1034:
ingo@1034: ArrayList rowList = new ArrayList();
ingo@1034: String[] rowArray = row.getValue();
ingo@1034: for (int i= 0; i < rowArray.length; i++){
ingo@1034: String value = rowArray[i];
ingo@1034: if (value != null && value.equals("GNV_STATION")) {
ingo@1034: value += "_" + idx++;
ingo@1034: }
ingo@1034: rowList.add(value);
ingo@1034: }
ingo@1034: for (int i = 0; i < paramids.size();i++){
ingo@1034: String key = paramids.get(i);
ingo@1034: String value = params.get(key);
ingo@1034: if (value == null){
ingo@1034: value = "";
ingo@1034: }
ingo@1034: rowList.add(value);
ingo@1034: rowList.add("1");
ingo@1034: }
ingo@1034: log.debug("Write new line into odv export.");
ingo@1034: writer.writeNext(rowList.toArray(rowArray));
ingo@1034: }
ingo@1034: }
ingo@1034:
ingo@1034: protected String[] generateRow(Result res) {
ingo@1034: Date tmpDate = null;
ingo@1034: String dateTmp = res.getString(dateIdx);
ingo@1034: try {
ingo@1034: tmpDate = srcFormat.parse(dateTmp);
ingo@1034: }
ingo@1034: catch (ParseException pe) {
ingo@1034: log.warn(pe,pe);
ingo@1034: }
ingo@1034:
ingo@1034: String shapeTmp = res.getString(shpIdx);
ingo@1034: Coordinate p = WKTUtils.toCoordinate(shapeTmp);
ingo@1034:
ingo@1034: String cruise = "GNV_EXPORT";
ingo@1034: String station = "GNV_STATION";
ingo@1034: String type = "*";
ingo@1034: String date = tmpDate != null
ingo@1034: ? destFormat.format(tmpDate)
ingo@1034: : dateTmp;
ingo@1034: String lon = "" + p.x;
ingo@1034: String lat = "" + p.y;
ingo@1034: String botDepth = "0";
ingo@1034: String depth = res.getString(depthIdx);
ingo@1034:
ingo@1034: return new String[] {
ingo@1034: cruise, station, type, date, lon, lat, botDepth, depth
ingo@1034: };
ingo@1034: }
ingo@1034:
ingo@1034: /**
ingo@1034: * This method is used to search specific value coresponding to its key
ingo@1034: * id
and return its description.
ingo@1034: *
ingo@1034: * @param values Collection of parameters.
ingo@1034: * @param id Key used to find the value.
ingo@1034: *
ingo@1034: * @return Description of searched value.
ingo@1034: */
ingo@1034: protected String findParamTitle(Collection values, String id) {
ingo@1034: if (values != null){
ingo@1034: Iterator it = values.iterator();
ingo@1034: while (it.hasNext()) {
ingo@1034: KeyValueDescibeData data = (KeyValueDescibeData) it.next();
ingo@1034:
ingo@1034: if (id.equals(data.getKey()))
ingo@1034: return data.getValue();
ingo@1034: }
ingo@1034: }
ingo@1034: return "";
ingo@1034: }
ingo@1034: } // HorizontalProfileMeshCrossODVExporter
ingo@1034:
ingo@1034:
sascha@528: public static final boolean USE_INDEX_BUFFER =
sascha@528: Boolean.getBoolean("gnv.horizontal.profile.mesh.cross.index.buffer");
sascha@528:
tim@352: private static final long serialVersionUID = 2205958041745637263L;
sascha@778:
tim@352: /**
tim@352: * the logger, used to log exceptions and additonaly information
tim@352: */
sascha@528: private static Logger log = Logger.getLogger(
sascha@528: HorizontalProfileMeshCrossOutputState.class);
tim@352:
tim@352: private String ijkQueryID = null;
sascha@778:
tim@352: /**
tim@352: * Constructor
tim@352: */
tim@352: public HorizontalProfileMeshCrossOutputState() {
tim@352: super();
tim@352: }
sascha@778:
ingo@811:
tim@352: @Override
tim@352: public void setup(Node configuration) {
tim@352: super.setup(configuration);
tim@352: this.ijkQueryID = Config.getStringXPath(configuration,"queryID-ijk");
sascha@778:
tim@352: }
tim@352:
ingo@365:
ingo@811: /**
ingo@811: * This method creates a chart and returns it.
ingo@811: *
ingo@811: * @param chartLables Labels used to decorate the chart.
ingo@811: * @param theme The theme used to adjust the look of the chart.
ingo@811: * @param parameters A collection with parameters this chart contains.
ingo@811: * @param measurements A collection with measurement this chart contains.
ingo@811: * @param dates A collection with dates this chart contains.
ingo@811: * @param result The data collection used to be displayed in this chart.
ingo@811: * @param locale The Locale used to determine the language.
ingo@811: * @param uuid The uuid of the current artifact.
ingo@811: * @param linesVisible A boolean property to determine the visibility of
ingo@811: * lines connecting two points in a chart (not used in this chart type).
ingo@811: * @param shapesVisible A boolean property to determine the visiblity of
ingo@811: * datapoints in this chart (not used in this chart type).
ingo@811: * @param callContext The CallContext object.
ingo@811: * @return a HorizontalCrossProfileChart
.
ingo@811: */
ingo@365: @Override
ingo@365: protected Chart getChart(
ingo@365: ChartLabels chartLables,
ingo@365: ChartTheme theme,
ingo@365: Collection parameters,
ingo@365: Collection measurements,
ingo@365: Collection dates,
ingo@429: Object result,
ingo@365: Locale locale,
ingo@365: String uuid,
ingo@365: boolean linesVisible,
sascha@439: boolean shapesVisible,
sascha@439: CallContext callContext
ingo@365: ) {
ingo@365: Chart chart = null;
ingo@365: if (CACHE_CHART) {
ingo@365: log.info("Try to get horizontalprofilemeshcross chart from cache.");
sascha@439: chart = (Chart) getChartFromCache(uuid, callContext);
ingo@365: }
ingo@365:
ingo@365: if (chart != null)
ingo@365: return chart;
ingo@365:
ingo@365: log.info("Chart not in cache yet.");
ingo@365: chart = new HorizontalCrossProfileChart(
ingo@365: chartLables,
ingo@365: theme,
ingo@365: parameters,
ingo@365: measurements,
ingo@365: dates,
ingo@429: (Collection)result,
ingo@365: null,
ingo@365: locale,
ingo@365: linesVisible,
ingo@365: shapesVisible
ingo@365: );
ingo@365: chart.generateChart();
ingo@365:
ingo@365: if (CACHE_CHART) {
ingo@365: log.info("Put chart into cache.");
ingo@365: purifyChart(chart, uuid);
ingo@365: }
ingo@365:
ingo@365: return chart;
ingo@365: }
ingo@365:
ingo@1034:
ingo@1034: @Override
ingo@1034: protected void createODV(
ingo@1034: OutputStream outputStream, String uuid, CallContext callContext)
ingo@1034: throws IOException, StateException {
ingo@1034:
ingo@1034: String [] COLUMN_HEADER = {
ingo@1034: "Cruise",
ingo@1034: "Station",
ingo@1034: "Type",
ingo@1034: "yyyy-mm-dd hh:mm",
ingo@1034: "Lon (°E)",
ingo@1034: "Lat (°N)",
ingo@1034: "Bot. Depth [m]",
ingo@1034: "Depth [m]"
ingo@1034: };
ingo@1034:
ingo@1034: Export.Profile ODV_PROFILE = new DefaultProfile(
ingo@1034: COLUMN_HEADER,
ingo@1034: '\t',
ingo@1034: CSVWriter.NO_QUOTE_CHARACTER,
ingo@1034: CSVWriter.NO_ESCAPE_CHARACTER,
ingo@1034: "ODV",
ingo@1034: "ISO-8859-1");
ingo@1034:
ingo@1034: Collection result = (Collection) getChartResult(
ingo@1034: uuid, callContext);
ingo@1034:
ingo@1034: if (result == null) {
ingo@1034: log.error("No data for export found.");
ingo@1034: return;
ingo@1034: }
ingo@1034:
ingo@1034: Export export = new HorizontalProfileMeshCrossODVExporter(
ingo@1034: getParameters(uuid));
ingo@1034:
ingo@1034: export.create(ODV_PROFILE, outputStream, result);
ingo@1034: }
ingo@1034:
ingo@1034:
sascha@443: private static int numSamples(CallContext callContext) {
sascha@443: GNVArtifactContext context =
sascha@443: (GNVArtifactContext)callContext.globalContext();
sascha@443: Integer samples = (Integer)context.get(
sascha@443: GNVArtifactContext.HORIZONTAL_CROSS_SECTION_PROFILE_SAMPLES_KEY);
sascha@443: return samples != null
sascha@443: ? samples.intValue()
sascha@443: : GNVArtifactContext.DEFAULT_HORIZONTAL_CROSS_SECTION_PROFILE_SAMPLES;
sascha@443: }
sascha@443:
tim@352: @Override
sascha@439: protected Object getChartResult(String uuid, CallContext callContext) {
ingo@365: log.debug("HorizontalProfileMeshCrossOutputState.getChartResult");
sascha@440:
ingo@1060: String key = getHash();
ingo@1030: if (CacheFactory.getInstance().isInitialized()) {
ingo@1030: log.debug("Using cache - key: " + key);
ingo@1030: net.sf.ehcache.Element value = CacheFactory.getInstance().getCache().get(key);
sascha@440:
ingo@1030: if (value != null) {
ingo@1030: log.debug("Found element in cache.");
ingo@1030: return (Collection) (value.getObjectValue());
tim@352: }
tim@352: }
ingo@1030:
ingo@1030: log.debug("Not using cache or element not found.");
ingo@1030: Collection result = null;
ingo@1030:
ingo@1030: InputData meshLine = inputData.get("mesh_linestring");
ingo@1030: InputData meshId = inputData.get("meshid");
ingo@1030:
ingo@1030: if (meshLine == null) {
ingo@1030: log.error("mesh_linestring is not defined");
ingo@1030: throw new IllegalStateException("missing mesh_linestring");
ingo@1030: }
ingo@1030:
ingo@1030: if (meshId == null) {
ingo@1030: log.error("meshid is not defined");
ingo@1030: throw new IllegalStateException("missing meshid");
ingo@1030: }
ingo@1030:
ingo@1030: Coordinate [] coords = WKTUtils.toCoordinates(
ingo@1030: meshLine.getValue());
ingo@1030:
ingo@1030: if (coords == null) {
ingo@1030: throw new IllegalStateException("cannot read coordinates");
ingo@1030: }
ingo@1030:
ingo@1030: try {
ingo@1030: String additionWhere = USE_INDEX_BUFFER
ingo@1030: ? WKTUtils.worldCoordinatesToIndex(
ingo@1030: coords,
ingo@1030: result,
ingo@1030: meshId.getValue(),
ingo@1030: ijkQueryID)
ingo@1030: : WKTUtils.TRUE_EXPRESSION;
ingo@1030:
ingo@1030: String[] addedFilterValues = StringUtils.append(
ingo@1030: generateFilterValuesFromInputData(),
ingo@1030: additionWhere);
ingo@1030:
ingo@1030: QueryExecutor queryExecutor = QueryExecutorFactory
ingo@1030: .getInstance()
ingo@1030: .getQueryExecutor();
ingo@1030:
ingo@1030: result = process(
ingo@1030: Arrays.asList(coords),
ingo@1030: numSamples(callContext),
ingo@1030: queryExecutor.executeQuery(
ingo@1030: queryID,
ingo@1030: addedFilterValues));
ingo@1030: }
ingo@1030: catch (QueryException e) {
ingo@1030: log.error(e,e);
ingo@1030: }
ingo@1030:
ingo@1030: if (CacheFactory.getInstance().isInitialized()) {
ingo@1030: CacheFactory.getInstance().getCache().put(new net.sf.ehcache.Element(key, result));
ingo@1030: }
ingo@1030:
tim@352: return result;
tim@352: }
tim@352:
ingo@365:
ingo@811: /**
ingo@811: * Prepares the input data for chart creation.
ingo@811: *
ingo@811: * @param path The coordinates describing the path the data is processed
ingo@811: * for.
ingo@811: * @param numSamples Number of samples.
ingo@811: * @param input The input data.
ingo@811: * @return finalized data ready for chart creation.
ingo@811: */
ingo@423: public static Collection process(
ingo@423: List path,
sascha@443: int numSamples,
ingo@423: Collection input
ingo@423: ) {
sascha@443: boolean debug = log.isDebugEnabled();
sascha@443:
sascha@443: if (debug) {
sascha@443: log.debug("--- number of points before processing: " + input.size());
sascha@443: log.debug(" number samples: " + numSamples);
sascha@443: }
sascha@443:
ingo@423: ArrayList output = new ArrayList();
ingo@423:
ingo@423: Result last = null;
ingo@423:
ingo@423: int [] diffColums = null;
ingo@423:
ingo@423: SectionHandler sectionHandler = null;
ingo@423:
ingo@423: for (Result result: input) {
ingo@423:
ingo@423: if (sectionHandler == null) {
ingo@423:
ingo@423: ResultDescriptor rd = result.getResultDescriptor();
ingo@423: diffColums = rd.getColumnIndices(DIFF_COLUMS);
ingo@423: int columns = rd.getColumnCount();
ingo@423:
ingo@423: DefaultResultDescriptor resultDescriptor =
ingo@423: new DefaultResultDescriptor();
ingo@423:
ingo@1034: log.debug("------------------------------------------------------");
ingo@423: for (int j = 0; j < columns; ++j) {
ingo@423: String columnName = rd.getColumnName(j);
sascha@439: if (!StringUtils.contains(COLUMN_BLACKLIST, columnName)) {
ingo@1034: log.debug("!!! COLUMN NAME: " + columnName);
ingo@423: resultDescriptor.addColumn(
ingo@423: columnName,
ingo@423: rd.getColumnClassName(j));
ingo@423: }
ingo@423: }
ingo@423:
ingo@423: sectionHandler = new SectionHandler(
ingo@423: path,
sascha@443: numSamples,
ingo@423: output,
ingo@423: resultDescriptor);
ingo@423:
ingo@423: sectionHandler.setPrototyp(result);
ingo@423: }
ingo@423:
ingo@423: if (last != null && WKTUtils.different(last, result, diffColums)) {
ingo@423: sectionHandler.finish();
ingo@423: sectionHandler.setPrototyp(result);
ingo@423: }
ingo@423:
ingo@423: sectionHandler.handle(result);
ingo@423:
ingo@423: last = result;
ingo@423: }
ingo@423:
ingo@423: if (sectionHandler != null) {
ingo@423: sectionHandler.finish();
ingo@423: }
ingo@423:
sascha@443: if (debug) {
sascha@443: log.debug("--- number of points after processing: " + output.size());
sascha@443: }
ingo@423:
ingo@423: return output;
ingo@423: }
ingo@423:
ingo@423:
ingo@423: private static final String [] DIFF_COLUMS = {
ingo@423: "GROUP1",
ingo@423: "GROUP2",
ingo@423: "GROUP3"
ingo@423: };
ingo@423:
ingo@423: private static final String [] COLUMN_BLACKLIST = {
ingo@423: "MEDIAN.MESHPOINT.JPOSITION",
ingo@423: "MEDIAN.MESHPOINT.IPOSITION"
ingo@423: };
ingo@423:
ingo@423: public static final double EPSILON = 1e-5d;
ingo@423:
ingo@423: public static final class SectionHandler
ingo@423: implements Interpolation2D.Consumer
ingo@423: {
ingo@423: private ArrayList points;
ingo@423: private List path;
ingo@423: private Collection output;
ingo@423: private Result prototyp;
ingo@423: private ResultDescriptor descriptor;
ingo@423: private boolean lastWasSuccess;
sascha@443: private int numSamples;
ingo@423:
ingo@423: public SectionHandler() {
ingo@423: }
ingo@423:
ingo@423: public SectionHandler(
ingo@423: List path,
sascha@443: int numSamples,
ingo@423: Collection output,
ingo@423: ResultDescriptor descriptor
ingo@423: ) {
ingo@423: this.path = path;
sascha@443: this.numSamples = numSamples;
ingo@423: this.output = output;
ingo@423: this.descriptor = descriptor;
ingo@423: points = new ArrayList();
ingo@423: lastWasSuccess = true;
ingo@423: }
ingo@423:
ingo@423: public void finish() {
ingo@423: if (!points.isEmpty()) {
ingo@423: double distance = WKTUtils.toKM(
ingo@423: DistanceCalculator.calculateDistance(path));
ingo@423:
ingo@423: if (distance > EPSILON) {
ingo@423:
ingo@423: Interpolation2D.interpolate(
ingo@423: path,
ingo@423: points,
ingo@423: 0d,
ingo@423: distance,
sascha@443: numSamples,
ingo@423: LinearMetrics.INSTANCE,
ingo@423: this);
ingo@423: }
ingo@423:
ingo@423: points.clear();
ingo@423: }
ingo@423: lastWasSuccess = true;
ingo@423: }
ingo@423:
ingo@423: public void setPrototyp(Result prototyp) {
ingo@423: this.prototyp = prototyp;
ingo@423: }
ingo@423:
ingo@423: public void handle(Result result) {
ingo@423: Coordinate coordinate =
ingo@423: WKTUtils.toCoordinate(result.getString("SHAPE"));
ingo@423: double value = result.getDouble("YORDINATE");
sascha@519: int iPos = result.getInteger("IPOSITION");
sascha@519: int jPos = result.getInteger("JPOSITION");
ingo@423: Point2d p = new Point2d(
ingo@423: coordinate.x,
ingo@423: coordinate.y,
ingo@423: value,
ingo@423: iPos, jPos);
ingo@423: points.add(p);
ingo@423: }
ingo@423:
ingo@423: public void interpolated(Coordinate coordinate, boolean success) {
sascha@425:
sascha@425: if (!success && !lastWasSuccess) {
sascha@425: // only insert null if last was valid.
sascha@425: // This prevents flooding the result set with nulls
sascha@425: // if interpolating over a large gap.
sascha@425: return;
sascha@425: }
sascha@425:
ingo@423: DefaultResult result = new DefaultResult(descriptor);
ingo@423: ResultDescriptor pd = prototyp.getResultDescriptor();
ingo@423:
ingo@423: int pcolums = pd.getColumnCount();
ingo@423: for (int i = 0, j = 0; i < pcolums; ++i) {
ingo@423: String colname = pd.getColumnName(i);
sascha@439: if (StringUtils.contains(COLUMN_BLACKLIST, colname)) {
ingo@423: continue;
ingo@423: }
ingo@423: if (colname.equals("SHAPE")) {
ingo@423: result.addColumnValue(j, WKTUtils.toWKT(coordinate));
ingo@423: }
ingo@423: else if (colname.equals("YORDINATE")) {
sascha@425: result.addColumnValue(j, success
sascha@425: ? Double.valueOf(coordinate.z)
sascha@425: : null);
ingo@423: }
ingo@423: else {
ingo@423: result.addColumnValue(j, prototyp.getObject(i));
ingo@423: }
ingo@423: ++j;
ingo@423: }
ingo@423: output.add(result);
ingo@423: lastWasSuccess = success;
ingo@423: }
ingo@423: }
tim@352: }
sascha@836: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :