-/*******************************************************************************\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;\r
-\r
-import org.simantics.databoard.annotations.Optional;\r
-import org.simantics.databoard.annotations.Referable;\r
-\r
-/**\r
- * \r
- * @author toni.kalajainen\r
- */\r
-public class WeightedMedian2 {\r
-\r
- public int maxItems;\r
- public int itemCount;\r
- @Optional public Item median;\r
- \r
- // Relative pos = pos - median.accumulated weight \r
- public double rpos;\r
- \r
- public WeightedMedian2()\r
- {\r
- maxItems = Integer.MAX_VALUE;\r
- }\r
- \r
- public WeightedMedian2(int maxItems)\r
- {\r
- this.maxItems = maxItems;\r
- }\r
- \r
- public void clear() {\r
- itemCount = 0;\r
- median = null;\r
- rpos = 0;\r
- }\r
- \r
- public void add(double weight, double value)\r
- {\r
- if (weight<=0) return;\r
- if (median == null) {\r
- median = new Item( weight, value );\r
- itemCount++;\r
- rpos = weight / 2;\r
- return; \r
- }\r
- \r
- Item i = median;\r
- while (true) {\r
- \r
- if (value>=i.low && value<=i.high) {\r
- double totWeight = i.weight+weight;\r
- i.value = ( i.value * i.weight + value * weight ) / totWeight;\r
- i.weight = totWeight;\r
- break;\r
- }\r
- \r
- if (value < i.low) {\r
- \r
- // i = 1st, add new item as first\r
- if (i.prev==null) {\r
- i.prev = new Item( weight, value, null, i );\r
- itemCount++;\r
- break;\r
- }\r
- \r
- // value is between two items, add new item\r
- if (i.prev.high < value) {\r
- Item n = new Item( weight, value, i.prev, i );\r
- itemCount++;\r
- i.prev.next = n;\r
- i.prev = n;\r
- break;\r
- }\r
- \r
- i = i.prev;\r
- continue;\r
- } \r
- \r
- if (value > i.high) {\r
- \r
- // i = last, add new item as last\r
- if (i.next==null) {\r
- i.next = new Item( weight, value, i, null ); \r
- itemCount++;\r
- break;\r
- }\r
- \r
- // value is between two items, add new item\r
- if (i.next.low > value) {\r
- Item n = new Item( weight, value, i, i.next );\r
- itemCount++;\r
- i.next.prev = n;\r
- i.next = n;\r
- break;\r
- }\r
- \r
- i = i.next;\r
- continue;\r
- }\r
- }\r
-\r
- rpos += (value<median.low?-1:1) * weight / 2;\r
- while (rpos<0) {\r
- median = median.prev;\r
- rpos += median.weight;\r
- }\r
- while (rpos>=median.weight) {\r
- rpos -= median.weight;\r
- median = median.next;\r
- }\r
- \r
- if (itemCount>maxItems) coalesce();\r
- }\r
- \r
- public void coalesce() \r
- {\r
- Item i = median.next;\r
- while (i!=null) {\r
- Item n = i.next;\r
- if (n==null) break;\r
- i.next = n.next;\r
- if (n.next!=null) n.next.prev = i;\r
- double totWeight = i.weight+n.weight;\r
- i.high = n.high;\r
- i.value = ( i.value * i.weight + n.value * n.weight ) / totWeight;\r
- i.weight = totWeight;\r
- i = i.next;\r
- }\r
- \r
- i = median.prev;\r
- while (i!=null) {\r
- Item p = i.prev;\r
- if (p==null) break;\r
- i.prev = p.prev;\r
- if (p.prev!=null) p.prev.next = i;\r
- double totWeight = i.weight+p.weight;\r
- i.low = p.low;\r
- i.value = ( i.value * i.weight + p.value * p.weight ) / totWeight;\r
- i.weight = totWeight;\r
- i = i.prev;\r
- } \r
- }\r
- \r
- public double getMedian() \r
- {\r
- if (median==null) return Double.NaN;\r
- if (median.low == median.high) return median.value;\r
- double d = median.high - median.low;\r
- double r = rpos/median.weight;\r
- return median.low + d*r;\r
- }\r
- \r
- @Override\r
- public String toString() {\r
- StringBuilder sb = new StringBuilder();\r
- sb.append( "Median="+getMedian()+" ");\r
- \r
- Item i = first();\r
- while (i!=null) {\r
- sb.append("(");\r
- sb.append("value=");\r
- if (i.low==i.high) sb.append(i.value); else \r
- sb.append(i.value+" ("+i.low+".."+i.high+")");\r
- sb.append(", w="+i.weight);\r
- if (i==median) {\r
- sb.append(", pos="+rpos);\r
- }\r
- sb.append(")");\r
- i = i.next;\r
- }\r
- \r
- return sb.toString();\r
- } \r
- \r
- Item first() {\r
- if (median==null) return null;\r
- Item i = median;\r
- while (i.prev!=null) i = i.prev;\r
- return i;\r
- }\r
- \r
- @Referable\r
- static public class Item {\r
- public double weight;\r
- public double low;\r
- public double high;\r
- public double value;\r
- \r
- public Item() {}\r
- \r
- public Item(double weight, double value) {\r
- this.weight = weight;\r
- this.low = this.high = value;\r
- }\r
-\r
- public Item(double weight, double value, Item prev, Item next) {\r
- this.weight = weight;\r
- this.value = this.low = this.high = value;\r
- this.prev = prev;\r
- this.next = next;\r
- }\r
- \r
- @Optional\r
- public Item prev;\r
- \r
- @Optional\r
- public Item next;\r
- \r
- @Override\r
- public String toString() {\r
- if (low==high) return "(value="+value+", w="+weight+")";\r
- return "(value="+value+" ("+low+".."+high+"), w="+weight+")";\r
- }\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;
+
+import org.simantics.databoard.annotations.Optional;
+import org.simantics.databoard.annotations.Referable;
+
+/**
+ *
+ * @author toni.kalajainen
+ */
+public class WeightedMedian2 {
+
+ public int maxItems;
+ public int itemCount;
+ @Optional public Item median;
+
+ // Relative pos = pos - median.accumulated weight
+ public double rpos;
+
+ public WeightedMedian2()
+ {
+ maxItems = Integer.MAX_VALUE;
+ }
+
+ public WeightedMedian2(int maxItems)
+ {
+ this.maxItems = maxItems;
+ }
+
+ public void clear() {
+ itemCount = 0;
+ median = null;
+ rpos = 0;
+ }
+
+ public void add(double weight, double value)
+ {
+ if (weight<=0) return;
+ if (median == null) {
+ median = new Item( weight, value );
+ itemCount++;
+ rpos = weight / 2;
+ return;
+ }
+
+ Item i = median;
+ while (true) {
+
+ if (value>=i.low && value<=i.high) {
+ double totWeight = i.weight+weight;
+ i.value = ( i.value * i.weight + value * weight ) / totWeight;
+ i.weight = totWeight;
+ break;
+ }
+
+ if (value < i.low) {
+
+ // i = 1st, add new item as first
+ if (i.prev==null) {
+ i.prev = new Item( weight, value, null, i );
+ itemCount++;
+ break;
+ }
+
+ // value is between two items, add new item
+ if (i.prev.high < value) {
+ Item n = new Item( weight, value, i.prev, i );
+ itemCount++;
+ i.prev.next = n;
+ i.prev = n;
+ break;
+ }
+
+ i = i.prev;
+ continue;
+ }
+
+ if (value > i.high) {
+
+ // i = last, add new item as last
+ if (i.next==null) {
+ i.next = new Item( weight, value, i, null );
+ itemCount++;
+ break;
+ }
+
+ // value is between two items, add new item
+ if (i.next.low > value) {
+ Item n = new Item( weight, value, i, i.next );
+ itemCount++;
+ i.next.prev = n;
+ i.next = n;
+ break;
+ }
+
+ i = i.next;
+ continue;
+ }
+ }
+
+ rpos += (value<median.low?-1:1) * weight / 2;
+ while (rpos<0) {
+ median = median.prev;
+ rpos += median.weight;
+ }
+ while (rpos>=median.weight) {
+ rpos -= median.weight;
+ median = median.next;
+ }
+
+ if (itemCount>maxItems) coalesce();
+ }
+
+ public void coalesce()
+ {
+ Item i = median.next;
+ while (i!=null) {
+ Item n = i.next;
+ if (n==null) break;
+ i.next = n.next;
+ if (n.next!=null) n.next.prev = i;
+ double totWeight = i.weight+n.weight;
+ i.high = n.high;
+ i.value = ( i.value * i.weight + n.value * n.weight ) / totWeight;
+ i.weight = totWeight;
+ i = i.next;
+ }
+
+ i = median.prev;
+ while (i!=null) {
+ Item p = i.prev;
+ if (p==null) break;
+ i.prev = p.prev;
+ if (p.prev!=null) p.prev.next = i;
+ double totWeight = i.weight+p.weight;
+ i.low = p.low;
+ i.value = ( i.value * i.weight + p.value * p.weight ) / totWeight;
+ i.weight = totWeight;
+ i = i.prev;
+ }
+ }
+
+ public double getMedian()
+ {
+ if (median==null) return Double.NaN;
+ if (median.low == median.high) return median.value;
+ double d = median.high - median.low;
+ double r = rpos/median.weight;
+ return median.low + d*r;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append( "Median="+getMedian()+" ");
+
+ Item i = first();
+ while (i!=null) {
+ sb.append("(");
+ sb.append("value=");
+ if (i.low==i.high) sb.append(i.value); else
+ sb.append(i.value+" ("+i.low+".."+i.high+")");
+ sb.append(", w="+i.weight);
+ if (i==median) {
+ sb.append(", pos="+rpos);
+ }
+ sb.append(")");
+ i = i.next;
+ }
+
+ return sb.toString();
+ }
+
+ Item first() {
+ if (median==null) return null;
+ Item i = median;
+ while (i.prev!=null) i = i.prev;
+ return i;
+ }
+
+ @Referable
+ static public class Item {
+ public double weight;
+ public double low;
+ public double high;
+ public double value;
+
+ public Item() {}
+
+ public Item(double weight, double value) {
+ this.weight = weight;
+ this.low = this.high = value;
+ }
+
+ public Item(double weight, double value, Item prev, Item next) {
+ this.weight = weight;
+ this.value = this.low = this.high = value;
+ this.prev = prev;
+ this.next = next;
+ }
+
+ @Optional
+ public Item prev;
+
+ @Optional
+ public Item next;
+
+ @Override
+ public String toString() {
+ if (low==high) return "(value="+value+", w="+weight+")";
+ return "(value="+value+" ("+low+".."+high+"), w="+weight+")";
+ }
+ }
+
+}