-/*******************************************************************************\r
- * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.history.util.subscription;\r
-\r
-import java.util.Arrays;\r
-import java.util.Comparator;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.Datatypes;\r
-import org.simantics.databoard.adapter.AdaptException;\r
-import org.simantics.databoard.type.ArrayType;\r
-import org.simantics.databoard.type.Component;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.databoard.type.NumberType;\r
-import org.simantics.databoard.type.RecordType;\r
-import org.simantics.databoard.util.Bean;\r
-import org.simantics.databoard.util.Limit;\r
-import org.simantics.databoard.util.Range;\r
-\r
-/**\r
- * This is an utility class for SubscriptionItem.\r
- * \r
- * The Simantics Charts samples history data in a specified way. \r
- * One data source item is recorded into multiple history item, each identified\r
- * with a named SamplingFormat. This class describes a named sampling format.\r
- * \r
- * @author toni.kalajainen@semantum.fi\r
- */\r
-public class SamplingFormat extends Bean {\r
- \r
- public static final SamplingFormat[] EMPTY = new SamplingFormat[0];\r
- \r
- public final static Comparator<Bean> INTERVAL_COMPARATOR = new Comparator<Bean>() {\r
- @Override\r
- public int compare(Bean o1, Bean o2) {\r
- double i1 = (Double) o1.getFieldUnchecked("interval");\r
- double i2 = (Double) o2.getFieldUnchecked("interval");\r
- boolean nan1 = Double.isNaN( i1 );\r
- boolean nan2 = Double.isNaN( i2 );\r
- \r
- if ( nan1 && nan2 ) return 0;\r
- if ( nan1 && !nan2) return -1;\r
- if ( !nan1 && nan2) return 1;\r
- return i1 == i2 ? 0 : ( i1 < i2 ? -1 : 1 );\r
- }\r
- };\r
- \r
- public final static Comparator<SamplingFormat> DEADBAND_COMPARATOR = new Comparator<SamplingFormat>() {\r
- @Override\r
- public int compare(SamplingFormat o1, SamplingFormat o2) {\r
- boolean nan1 = Double.isNaN( o1.deadband );\r
- boolean nan2 = Double.isNaN( o2.deadband );\r
- \r
- if ( nan1 && nan2 ) return 0;\r
- if ( nan1 && !nan2) return -1;\r
- if ( !nan1 && nan2) return 1;\r
- return o1.deadband == o2.deadband ? 0 : ( o1.deadband < o2.deadband ? -1 : 1 );\r
- }\r
- };\r
-\r
- /** Identifier, this value is used for separating the time series files */\r
- public String formatId;\r
- \r
- /** \r
- * Describes the format of the packed sample. The sample must be a record.\r
- * The record must have any combination of the following named fields.\r
- * The field types must one of: byte, integer, long, float, double.\r
- * \r
- * time, endTime, value - are mandatory fields.\r
- * \r
- * time - Region start time, the time of the 1st included sample\r
- * endTime - Region end time, the time of the last included sample\r
- * \r
- * value - First value in the region\r
- * lastValue - Last value in the region\r
- * avg - Average value of all included samples\r
- * median - Median value of all samples in the region\r
- * min - Lowest value in the region\r
- * max - Highest value in the region\r
- * \r
- * quality - 0 = Good, -1 = No value\r
- * count - The number of included samples in the region\r
- */\r
- public Datatype format;\r
-\r
- /** Interval sets the minimum time for a packed sample */\r
- public double interval = Double.NaN;\r
-\r
- /** Deadband determines the minimum value change for a packed sample when collecting data */\r
- public double deadband = Double.NaN;\r
- \r
- public SamplingFormat()\r
- { \r
- }\r
- \r
- public SamplingFormat(String id, RecordType sampleType, double interval, double deadband)\r
- {\r
- this.formatId = id;\r
- this.format = sampleType;\r
- this.interval = interval;\r
- this.deadband = deadband;\r
- }\r
- \r
- // Sampling format templates\r
- public static SamplingFormat simple, allfields, vector;\r
- \r
- public RecordType record() { return (RecordType) format; }\r
-\r
- static {\r
- simple = new SamplingFormat();\r
- simple.formatId = "Simple";\r
- RecordType format = (RecordType) (simple.format = new RecordType()); \r
- format.addComponent("time", Datatypes.DOUBLE);\r
- format.addComponent("endTime", Datatypes.DOUBLE);\r
- format.addComponent("value", Datatypes.DOUBLE);\r
- format.addComponent("quality", Datatypes.BYTE);\r
- simple.interval = Double.NaN;\r
- simple.deadband = Double.NaN;\r
- \r
- allfields = new SamplingFormat();\r
- allfields.formatId = "Allfields";\r
- allfields.format = new RecordType();\r
- format = (RecordType) (allfields.format = new RecordType()); \r
- format.addComponent("time", Datatypes.DOUBLE);\r
- format.addComponent("endTime", Datatypes.DOUBLE);\r
- \r
- format.addComponent("value", Datatypes.DOUBLE);\r
- format.addComponent("lastValue", Datatypes.DOUBLE); \r
- format.addComponent("min", Datatypes.DOUBLE);\r
- format.addComponent("max", Datatypes.DOUBLE);\r
- format.addComponent("avg", Datatypes.DOUBLE);\r
- format.addComponent("median", Datatypes.DOUBLE);\r
- \r
- format.addComponent("quality", Datatypes.BYTE);\r
- format.addComponent("count", Datatypes.INTEGER);\r
- allfields.interval = Double.NaN;\r
- allfields.deadband = Double.NaN; \r
- \r
- vector = new SamplingFormat();\r
- vector.formatId = "Vector";\r
- vector.format = new RecordType();\r
- format = (RecordType) (vector.format = new RecordType()); \r
- format.addComponent("time", Datatypes.FLOAT);\r
- format.addComponent("endTime", Datatypes.FLOAT);\r
- format.addComponent("value", new ArrayType( Datatypes.DOUBLE, Range.between(Limit.inclusive(3), Limit.inclusive(3)) ));\r
- format.addComponent("count", Datatypes.INTEGER);\r
- vector.interval = Double.NaN;\r
- vector.deadband = Double.NaN;\r
- \r
- }\r
- \r
- @Override\r
- public boolean equals(Object obj) {\r
- if ( obj == null ) return false;\r
- if ( obj == this ) return true;\r
- if ( obj instanceof SamplingFormat == false ) return false;\r
- SamplingFormat other = (SamplingFormat) obj; \r
-// if ( !doubleEquals(interval, other.interval) || !doubleEquals(deadband, other.deadband) ) return false;\r
-// return RecordTypeBinding.equals( other.sampleType, sampleType );\r
- return formatId.equals(other.formatId);\r
- }\r
- \r
- @Override\r
- public String toString() {\r
- return "id="+formatId+", "+format +", interval="+interval+", deadband="+deadband;\r
- }\r
- \r
- @Override\r
- public SamplingFormat clone() {\r
- try {\r
- SamplingFormat result = new SamplingFormat();\r
- result.formatId = formatId;\r
- result.interval = interval;\r
- result.deadband = deadband;\r
- result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );\r
- return result;\r
- } catch (AdaptException e) {\r
- throw new RuntimeException( e );\r
- }\r
- }\r
-\r
- public SamplingFormat clone(double interval, double deadband) {\r
- try {\r
- SamplingFormat result = new SamplingFormat();\r
- result.formatId = formatId;\r
- result.interval = interval;\r
- result.deadband = deadband;\r
- result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );\r
- return result;\r
- } catch (AdaptException e) {\r
- throw new RuntimeException( e );\r
- }\r
- }\r
- \r
- public SamplingFormat cloneTo(String id, double interval, double deadband) {\r
- try {\r
- SamplingFormat result = new SamplingFormat();\r
- result.formatId = id;\r
- result.interval = interval;\r
- result.deadband = deadband;\r
- result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );\r
- return result;\r
- } catch (AdaptException e) {\r
- throw new RuntimeException( e );\r
- }\r
- }\r
- \r
- public SamplingFormat setUnit(String unit) {\r
- for ( int i = 0; i<format.getComponentCount(); i++ ) {\r
- Component c = ((RecordType)format).getComponent(i);\r
- if ( c.name.equals( "value" ) || \r
- c.name.equals( "min" ) || \r
- c.name.equals( "max" ) || \r
- c.name.equals( "avg" ) ||\r
- c.name.equals( "median" )\r
- ) {\r
- if ( c.type instanceof NumberType ) {\r
- NumberType nt = (NumberType) c.type;\r
- nt.setUnit( unit );\r
- }\r
- }\r
- }\r
- return this;\r
- }\r
- \r
- public static void sortByInterval( SamplingFormat[] formats ) {\r
- Arrays.sort(formats, INTERVAL_COMPARATOR);\r
- }\r
- \r
- public static void sortByDeadband( SamplingFormat[] formats ) {\r
- Arrays.sort(formats, DEADBAND_COMPARATOR);\r
- }\r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.history.util.subscription;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.Datatypes;
+import org.simantics.databoard.adapter.AdaptException;
+import org.simantics.databoard.type.ArrayType;
+import org.simantics.databoard.type.Component;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.type.NumberType;
+import org.simantics.databoard.type.RecordType;
+import org.simantics.databoard.util.Bean;
+import org.simantics.databoard.util.Limit;
+import org.simantics.databoard.util.Range;
+
+/**
+ * This is an utility class for SubscriptionItem.
+ *
+ * The Simantics Charts samples history data in a specified way.
+ * One data source item is recorded into multiple history item, each identified
+ * with a named SamplingFormat. This class describes a named sampling format.
+ *
+ * @author toni.kalajainen@semantum.fi
+ */
+public class SamplingFormat extends Bean {
+
+ public static final SamplingFormat[] EMPTY = new SamplingFormat[0];
+
+ public static int compareSamplingInterval(double i1, double i2) {
+ boolean nan1 = Double.isNaN( i1 );
+ boolean nan2 = Double.isNaN( i2 );
+
+ if ( nan1 && nan2 ) return 0;
+ if ( nan1 && !nan2) return -1;
+ if ( !nan1 && nan2) return 1;
+ return i1 == i2 ? 0 : ( i1 < i2 ? -1 : 1 );
+ }
+
+ public final static Comparator<Bean> INTERVAL_COMPARATOR = new Comparator<Bean>() {
+ @Override
+ public int compare(Bean o1, Bean o2) {
+ double i1 = (Double) o1.getFieldUnchecked("interval");
+ double i2 = (Double) o2.getFieldUnchecked("interval");
+ return compareSamplingInterval(i1, i2);
+ }
+ };
+
+ public final static Comparator<SamplingFormat> DEADBAND_COMPARATOR = new Comparator<SamplingFormat>() {
+ @Override
+ public int compare(SamplingFormat o1, SamplingFormat o2) {
+ boolean nan1 = Double.isNaN( o1.deadband );
+ boolean nan2 = Double.isNaN( o2.deadband );
+
+ if ( nan1 && nan2 ) return 0;
+ if ( nan1 && !nan2) return -1;
+ if ( !nan1 && nan2) return 1;
+ return o1.deadband == o2.deadband ? 0 : ( o1.deadband < o2.deadband ? -1 : 1 );
+ }
+ };
+
+ /** Identifier, this value is used for separating the time series files */
+ public String formatId;
+
+ /**
+ * Describes the format of the packed sample. The sample must be a record.
+ * The record must have any combination of the following named fields.
+ * The field types must one of: byte, integer, long, float, double.
+ *
+ * time, endTime, value - are mandatory fields.
+ *
+ * time - Region start time, the time of the 1st included sample
+ * endTime - Region end time, the time of the last included sample
+ *
+ * value - First value in the region
+ * lastValue - Last value in the region
+ * avg - Average value of all included samples
+ * median - Median value of all samples in the region
+ * min - Lowest value in the region
+ * max - Highest value in the region
+ *
+ * quality - 0 = Good, -1 = No value
+ * count - The number of included samples in the region
+ */
+ public Datatype format;
+
+ /** Interval sets the minimum time for a packed sample */
+ public double interval = Double.NaN;
+
+ /** Deadband determines the minimum value change for a packed sample when collecting data */
+ public double deadband = Double.NaN;
+
+ public SamplingFormat()
+ {
+ }
+
+ public SamplingFormat(String id, RecordType sampleType, double interval, double deadband)
+ {
+ this.formatId = id;
+ this.format = sampleType;
+ this.interval = interval;
+ this.deadband = deadband;
+ }
+
+ // Sampling format templates
+ public static SamplingFormat simple, allfields, vector;
+
+ public RecordType record() { return (RecordType) format; }
+
+ static {
+ simple = new SamplingFormat();
+ simple.formatId = "Simple";
+ RecordType format = (RecordType) (simple.format = new RecordType());
+ format.addComponent("time", Datatypes.DOUBLE);
+ format.addComponent("endTime", Datatypes.DOUBLE);
+ format.addComponent("value", Datatypes.DOUBLE);
+ format.addComponent("quality", Datatypes.BYTE);
+ simple.interval = Double.NaN;
+ simple.deadband = Double.NaN;
+
+ allfields = new SamplingFormat();
+ allfields.formatId = "Allfields";
+ allfields.format = new RecordType();
+ format = (RecordType) (allfields.format = new RecordType());
+ format.addComponent("time", Datatypes.DOUBLE);
+ format.addComponent("endTime", Datatypes.DOUBLE);
+
+ format.addComponent("value", Datatypes.DOUBLE);
+ format.addComponent("lastValue", Datatypes.DOUBLE);
+ format.addComponent("min", Datatypes.DOUBLE);
+ format.addComponent("max", Datatypes.DOUBLE);
+ format.addComponent("avg", Datatypes.DOUBLE);
+ format.addComponent("median", Datatypes.DOUBLE);
+
+ format.addComponent("quality", Datatypes.BYTE);
+ format.addComponent("count", Datatypes.INTEGER);
+ allfields.interval = Double.NaN;
+ allfields.deadband = Double.NaN;
+
+ vector = new SamplingFormat();
+ vector.formatId = "Vector";
+ vector.format = new RecordType();
+ format = (RecordType) (vector.format = new RecordType());
+ format.addComponent("time", Datatypes.FLOAT);
+ format.addComponent("endTime", Datatypes.FLOAT);
+ format.addComponent("value", new ArrayType( Datatypes.DOUBLE, Range.between(Limit.inclusive(3), Limit.inclusive(3)) ));
+ format.addComponent("count", Datatypes.INTEGER);
+ vector.interval = Double.NaN;
+ vector.deadband = Double.NaN;
+
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( obj == null ) return false;
+ if ( obj == this ) return true;
+ if ( obj instanceof SamplingFormat == false ) return false;
+ SamplingFormat other = (SamplingFormat) obj;
+// if ( !doubleEquals(interval, other.interval) || !doubleEquals(deadband, other.deadband) ) return false;
+// return RecordTypeBinding.equals( other.sampleType, sampleType );
+ return formatId.equals(other.formatId);
+ }
+
+ @Override
+ public String toString() {
+ return "id="+formatId+", "+format +", interval="+interval+", deadband="+deadband;
+ }
+
+ @Override
+ public SamplingFormat clone() {
+ try {
+ SamplingFormat result = new SamplingFormat();
+ result.formatId = formatId;
+ result.interval = interval;
+ result.deadband = deadband;
+ result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );
+ return result;
+ } catch (AdaptException e) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ public SamplingFormat clone(double interval, double deadband) {
+ try {
+ SamplingFormat result = new SamplingFormat();
+ result.formatId = formatId;
+ result.interval = interval;
+ result.deadband = deadband;
+ result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );
+ return result;
+ } catch (AdaptException e) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ public SamplingFormat cloneTo(String id, double interval, double deadband) {
+ try {
+ SamplingFormat result = new SamplingFormat();
+ result.formatId = id;
+ result.interval = interval;
+ result.deadband = deadband;
+ result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );
+ return result;
+ } catch (AdaptException e) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ public SamplingFormat setUnit(String unit) {
+ for ( int i = 0; i<format.getComponentCount(); i++ ) {
+ Component c = ((RecordType)format).getComponent(i);
+ if ( c.name.equals( "value" ) ||
+ c.name.equals( "min" ) ||
+ c.name.equals( "max" ) ||
+ c.name.equals( "avg" ) ||
+ c.name.equals( "median" )
+ ) {
+ if ( c.type instanceof NumberType ) {
+ NumberType nt = (NumberType) c.type;
+ nt.setUnit( unit );
+ }
+ }
+ }
+ return this;
+ }
+
+ public static void sortByInterval( SamplingFormat[] formats ) {
+ Arrays.sort(formats, INTERVAL_COMPARATOR);
+ }
+
+ public static void sortByDeadband( SamplingFormat[] formats ) {
+ Arrays.sort(formats, DEADBAND_COMPARATOR);
+ }
+
+}