X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.history%2Fsrc%2Forg%2Fsimantics%2Fhistory%2FHistorySampler.java;h=7320f02499e552b576aad73df1c65bc9650536f7;hp=1c45a220fcf005ac80bf0e2b92f9c988127987fc;hb=e3940e67813aa0988bdd0fe6161500034e6e7518;hpb=965fa411938344172cff82a2ec0b6c50b7cb2b7c diff --git a/bundles/org.simantics.history/src/org/simantics/history/HistorySampler.java b/bundles/org.simantics.history/src/org/simantics/history/HistorySampler.java index 1c45a220f..7320f0249 100644 --- a/bundles/org.simantics.history/src/org/simantics/history/HistorySampler.java +++ b/bundles/org.simantics.history/src/org/simantics/history/HistorySampler.java @@ -1,7 +1,5 @@ package org.simantics.history; -import gnu.trove.list.array.TDoubleArrayList; - import java.io.IOException; import java.math.BigDecimal; @@ -10,6 +8,8 @@ import org.simantics.history.util.HistoryExportUtil; import org.simantics.history.util.StreamIterator; import org.simantics.history.util.ValueBand; +import gnu.trove.list.array.TDoubleArrayList; + public class HistorySampler { public synchronized static TDoubleArrayList sample( HistorySamplerItem item, double from, double end, double timeWindow, double timeStep, boolean resample ) throws HistoryException, IOException { @@ -226,5 +226,201 @@ public class HistorySampler { } - + // ------------------------------------------------------------------------ + // New history sampling routine, supports mip-mapped subscriptions + + public synchronized static TDoubleArrayList sample(HistorySamplerItem2 item, double end, double timeWindow, int maxSamples, boolean resample) throws HistoryException, IOException { + try { + // Avoid div / 0 + if (maxSamples <= 0) + return new TDoubleArrayList(0); + + // If there is something pending at this point, flush before opening for read + if (item.collector != null) + item.collector.flush(); + + // Open data source with most suitable sampling interval + double secondsPerPixel = timeWindow / (double) maxSamples; + //System.out.println("SECONDS / PIXEL: " + secondsPerPixel); + item.open(secondsPerPixel); + + return sample(item.iter, end, timeWindow, maxSamples, resample); + } finally { + item.close(); + } + } + + private static TDoubleArrayList sample(StreamIterator iter, double endTime, double timeWindow, int maxSamples, boolean resample) throws HistoryException, IOException { + double fromTime = endTime - timeWindow; + //System.out.println("sample: [" + fromTime + " .. " + endTime + "] window = " + timeWindow + " s, max samples = " + maxSamples + ", resample = " + resample); + ExportInterpolation interpolation = ExportInterpolation.LINEAR_INTERPOLATION; + + if (iter.isEmpty() || (resample && maxSamples <= 0)) + return new TDoubleArrayList(0); + + double dataFrom = iter.getFirstTime(); + double dataEnd = iter.getLastTime(); + + // Prepare time + boolean hasAnyValues = dataFrom != Double.MAX_VALUE && dataEnd != -Double.MAX_VALUE; + if (!hasAnyValues) { + //System.out.println("=> no values"); + return new TDoubleArrayList(0); + } + + // Make intersection of actual data range (allFrom, allEnd) and requested data (from, end) + double from = Math.max(fromTime, dataFrom); + double end = Math.min(endTime, dataEnd); + + //System.out.println("data available [" + dataFrom + " .. " + dataEnd + "]"); + //System.out.println("will sample between [" + from + " .. " + end + "]"); + + // Iterate until endTime is met + double time = from; + double timeStep = 0; + + if (resample) { + timeStep = timeWindow / maxSamples; + } else { + // If resample is false then all samples are reported as is. + // The code achieves this by setting startTime to from and timeStep to 0.0. + } + + // Must convert double times to String when initializing BigDecimal. + // Otherwise BigDecimal will pick up inaccuracies from beyond 15 precise digits + // thus making a mess of the time step calculations. + BigDecimal bigTime = new BigDecimal(String.valueOf(time)); + BigDecimal bigTimeStep = new BigDecimal(String.valueOf(timeStep)); + + //System.out.println("=> goto " + time); + + TDoubleArrayList result = new TDoubleArrayList(); + if (!iter.gotoTime(time)) { + //System.out.println("=> no sample found at " + time); + return result; + } + + //time = iter.getValueBand().getTimeDouble(); + + //System.out.println("=> ignore first item?: " + time + " - " + from + " = " + (time-from) + " => " + (Math.abs(time-from) < 1e-6)); + //boolean ignore = Math.abs(time-from) < 1e-6; + boolean ignore = false; + + do { + //System.out.println("process " + time + " " + iter.getValueBand() + " (ignore = " + ignore + ")"); + + // Check for valid value + if ( iter.hasValidValue() ) { + + // Write time + if (!ignore) { + //System.out.println("Add time : " + time); + result.add(time); + } + // Write value + Object value = iter.getValueBand().getValue(); + //System.out.print("Add value : " + value); + if (value instanceof Number) { + if (value instanceof Float || value instanceof Double) { + switch (interpolation) { + case PREVIOUS_SAMPLE: + if (!ignore) { + //System.out.println(" previous .. done!"); + result.add(((Number) value).doubleValue()); + } + break; + + case LINEAR_INTERPOLATION: + if (time != iter.getValueBand().getTimeDouble() && iter.hasNext()) { + // Interpolate + int currentIndex = iter.getIndex(); + ValueBand band = iter.getValueBand(); + //double t1 = band.getTimeDouble(); + Number v1 = (Number) value; + double t12 = band.getEndTimeDouble(); + iter.next(); + double t2 = iter.getValueBand().getTimeDouble(); + Number v2 = (Number) iter.getValueBand().getValue(); + iter.gotoIndex(currentIndex); + + double vs = v1.doubleValue(); + if (time > t12) + vs = HistoryExportUtil.biglerp(t12, v1.doubleValue(), t2, v2.doubleValue(), time); + + if (!ignore) { + //System.out.println(" linear .. done!"); + result.add(vs); + } + + } else { + // Exact timestamp match, or last sample. + // Don't interpolate nor extrapolate. + if (!ignore) { + //System.out.println(" else .. done!"); + result.add(((Number) value).doubleValue()); + } + } + break; + + default: + throw new UnsupportedOperationException("Unsupported interpolation: " + interpolation); + } + } else { + throw new IllegalStateException("Value is not a number " + value); + } + } else if (value instanceof Boolean) { + if(!ignore) + result.add( (Boolean)value ? 1.0: 0.0); + } else { + throw new IllegalStateException("Value is not a number " + value); + } + } + + ignore = false; + + // Read next values, and the following times + if ( timeStep>0.0 ) { + bigTime = bigTime.add(bigTimeStep); + time = bigTime.doubleValue(); + } else { + // Get smallest end time that is larger than current time + Double nextTime = null; + //System.out.println(" time = "+time); + if(!iter.hasNext()) { + duplicateLastDataPoint(result, end); + break; + } + Double itemNextTime = iter.getNextTime( time ); + //System.out.println(" "+iter.toString()+" nextTime="+itemNextTime); + if ( nextTime == null || ( nextTime > itemNextTime && !itemNextTime.equals( time ) ) ) nextTime = itemNextTime; + if ( nextTime == null || nextTime.equals( time ) ) break; + time = nextTime; + } + + boolean hasMore = false; + + iter.proceedToTime(time); + if (HistoryExportUtil.contains(iter, time)) hasMore = true; + + if (!hasMore) { + if (time <= end) { + duplicateLastDataPoint(result, end); + } + break; + } + + } while (time <= end); + + //System.out.println("=> [" + result.size() + "]" + Arrays.toString(result.toArray())); + //System.out.println("=> [" + result.size() + "]"); + return result; + } + + private static void duplicateLastDataPoint(TDoubleArrayList data, double timestamp) { + double lastValue = data.get(data.size() - 1); + //System.out.println("Duplicating last sample value " + lastValue + " @ " + timestamp); + data.add(timestamp); + data.add(lastValue); + } + }