/** * Creates tile managers from the specified collection of tiles. This method usually returns a * single tile manager, but more could be returned if this factory has been unable to put every * tiles in a single mosaic (for example if the ratio between {@linkplain AffineTransform affine * transform} given to {@linkplain Tile#Tile(ImageReaderSpi,Object,int,Rectangle,AffineTransform) * tile constructor} would lead to fractional {@linkplain Tile#getSubsampling subsampling}). * * @param tiles The tiles to give to a tile manager. * @return A tile manager created from the given tiles. * @throws IOException If an I/O operation was required and failed. */ public TileManager[] create(Collection<Tile> tiles) throws IOException { int count = 0; final TileManager[] managers; if (!hasPendingGridToCRS(tiles)) { /* * There is no tile having a "gridToCRS" transform pending RegionCalculator work. So we * can create (at the end of this method) a single TileManager using all those tiles. */ if (!tiles.isEmpty()) { count = 1; } managers = new TileManager[count]; } else { /* * At least one tile have a pending "gridToCRS" transform (actually we should have * more than one - typically all of them - otherwise the RegionCalculator work will * be useless). Computes their region now. Note that we could execute this block * unconditionally. The 'hasPendingGridToCRS' check we just for avoiding the cost * of creating RegionCalculator in the common case where it is not needed. So it is * not a big deal if 'hasPendingGridToCRS' conservatively returned 'true'. */ final Collection<Tile> remainings = new ArrayList<>(Math.min(16, tiles.size())); final RegionCalculator calculator = new RegionCalculator(); for (final Tile tile : tiles) { if (!calculator.add(tile)) { remainings.add(tile); } } if (!remainings.isEmpty()) { count = 1; } final Map<ImageGeometry, Tile[]> split = calculator.tiles(); managers = new TileManager[split.size() + count]; for (final Map.Entry<ImageGeometry, Tile[]> entry : split.entrySet()) { final TileManager manager = createGeneric(entry.getValue()); manager.setGridGeometry(entry.getKey()); managers[count++] = manager; } tiles = remainings; } /* * The collection now contains tiles that has not been processed by RegionCalculator, * because their 'gridToCRS' transform is flagged as already computed. Create a mosaic * for them, and use the affine transform having the finest resolution as the "global" * one. */ if (!tiles.isEmpty()) { final TileManager manager = createGeneric(tiles.toArray(new Tile[tiles.size()])); final Rectangle imageBounds = new Rectangle(-1, -1); AffineTransform gridToCRS = null; Dimension subsampling = null; double scale = Double.POSITIVE_INFINITY; for (final Tile tile : tiles) { imageBounds.add(tile.getAbsoluteRegion()); final AffineTransform candidate = tile.getGridToCRS(); if (candidate != null && !candidate.equals(gridToCRS)) { final double cs = XAffineTransform.getScale(candidate); if (cs < scale) { // Found a new tile at a finer resolution. scale = cs; gridToCRS = candidate; subsampling = tile.getSubsampling(); } else if (cs == scale) { // Inconsistent transform at the finest level. // Abandon the attempt to create a grid geometry. gridToCRS = null; break; } } } if (gridToCRS != null) { if (subsampling.width != 1 || subsampling.height != 1) { gridToCRS = new AffineTransform(gridToCRS); gridToCRS.scale(subsampling.width, subsampling.height); } manager.setGridGeometry(new ImageGeometry(imageBounds, gridToCRS)); } managers[0] = manager; } return managers; }