--- /dev/null
+package org.simantics.history;\r
+\r
+import gnu.trove.list.array.TDoubleArrayList;\r
+\r
+import java.io.IOException;\r
+import java.math.BigDecimal;\r
+\r
+import org.simantics.history.csv.ExportInterpolation;\r
+import org.simantics.history.util.HistoryExportUtil;\r
+import org.simantics.history.util.StreamIterator;\r
+import org.simantics.history.util.ValueBand;\r
+\r
+public class HistorySampler {\r
+ \r
+ public synchronized static TDoubleArrayList sample( HistorySamplerItem item, double from, double end, double timeWindow, double timeStep, boolean resample ) throws HistoryException, IOException {\r
+\r
+ try {\r
+ item.open();\r
+ if(item.collector != null)\r
+ item.collector.flush();\r
+ return sample(item.iter, from, end, timeWindow, timeStep, resample);\r
+ } finally {\r
+ item.close();\r
+ }\r
+ }\r
+\r
+ public static TDoubleArrayList sample( StreamIterator iter, double from, double end, double timeWindow, double timeStep, boolean resample ) throws HistoryException, IOException {\r
+\r
+ ExportInterpolation numberInterpolation = ExportInterpolation.LINEAR_INTERPOLATION;\r
+\r
+ double startTime = 0.0;\r
+\r
+ TDoubleArrayList result = new TDoubleArrayList();\r
+\r
+ if(iter.isEmpty()) return result;\r
+\r
+ double allFrom = iter.getFirstTime();\r
+ double allEnd = 10e10;//iter.getLastTime();\r
+ \r
+ if(from > (allEnd + timeStep)) {\r
+ from = allEnd-timeWindow;\r
+ end = allEnd;\r
+ }\r
+ \r
+// System.err.println("sample " + from + " " + end);\r
+// if(from < 0)\r
+// System.err.println("fgag");\r
+\r
+ // Prepare time \r
+ boolean hasAnyValues = allFrom != Double.MAX_VALUE && allEnd != -Double.MAX_VALUE;\r
+\r
+ // Make intersection of actual data range (allFrom, allEnd) and requested data (from, end)\r
+ double _from = Double.MAX_VALUE, _end = -Double.MAX_VALUE; \r
+ if (hasAnyValues) {\r
+ _from = Math.max(allFrom, from);\r
+ _end = Math.min(allEnd, end);\r
+ }\r
+\r
+ if (!hasAnyValues) {\r
+// System.err.println("=> no values");\r
+ return result;\r
+ }\r
+\r
+ // Iterate until endTime is met for all variables\r
+ double time = _from;\r
+\r
+ if(!resample) {\r
+\r
+ // 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 \r
+ time = _from;\r
+ timeStep = 0.0;\r
+\r
+ } else {\r
+\r
+ // time = startTime + n*timeStep \r
+\r
+ // Sampling based on given startTime and timeStep\r
+ if(timeStep > 0) {\r
+\r
+ // Find the first sample time that contains data \r
+ double n = Math.max(0, Math.ceil((_from-startTime) / timeStep));\r
+ time = startTime + n*timeStep;\r
+\r
+ } else {\r
+\r
+ // Start sampling from startTime but make sure that it is not less than _from\r
+ if(startTime > _from) time = startTime;\r
+\r
+ }\r
+\r
+\r
+ }\r
+\r
+ // Must convert double times to String when initializing BigDecimal.\r
+ // Otherwise BigDecimal will pick up inaccuracies from beyond 15 precise digits\r
+ // thus making a mess of the time step calculations.\r
+\r
+ BigDecimal bigTime = new BigDecimal(String.valueOf(time));\r
+ BigDecimal bigTimeStep = new BigDecimal(String.valueOf(timeStep));\r
+\r
+ //System.err.println("=> goto " + time);\r
+ \r
+ if(!iter.gotoTime(time)) {\r
+ //System.err.println("=> no sample found at " + time);\r
+ return result;\r
+ }\r
+ \r
+ //time = iter.getValueBand().getTimeDouble();\r
+\r
+ boolean ignore = Math.abs(time-from) < 1e-6; \r
+\r
+ do {\r
+ \r
+ //System.err.println("process " + time + " " + iter.getValueBand());\r
+\r
+\r
+\r
+ // Check for valid value\r
+ if ( iter.hasValidValue() ) {\r
+ \r
+ // Write time\r
+ if(!ignore) {\r
+// System.err.println("Add time : " + time);\r
+ result.add(time);\r
+ }\r
+ // Write value\r
+ Object value = iter.getValueBand().getValue();\r
+ //System.err.print("Add value : " + value);\r
+ if (value instanceof Number) {\r
+ if (value instanceof Float || value instanceof Double) {\r
+ switch (numberInterpolation) {\r
+ case PREVIOUS_SAMPLE:\r
+\r
+ if(!ignore) {\r
+// System.err.println(" previous .. done!");\r
+ result.add(((Number) value).doubleValue());\r
+ }\r
+ \r
+ break;\r
+\r
+ case LINEAR_INTERPOLATION:\r
+ if (time != iter.getValueBand().getTimeDouble() && iter.hasNext()) {\r
+\r
+ // Interpolate\r
+ int currentIndex = iter.getIndex();\r
+ ValueBand band = iter.getValueBand();\r
+ //double t1 = band.getTimeDouble();\r
+ Number v1 = (Number) value;\r
+ double t12 = band.getEndTimeDouble();\r
+ iter.next();\r
+ double t2 = iter.getValueBand().getTimeDouble();\r
+ Number v2 = (Number) iter.getValueBand().getValue();\r
+ iter.gotoIndex(currentIndex);\r
+\r
+ double vs = v1.doubleValue();\r
+ if(time > t12)\r
+ vs = HistoryExportUtil.biglerp(t12, v1.doubleValue(), t2, v2.doubleValue(), time);\r
+\r
+ if(!ignore) {\r
+// System.err.println(" linear .. done!");\r
+ result.add(vs);\r
+ }\r
+\r
+ } else {\r
+ // Exact timestamp match, or last sample.\r
+ // Don't interpolate nor extrapolate.\r
+ if(!ignore) {\r
+// System.err.println(" else .. done!");\r
+ result.add(((Number) value).doubleValue());\r
+ }\r
+ }\r
+ break;\r
+ default:\r
+ throw new UnsupportedOperationException("Unsupported interpolation: " + numberInterpolation);\r
+ }\r
+ } else {\r
+ throw new IllegalStateException("Value is not a number " + value);\r
+ }\r
+ } else if (value instanceof Boolean) {\r
+ if(!ignore)\r
+ result.add( (Boolean)value ? 1.0: 0.0);\r
+ } else {\r
+ throw new IllegalStateException("Value is not a number " + value);\r
+ }\r
+ }\r
+ \r
+ ignore = false;\r
+\r
+ // Read next values, and the following times\r
+ if ( timeStep>0.0 ) {\r
+ bigTime = bigTime.add(bigTimeStep);\r
+ time = bigTime.doubleValue();\r
+ } else {\r
+ // Get smallest end time that is larger than current time\r
+ Double nextTime = null;\r
+ // System.out.println("time = "+time);\r
+ if(!iter.hasNext()) break;\r
+ Double itemNextTime = iter.getNextTime( time );\r
+ // System.err.println(" "+i.label+" nextTime="+itemNextTime);\r
+ if ( nextTime == null || ( nextTime > itemNextTime && !itemNextTime.equals( time ) ) ) nextTime = itemNextTime; \r
+ if ( nextTime == null || nextTime.equals( time ) ) break;\r
+ time = nextTime;\r
+ }\r
+\r
+ boolean hasMore = false;\r
+\r
+ iter.proceedToTime(time);\r
+ if(HistoryExportUtil.contains(iter, time)) hasMore = true;\r
+\r
+ if(!hasMore) break;\r
+\r
+ } while (time<=_end);\r
+\r
+ //System.err.println("=> " + Arrays.toString(result.toArray()));\r
+ \r
+ return result;\r
+\r
+ }\r
+\r
+ \r
+}\r