public static final GeoTimeSerie bucketize(GeoTimeSerie gts,long bucketspan,int bucketcount,long lastbucket,WarpScriptBucketizerFunction aggregator,long maxbuckets) throws WarpScriptException {
  long lasttick=GTSHelper.lasttick(gts);
  long firsttick=GTSHelper.firsttick(gts);
  boolean zeroLastBucket=0 == lastbucket;
  boolean zeroBucketcount=0 == bucketcount;
  if (0 == lastbucket) {
    lastbucket=lasttick;
  }
  if (0 == bucketspan && 0 != bucketcount) {
    if (lastbucket >= firsttick) {
      long delta=lastbucket - firsttick + 1;
      bucketspan=delta / bucketcount;
      if (0 == bucketspan || (delta % bucketspan) != 0) {
        bucketspan++;
      }
    }
  }
 else   if (0 == bucketspan && 0 == bucketcount) {
    throw new WarpScriptException("One of bucketspan or bucketcount must be different from zero.");
  }
  if (0 == bucketcount) {
    if (lastbucket >= firsttick) {
      long delta=lastbucket - firsttick;
      if (delta < bucketspan) {
        bucketcount=1;
      }
 else {
        bucketcount=1 + (int)(delta / bucketspan);
      }
    }
  }
  if (zeroLastBucket && zeroBucketcount) {
    if (0 != lastbucket % bucketspan) {
      lastbucket=lastbucket - (lastbucket % bucketspan) + bucketspan;
      if (lastbucket - bucketcount * bucketspan >= firsttick) {
        bucketcount++;
      }
    }
  }
  if (bucketcount < 0 || bucketcount > maxbuckets) {
    throw new WarpScriptException("Bucket count (" + bucketcount + ") would exceed maximum value of "+ maxbuckets);
  }
  if (0 == bucketspan) {
    throw new WarpScriptException("Undefined bucket span, check your GTS timestamps.");
  }
  int hint=Math.min(gts.values,(int)((lasttick - firsttick) / bucketspan));
  GeoTimeSerie bucketized=new GeoTimeSerie(lastbucket,bucketcount,bucketspan,hint);
  bucketized.setName(gts.getName());
  Map<String,String> labels=gts.getLabels();
  bucketized.setLabels(labels);
  GeoTimeSerie subgts=null;
  for (int i=0; i < bucketcount; i++) {
    long bucketend=lastbucket - i * bucketspan;
    subgts=subSerie(gts,bucketend - bucketspan + 1,bucketend,false,false,subgts);
    if (0 == subgts.values) {
      continue;
    }
    Object[] parms=new Object[8];
    int idx=0;
    parms[idx++]=bucketend;
    parms[idx]=new String[1];
    ((String[])parms[idx++])[0]=bucketized.getName();
    parms[idx]=new Map[1];
    ((Map[])parms[idx++])[0]=labels;
    parms[idx++]=Arrays.copyOf(subgts.ticks,subgts.values);
    if (null != subgts.locations) {
      parms[idx++]=Arrays.copyOf(subgts.locations,subgts.values);
    }
 else {
      parms[idx++]=new long[subgts.values];
      Arrays.fill((long[])parms[idx - 1],GeoTimeSerie.NO_LOCATION);
    }
    if (null != subgts.elevations) {
      parms[idx++]=Arrays.copyOf(subgts.elevations,subgts.values);
    }
 else {
      parms[idx++]=new long[subgts.values];
      Arrays.fill((long[])parms[idx - 1],GeoTimeSerie.NO_ELEVATION);
    }
    parms[idx++]=new Object[subgts.values];
    parms[idx++]=new long[]{0,-bucketspan,bucketend - bucketspan,bucketend};
    for (int j=0; j < subgts.values; j++) {
      ((Object[])parms[6])[j]=valueAtIndex(subgts,j);
    }
    Object[] aggregated=(Object[])aggregator.apply(parms);
    if (null != aggregated[3]) {
      setValue(bucketized,bucketend,(long)aggregated[1],(long)aggregated[2],aggregated[3],false);
    }
  }
  GTSHelper.shrink(bucketized);
  return bucketized;
}

