package com.revolsys.swing.map.print; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import javax.measure.Measure; import javax.measure.unit.NonSI; import javax.measure.unit.SI; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.swing.map.layer.LayerGroup; import com.revolsys.swing.map.layer.Project; public class MapPrintable implements Printable { private final BoundingBox boundingBox; private final int column; private final Rectangle2D contentRect; private final int dpi; private double majorDivisions = 1000; private final Project map; private double millimetre = Measure.valueOf(1, SI.MILLIMETRE).doubleValue(NonSI.INCH.divide(72)); private double minorDivisions = 200; private final int row; private final double rulerSizePixels; private final double scale; public MapPrintable(final Project map, final int column, final int row, final BoundingBox boundingBox, final Rectangle2D contentRect, final int dpi, final double rulerSizePixels, final double minorDivisions, final double scale) { this.map = map; this.column = column; this.row = row; this.boundingBox = boundingBox; this.contentRect = contentRect; this.dpi = dpi; this.rulerSizePixels = rulerSizePixels; this.millimetre = Measure.valueOf(1, SI.MILLIMETRE).doubleValue(NonSI.INCH.divide(dpi)); this.minorDivisions = minorDivisions; this.majorDivisions = minorDivisions * 5; this.scale = scale; } private void drawFooter(final Graphics2D graphics2d) { graphics2d.setFont(new Font("Arial", Font.PLAIN, 12)); final String sheetName = (char)('A' + this.column) + "" + this.row; final String text = this.boundingBox.getCoordinateSystem().getCoordinateSystemName() + " - 1:" + this.scale + " - " + sheetName; graphics2d.drawString(text, 0, (float)(this.contentRect.getMaxY() + this.rulerSizePixels * 2)); } private void drawRuler(final PrintViewport2D viewport, final Graphics2D graphics2d) { final double unit = viewport.getModelUnitsPerViewUnit(); final float lineWidth = (float)(unit * this.millimetre / 10); // final boolean savedUseModelCoordinates = viewport.setUseModelCoordinates( // true, graphics2d); try { graphics2d .setStroke(new BasicStroke(lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); final double rulerHeight = unit * this.rulerSizePixels; final double minX = this.boundingBox.getMinX(); final double maxX = this.boundingBox.getMaxX(); final double minY = this.boundingBox.getMinY(); final double maxY = this.boundingBox.getMaxY(); final double width = maxX - minX; final double height = maxY - minY; final int startXIndex = (int)Math.ceil(minX / this.minorDivisions); final int endXIndex = (int)Math.ceil(maxX / this.minorDivisions); final AffineTransform modelToScreenTransform = viewport.getModelToScreenTransform(); for (int i = startXIndex; i < endXIndex; i++) { final double x = i * this.minorDivisions; double currentRulerHeight; if (x % this.majorDivisions < this.minorDivisions) { graphics2d.setColor(Color.BLACK); currentRulerHeight = rulerHeight; // final boolean saved2 = viewport.setUseModelCoordinates(false, // graphics2d); try { graphics2d.setFont(new Font("Arial", Font.PLAIN, 12)); final double[] coord = new double[2]; modelToScreenTransform.transform(new double[] { x + unit * this.millimetre, minY - unit * this.millimetre * 4.5 }, 0, coord, 0, 1); graphics2d.drawString(String.valueOf((int)x), (float)coord[0], (float)coord[1]); modelToScreenTransform.transform(new double[] { x + unit * this.millimetre, maxY + unit * this.millimetre * 2.25 }, 0, coord, 0, 1); graphics2d.drawString(String.valueOf((int)x), (float)coord[0], (float)coord[1]); } finally { // viewport.setUseModelCoordinates(saved2, graphics2d); } } else { graphics2d.setColor(Color.LIGHT_GRAY); currentRulerHeight = rulerHeight / 3; } graphics2d.draw(new Line2D.Double(x, minY - currentRulerHeight, x, minY - lineWidth)); graphics2d.draw(new Line2D.Double(x, maxY + lineWidth, x, maxY + currentRulerHeight)); } final int startYIndex = (int)Math.ceil(minY / this.minorDivisions); final int endYIndex = (int)Math.ceil(maxY / this.minorDivisions); for (int i = startYIndex; i < endYIndex; i++) { final double y = i * this.minorDivisions; double currentRulerHeight; if (y % this.majorDivisions < this.minorDivisions) { graphics2d.setColor(Color.BLACK); currentRulerHeight = rulerHeight; graphics2d.setFont(new Font("Arial", Font.PLAIN, 12)); final double[] coord = new double[2]; // final boolean saved2 = viewport.setUseModelCoordinates(false, // graphics2d); try { modelToScreenTransform.transform(new double[] { minX - unit * this.millimetre * 2.25, y + unit * this.millimetre }, 0, coord, 0, 1); drawString(graphics2d, String.valueOf((int)y), coord[0], coord[1], -Math.PI / 2); modelToScreenTransform.transform(new double[] { maxX + unit * this.millimetre * 4.5, y + unit * this.millimetre }, 0, coord, 0, 1); drawString(graphics2d, String.valueOf((int)y), coord[0], coord[1], -Math.PI / 2); } finally { // viewport.setUseModelCoordinates(saved2, graphics2d); } } else { graphics2d.setColor(Color.LIGHT_GRAY); currentRulerHeight = rulerHeight / 2; } graphics2d.draw(new Line2D.Double(minX - currentRulerHeight, y, minX - lineWidth, y)); graphics2d.draw(new Line2D.Double(maxX + lineWidth, y, maxX + currentRulerHeight, y)); } graphics2d.setColor(Color.BLACK); graphics2d.draw(new Rectangle2D.Double(minX - rulerHeight, minY - rulerHeight, width + 2 * rulerHeight, height + 2 * rulerHeight)); graphics2d.draw(new Rectangle2D.Double(minX - lineWidth, minY - lineWidth, width + lineWidth * 2, height + lineWidth * 2)); } finally { // viewport.setUseModelCoordinates(savedUseModelCoordinates, graphics2d); } } private void drawString(final Graphics2D graphics2d, final String label, final double x, final double y, final double rotation) { final AffineTransform savedTransform = graphics2d.getTransform(); graphics2d.translate(x, y); graphics2d.rotate(rotation); graphics2d.drawString(label, 0, 0); graphics2d.setTransform(savedTransform); } @Override public int print(final Graphics graphics, final PageFormat pageFormat, final int pageIndex) throws PrinterException { final Graphics2D graphics2d = (Graphics2D)graphics; final PrintViewport2D viewport = new PrintViewport2D(this.map, graphics2d, pageFormat, this.boundingBox, this.contentRect, this.dpi); graphics2d.translate(pageFormat.getImageableX() * this.dpi / 72.0, pageFormat.getImageableX() * this.dpi / 72.0); drawFooter(graphics2d); graphics2d.translate(this.contentRect.getMinX(), this.contentRect.getMinY()); drawRuler(viewport, graphics2d); graphics2d.clip( new Rectangle2D.Double(0, 0, this.contentRect.getWidth(), this.contentRect.getHeight())); final LayerGroup map = viewport.getProject(); map.getRenderer().render(viewport); final double unit = viewport.getModelUnitsPerViewUnit(); final float lineWidth = (float)(unit * this.millimetre / 5); // final boolean saved = viewport.setUseModelCoordinates(true, graphics2d); try { graphics2d .setStroke(new BasicStroke(lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); final double minX = this.boundingBox.getMinX(); final double maxX = this.boundingBox.getMaxX(); final double minY = this.boundingBox.getMinY(); final double maxY = this.boundingBox.getMaxY(); final int startXIndex = (int)Math.ceil(minX / this.majorDivisions); final int endXIndex = (int)Math.ceil(maxX / this.majorDivisions); graphics2d.setColor(Color.GRAY); for (int i = startXIndex; i < endXIndex; i++) { final double x = i * this.majorDivisions; graphics2d.draw(new Line2D.Double(x, minY, x, maxY)); } final int startYIndex = (int)Math.ceil(minY / this.majorDivisions); final int endYIndex = (int)Math.ceil(maxY / this.majorDivisions); for (int i = startYIndex; i < endYIndex; i++) { final double y = i * this.majorDivisions; graphics2d.draw(new Line2D.Double(minX, y, maxX, y)); } } finally { // viewport.setUseModelCoordinates(saved, graphics2d); } return PAGE_EXISTS; } }