public Specialized(
     double spacing, N floor, boolean fill, Aggregates<? extends N> aggregates) {
   super(spacing, floor, fill);
   Util.Stats<N> stats = Util.stats(aggregates, true, true, true);
   N bottom = floor == null ? (N) stats.min : floor;
   contourLevels = LocalUtils.steps(bottom, stats.max, spacing);
 }
  public <G, V, A> void testWith(
      String test, Glyphset<G, V> glyphs, Aggregator<V, A> agg, Transfer<? super A, Color> t)
      throws Exception {
    RenderUtils.RECORD_PROGRESS = true;
    Renderer r = new SerialRenderer();
    BufferedImage ref_img = image(r, glyphs, agg, t);
    Util.writeImage(ref_img, new File(String.format("./testResults/%s/ref.png", test)));

    r = new SerialRenderer();
    BufferedImage ser_img = image(r, glyphs, agg, t);
    Util.writeImage(ser_img, new File(String.format("./testResults/%s/ser.png", test)));
    assertImageEquals("Serial", ref_img, ser_img);

    r = new ParallelRenderer();
    BufferedImage pg_img = image(r, glyphs, agg, t);
    Util.writeImage(pg_img, new File(String.format("./testResults/%s/pg.png", test)));
    assertImageEquals("Parallel glyphs", ref_img, pg_img);
  }
 public <G, V, A> BufferedImage image(
     Renderer r, Glyphset<G, V> g, Aggregator<V, A> agg, Transfer<? super A, Color> t)
     throws Exception {
   AffineTransform vt = Util.zoomFit(g.bounds(), width, height);
   Selector<G> selector = TouchesPixel.make(g);
   Aggregates<A> aggs = r.aggregate(g, selector, agg, vt, width, height);
   Transfer.Specialized<? super A, Color> t2 = t.specialize(aggs);
   Aggregates<Color> imgAggs = r.transfer(aggs, t2);
   BufferedImage img = AggregateUtils.asImage(imgAggs, width, height, Color.white);
   return img;
 }
 public Specialized(int n, boolean fill, Aggregates<? extends N> aggregates) {
   super(n, fill);
   Util.Stats<N> stats = Util.stats(aggregates, true, true, true);
   double spacing = (stats.max.doubleValue() - stats.min.doubleValue()) / n;
   contourLevels = LocalUtils.steps(stats.min, stats.max, spacing);
 }