/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2015, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.math; /** * Histogram querying class. * * @author Johann Sorel (Geomatys) */ public class Histogram { private final long[] buckets; private final double start; private final double end; private long sum = -1; public Histogram(long[] buckets, double start, double end) { this.buckets = buckets; this.start = start; this.end = end; } public double getStart() { return start; } public double getEnd() { return end; } public long[] getBuckets() { return buckets; } /** * Calculate sum of all values in the buckets. * * @return number of values in the histogram (sum of all buckets) */ public long getSum() { if(sum!=-1) return sum; //calculate sum long s = 0; for(long l : buckets) s+=l; sum = s; return sum; } /** * Get the span of a bucket. * @return bucket span */ public double getBucketSize(){ return (end-start) / buckets.length; } public double[] getBucketRange(int index){ final double span = getBucketSize(); return new double[]{start+index*span, start+(index+1)*span}; } /** * Estimate the thredhold value for a given ratio . * * @param ratio [0-1] */ public double getValueAt(double ratio){ if(ratio<=0) return start; if(ratio>=1) return end; final long sum = getSum(); double remain = sum * ratio; for(int i=0;i<buckets.length;i++){ if(buckets[i]>remain){ //this bucket contain the searched % //linear interpolatation final double span = getBucketSize(); final double bucketStart = start+i*span; final double bucketEnd = start+(i+1)*span; ratio = 1.0 - (((double)buckets[i]-remain) / (double)buckets[i]); return bucketStart + (bucketEnd-bucketStart) * ratio; }else{ remain -= buckets[i]; } } //we should be reach here, because of double rounding values it might happen //if the % value is very close to 1 return end; } }