public static final GeoTimeSerie bucketize ( GeoTimeSerie gts , long bucketspan , int bucketcount , long lastbucket , WarpScriptBucketizerFunction aggregator , long maxbuckets ) throws WarpScriptException { long lasttick = GTSHelper . lasttick ( gts ) ; long firsttick = GTSHelper . firsttick ( gts ) ; boolean zeroLastBucket = 0 == lastbucket ; boolean zeroBucketcount = 0 == bucketcount ; if ( 0 == lastbucket ) { lastbucket = lasttick ; } if ( 0 == bucketspan && 0 != bucketcount ) { if ( lastbucket >= firsttick ) { long delta = lastbucket - firsttick + 1 ; bucketspan = delta / bucketcount ; if ( 0 == bucketspan || ( delta % bucketspan ) != 0 ) { bucketspan ++ ; } } } else if ( 0 == bucketspan && 0 == bucketcount ) { throw new WarpScriptException ( "One of bucketspan or bucketcount must be different from zero." ) ; } if ( 0 == bucketcount ) { if ( lastbucket >= firsttick ) { long delta = lastbucket - firsttick ; if ( delta < bucketspan ) { bucketcount = 1 ; } else { bucketcount = 1 + ( int ) ( delta / bucketspan ) ; } } } if ( zeroLastBucket && zeroBucketcount ) { if ( 0 != lastbucket % bucketspan ) { lastbucket = lastbucket - ( lastbucket % bucketspan ) + bucketspan ; if ( lastbucket - bucketcount * bucketspan >= firsttick ) { bucketcount ++ ; } } } if ( bucketcount < 0 || bucketcount > maxbuckets ) { throw new WarpScriptException ( "Bucket count (" + bucketcount + ") would exceed maximum value of " + maxbuckets ) ; } if ( 0 == bucketspan ) { throw new WarpScriptException ( "Undefined bucket span, check your GTS timestamps." ) ; } int hint = Math . min ( gts . values , ( int ) ( ( lasttick - firsttick ) / bucketspan ) ) ; GeoTimeSerie bucketized = new GeoTimeSerie ( lastbucket , bucketcount , bucketspan , hint ) ; bucketized . setName ( gts . getName ( ) ) ; Map < String , String > labels = gts . getLabels ( ) ; bucketized . setLabels ( labels ) ; GeoTimeSerie subgts = null ; for ( int i = 0 ; i < bucketcount ; i ++ ) { long bucketend = lastbucket - i * bucketspan ; subgts = subSerie ( gts , bucketend - bucketspan + 1 , bucketend , false , false , subgts ) ; if ( 0 == subgts . values ) { continue ; } Object [ ] parms = new Object [ 8 ] ; int idx = 0 ; parms [ idx ++ ] = bucketend ; parms [ idx ] = new String [ 1 ] ; ( ( String [ ] ) parms [ idx ++ ] ) [ 0 ] = bucketized . getName ( ) ; parms [ idx ] = new Map [ 1 ] ; ( ( Map [ ] ) parms [ idx ++ ] ) [ 0 ] = labels ; parms [ idx ++ ] = Arrays . copyOf ( subgts . ticks , subgts . values ) ; if ( null != subgts . locations ) { parms [ idx ++ ] = Arrays . copyOf ( subgts . locations , subgts . values ) ; } else { parms [ idx ++ ] = new long [ subgts . values ] ; Arrays . fill ( ( long [ ] ) parms [ idx - 1 ] , GeoTimeSerie . NO_LOCATION ) ; } if ( null != subgts . elevations ) { parms [ idx ++ ] = Arrays . copyOf ( subgts . elevations , subgts . values ) ; } else { parms [ idx ++ ] = new long [ subgts . values ] ; Arrays . fill ( ( long [ ] ) parms [ idx - 1 ] , GeoTimeSerie . NO_ELEVATION ) ; } parms [ idx ++ ] = new Object [ subgts . values ] ; parms [ idx ++ ] = new long [ ] { 0 , - bucketspan , bucketend - bucketspan , bucketend } ; for ( int j = 0 ; j < subgts . values ; j ++ ) { ( ( Object [ ] ) parms [ 6 ] ) [ j ] = valueAtIndex ( subgts , j ) ; } Object [ ] aggregated = ( Object [ ] ) aggregator . apply ( parms ) ; if ( null != aggregated [ 3 ] ) { setValue ( bucketized , bucketend , ( long ) aggregated [ 1 ] , ( long ) aggregated [ 2 ] , aggregated [ 3 ] , false ) ; } } GTSHelper . shrink ( bucketized ) ; return bucketized ; }
converts a geo time serie into a bucketized version . bucketizing means aggregating values ( with associated location and elevation ) that lie within a given interval into a single one . intervals considered span a given width called the bucketspan .
