package com.revolsys.swing.map.print; import java.awt.geom.Rectangle2D; import java.awt.print.PageFormat; import java.awt.print.Pageable; import java.awt.print.Printable; import javax.measure.Measure; import javax.measure.quantity.Length; import javax.measure.unit.NonSI; import javax.measure.unit.SI; import javax.measure.unit.Unit; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.swing.map.layer.Project; public class MapPageable implements Pageable { private final Rectangle2D.Double contentRect; private double coreCellsPerHeight; private double coreCellsPerWidth; private final int dpi; private final Project map; private BoundingBox mapBoundingBox; private double modelGridSizeMetres = 200; private final double modelPageHeight; private final double modelPageWidth; private final int numPages; private final int numXPages; private final int numYPages; private final PageFormat pageFormat; private final double rulerSizePixels; private final double scale; public MapPageable(final Project map, final BoundingBox boundingBox, final PageFormat pageFormat, final double scale, final int dpi, final double gridSizeMetres) { this.map = map; this.pageFormat = pageFormat; this.scale = scale; this.dpi = dpi; this.modelGridSizeMetres = gridSizeMetres; final Unit<Length> pixelSize = NonSI.INCH.divide(dpi); this.mapBoundingBox = boundingBox; this.rulerSizePixels = Measure.valueOf(0.5, SI.CENTIMETRE).doubleValue(pixelSize); final double modelWidthMetres = this.mapBoundingBox.getWidthLength().doubleValue(SI.METRE); final double modelHeightMetres = this.mapBoundingBox.getWidthLength().doubleValue(SI.METRE); final double printWidthPixels = pageFormat.getImageableWidth() * dpi / 72; final double printHeightPixels = pageFormat.getImageableHeight() * dpi / 72; final double widthPixels = printWidthPixels - 2 * this.rulerSizePixels; final double heightPixels = printHeightPixels - 3 * this.rulerSizePixels; final double pageWidthMetres = Measure.valueOf(widthPixels, pixelSize).doubleValue(SI.METRE); final double pageHeightMetres = Measure.valueOf(heightPixels, pixelSize).doubleValue(SI.METRE); this.modelPageWidth = pageWidthMetres * scale; this.modelPageHeight = pageHeightMetres * scale; final double cellsPerWidth = Math.ceil(pageWidthMetres * scale / this.modelGridSizeMetres); final double cellsPerHeight = Math.ceil(pageHeightMetres * scale / this.modelGridSizeMetres); final double numXCells = Math.ceil(modelWidthMetres / this.modelGridSizeMetres); final double numYCells = Math.ceil(modelHeightMetres / this.modelGridSizeMetres); if (numXCells <= cellsPerWidth - 1) { this.coreCellsPerWidth = cellsPerWidth - 1; } else { this.coreCellsPerWidth = cellsPerWidth - 2; } if (numYCells <= cellsPerHeight - 1) { this.coreCellsPerHeight = cellsPerHeight - 1; } else { this.coreCellsPerHeight = cellsPerHeight - 2; } this.numXPages = (int)Math.ceil(numXCells / this.coreCellsPerWidth); this.numYPages = (int)Math.ceil(numYCells / this.coreCellsPerHeight); final double totalModelWidth = this.numXPages * this.coreCellsPerWidth * this.modelGridSizeMetres; if (this.mapBoundingBox.getWidth() < totalModelWidth) { final double expandDistance = (totalModelWidth - this.mapBoundingBox.getWidth()) / 2; this.mapBoundingBox = this.mapBoundingBox.expand(expandDistance, 0); } final double totalModelHeight = this.numYPages * this.coreCellsPerHeight * this.modelGridSizeMetres; if (this.mapBoundingBox.getHeight() < totalModelHeight) { final double expandDistance = (totalModelHeight - this.mapBoundingBox.getHeight()) / 2; this.mapBoundingBox = this.mapBoundingBox.expand(0, expandDistance); } this.numPages = this.numXPages * this.numYPages; this.contentRect = new Rectangle2D.Double(this.rulerSizePixels, this.rulerSizePixels, widthPixels, heightPixels); } @Override public int getNumberOfPages() { return this.numPages; } @Override public PageFormat getPageFormat(final int pageIndex) { return this.pageFormat; } @Override public Printable getPrintable(final int pageIndex) { final double pageXOffset = (this.modelPageWidth - this.coreCellsPerWidth * this.modelGridSizeMetres) / 2; final double pageYOffset = (this.modelPageHeight - this.coreCellsPerHeight * this.modelGridSizeMetres) / 2; final double startX = Math.floor(this.mapBoundingBox.getMinX() / this.modelGridSizeMetres) * this.modelGridSizeMetres; final double startY = Math.floor(this.mapBoundingBox.getMinY() / this.modelGridSizeMetres) * this.modelGridSizeMetres; final int column = pageIndex % this.numXPages; final int row = this.numYPages - 1 - (int)Math.floor((double)pageIndex / this.numXPages); final double x = startX + column * this.modelGridSizeMetres * this.coreCellsPerWidth - pageXOffset; final double y = startY + row * this.modelGridSizeMetres * this.coreCellsPerHeight - pageYOffset; final BoundingBox pageBoundingBox = this.map.getGeometryFactory().newBoundingBox(x, y, x + this.modelPageWidth, y + this.modelPageHeight); return new MapPrintable(this.map, column, this.numYPages - row, pageBoundingBox, this.contentRect, this.dpi, this.rulerSizePixels, this.modelGridSizeMetres, this.scale); } }