@Test public void testBinStringification () { BinIndex b = new BinIndex(23, 41); String bs = b.toString(); Assert.assertEquals("[23, 41]", bs); BinIndex b2 = BinIndex.fromString(bs); Assert.assertEquals(b, b2); }
@Override public boolean equals (Object obj) { if (this == obj) return true; if (null == obj) return false; if (!(obj instanceof TileAndBinIndices)) return false; TileAndBinIndices tb = (TileAndBinIndices) obj; if (!_tile.equals(tb.getTile())) return false; if (!_bin.equals(tb.getBin())) return false; return true; } }
static public AnnotationTile getTileFromJSON( JSONObject json ) throws IllegalArgumentException { try { TileIndex index = new TileIndex( json.getInt("level"), json.getInt("x"), json.getInt("y"), AnnotationIndexer.NUM_BINS, AnnotationIndexer.NUM_BINS ); // create tile with empty bins DenseTileData<AnnotationBin> tile = new DenseTileData<>( index ); // for all binkeys Iterator<?> binKeys = json.keys(); while( binKeys.hasNext() ) { String binKey = (String)binKeys.next(); if( json.get(binKey) instanceof JSONObject ){ JSONObject bin = (JSONObject)json.get(binKey); BinIndex binIndex = BinIndex.fromString( binKey ); tile.setBin( binIndex.getX(), binIndex.getY(), getBinFromJSON( bin )); } } return new AnnotationTile( tile.getDefinition(), tile.getData() ); } catch ( Exception e ) { throw new IllegalArgumentException( e ); } }
/** * Converts from a string to a bin index. This takes in strings of exactly * the form output by {@link #toString()} - i.e., formatted with "[%d, %d]" */ public static BinIndex fromString (String string) { try { int a = string.indexOf('[')+1; int b = string.indexOf(',', a); int x = Integer.parseInt(string.substring(a, b).trim()); a = b+1; b = string.indexOf(']', a); int y = Integer.parseInt(string.substring(a+1, b).trim()); return new BinIndex(x, y); } catch (NumberFormatException e) { return null; } catch (IndexOutOfBoundsException e) { return null; } } }
static public JSONObject tileToJSON( AnnotationTile tile ) { JSONObject tileJSON = new JSONObject(); try { tileJSON.put("level", tile.getDefinition().getLevel() ); tileJSON.put("x", tile.getDefinition().getX() ); tileJSON.put("y", tile.getDefinition().getY() ); for (int i=0; i<tile.getDefinition().getXBins(); i++ ) { for (int j=0; j<tile.getDefinition().getYBins(); j++ ) { AnnotationBin bin = tile.getBin(i, j); if ( bin != null) { // add bin object to tile tileJSON.put( new BinIndex(i, j).toString(), binToJSON( bin ) ); } } } } catch ( Exception e ) { e.printStackTrace(); } return tileJSON; }
@Test public void testBinComparison () { BinIndex b0 = new BinIndex(0, 0); BinIndex b1 = new BinIndex(1, 0); Assert.assertTrue(-1 == b0.compareTo(b1)); Assert.assertTrue(1 == b1.compareTo(b0)); b0 = new BinIndex(0, 0); b1 = new BinIndex(0, 1); Assert.assertTrue(-1 == b0.compareTo(b1)); Assert.assertTrue(1 == b1.compareTo(b0)); b0 = new BinIndex(0, 0); b1 = new BinIndex(0, 0); Assert.assertTrue(0 == b0.compareTo(b1)); Assert.assertTrue(0 == b1.compareTo(b0)); bins.add(new BinIndex(2, 1)); bins.add(new BinIndex(2, 0)); bins.add(new BinIndex(0, 1)); bins.add(new BinIndex(1, 1)); bins.add(new BinIndex(1, 2)); bins.add(new BinIndex(1, 0)); bins.add(new BinIndex(0, 2)); bins.add(new BinIndex(0, 0)); bins.add(new BinIndex(2, 2)); Assert.assertEquals(new BinIndex(0, 0), bins.get(0)); Assert.assertEquals(new BinIndex(1, 0), bins.get(1)); Assert.assertEquals(new BinIndex(2, 0), bins.get(2));
@Override public String toString () { return _tile.toString()+":"+_bin.toString(); }
@Override public int hashCode() { return _tile.hashCode()+7*_bin.hashCode(); }
@Override public TileAndBinIndices next () { int tileX = (int) Math.floor(_curBinX/_numXBins); int tileY = (int) Math.floor(_curBinY/_numYBins); TileIndex tile = new TileIndex(_level, tileX, tileY, _numXBins, _numYBins); int binX = _curBinX-_numXBins*tileX; int binY = _curBinY-_numYBins*tileY; BinIndex bin = new BinIndex(binX, _numYBins-1-binY); ++_curBinX; if (_curBinX > _maxBinX) { _curBinX = _minBinX; ++_curBinY; } return new TileAndBinIndices(tile, bin); }
@Override public double getBinOverlap (TileIndex tile, BinIndex bin, Rectangle2D area) { Point2D lowerLeftRoot = new Point2D.Double(area.getMinX(), area.getMinY()); Point2D lowerLeftMercator = rootToTileMercator(lowerLeftRoot, tile.getLevel()); double left = (lowerLeftMercator.getX()-tile.getX())*tile.getXBins()-bin.getX(); double bottom = (tile.getYBins()-1) - (lowerLeftMercator.getY()-tile.getY())*tile.getYBins() - bin.getY(); Point2D upperRightRoot = new Point2D.Double(area.getMaxX(), area.getMaxY()); Point2D upperRightMercator = rootToTileMercator(upperRightRoot, tile.getLevel()); double right = (upperRightMercator.getX()-tile.getX())*tile.getXBins()-bin.getX(); double top = (tile.getYBins()-1) - (upperRightMercator.getY() - tile.getY())*tile.getYBins() - bin.getY(); // Top and bottom actually reversed, but since we take absolute values, it doesn't really matter. left = Math.min(Math.max(left, 0.0), 1.0); right = Math.min(Math.max(right, 0.0), 1.0); top = Math.min(Math.max(top, -1.0), 0.0); bottom = Math.min(Math.max(bottom, -1.0), 0.0); return Math.abs((right-left) * (top-bottom)); }
int uniBinX = Math.min(Math.max(bin.getX(), 0), pow2*xBins-1); // restrict uni X bin to valid range tileX = uniBinX/xBins; tileLeft = tileX * xBins; int uniBinY = Math.min(Math.max(bin.getY(), 0), pow2*yBins-1); // restrict uni Y bin to valid range tileY = pow2 - uniBinY/yBins - 1; tileTop = (pow2 - tileY - 1) * yBins; BinIndex tileBin = new BinIndex(uniBinX - tileLeft, uniBinY - tileTop); TileIndex tile = new TileIndex(level, tileX, tileY, xBins, yBins);
@Override public BinIndex rootToBin (Point2D point, TileIndex tile) { Point2D tileMercator = rootToTileMercator(point, tile.getLevel()); return new BinIndex((int) Math.floor((tileMercator.getX()-tile.getX())*tile.getXBins()), tile.getYBins()-1-(int) Math.floor((tileMercator.getY()-tile.getY())*tile.getYBins())); }
@Override public Rectangle2D getBinBounds(TileIndex tile, BinIndex bin) { long pow2 = 1L << tile.getLevel(); double tileXSize = (_maxX-_minX)/pow2; double tileYSize = (_maxY-_minY)/pow2; double binXSize = tileXSize/tile.getXBins(); double binYSize = tileYSize/tile.getYBins(); int adjustedBinY = tile.getYBins()-1-bin.getY(); return new Rectangle2D.Double(_minX+tileXSize*tile.getX()+binXSize*bin.getX(), _minY+tileYSize*tile.getY()+binYSize*adjustedBinY, binXSize, binYSize); }
/** * Translates from a bin relative to the root position of this tile, to a * bin relative to the root position of the entire data set. * * @param tile * The tile in which this bin falls * @param bin * The bin relative to the root position of this tile (with * coordinates [0 to getXBins(), 0 to getYBins()]) * @return The bin relative to the root position of the entire data set * (with coordinates [0 to getXBins()*2^level, 0 to * getYBins()*2^level]) */ public static BinIndex tileBinIndexToUniversalBinIndex (TileIndex tile, BinIndex bin) { // Tiles go from lower left to upper right // Bins go from upper left to lower right int pow2 = 1 << tile.getLevel(); int tileLeft, tileTop; int xBins = tile.getXBins(); tileLeft = tile.getX() * xBins; int yBins = tile.getYBins(); tileTop = (pow2 - tile.getY() - 1) * yBins; return new BinIndex(tileLeft + bin.getX(), tileTop + bin.getY()); }
@Override public BinIndex rootToBin (double x, double y, TileIndex tile) { Point2D tileMercator = rootToTileMercator(x, y, tile.getLevel()); return new BinIndex((int) Math.floor((tileMercator.getX()-tile.getX())*tile.getXBins()), tile.getYBins()-1-(int) Math.floor((tileMercator.getY()-tile.getY())*tile.getYBins())); }
private Map<Integer, Map> parseAggregations(Histogram date_agg, TileIndex tileIndex) { List<? extends Histogram.Bucket> dateBuckets = date_agg.getBuckets(); Map<Integer, Map> result = new HashMap<>(); long maxval = 0; for (Histogram.Bucket dateBucket : dateBuckets) { Histogram cluster_agg = dateBucket.getAggregations().get("yField"); List<? extends Histogram.Bucket> clusterBuckets = cluster_agg.getBuckets(); BinIndex xBinIndex = tilePyramid.rootToBin(dateBucket.getKeyAsNumber().doubleValue(), 0, tileIndex); int xBin = xBinIndex.getX(); Map<Integer,Long> intermediate = new HashMap<>(); result.put(xBin, intermediate); for( Histogram.Bucket clusterBucket : clusterBuckets) { //given the bin coordinates, see if there's any data in those bins, add values to existing bins BinIndex binIndex = tilePyramid.rootToBin(dateBucket.getKeyAsNumber().doubleValue(), clusterBucket.getKeyAsNumber().doubleValue(), tileIndex); int yBin = binIndex.getY(); if (result.containsKey(xBin) && result.get(xBin).containsKey(yBin)) { intermediate.put(yBin, (long) intermediate.get(yBin) + clusterBucket.getDocCount()); } else if (result.containsKey(xBin) && !(intermediate.containsKey(yBin))) { intermediate.put(yBin, clusterBucket.getDocCount()); } if (maxval < clusterBucket.getDocCount()){ maxval = clusterBucket.getDocCount(); } } } return result; }
List<Integer> expected = topTile.getBin(x, y); List<Integer> actual = null; BinIndex baseTopUBin = TileIndex.tileBinIndexToUniversalBinIndex(topIdx, new BinIndex(x, y)); BinIndex baseUBin = new BinIndex(baseTopUBin.getX() * lf, baseTopUBin.getY() * lf); TileIndex baseTile = new TileIndex(b, 0, 0); for (int rx = 0; rx < lf; ++rx) { for (int ry = 0; ry < lf; ++ry) { BinIndex bin = new BinIndex(baseUBin.getX() + rx, baseUBin.getY() + ry); TileAndBinIndices tbi = TileIndex.universalBinIndexToTileBinIndex(baseTile, bin); TileData<List<Integer>> subTile = allTiles.get(b).get(tbi.getTile()); if (null != subTile) { List<Integer> subBin = subTile.getBin(tbi.getBin().getX(), tbi.getBin().getY()); actual = addLists(actual, subBin);