/* * PageSize.java * * Created on April 20, 2007, 9:10 PM * */ package ika.gui; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.Vector; /** * PageFormat specifies the map scale, the map size and the map position. * * @author Bernhard Jenny, Institute of Cartography, ETH Zurich */ public class PageFormat implements Cloneable, Serializable { /** * A factor to convert from millimeter to pixels. Assumes 72 pixels per * inch. */ public static final double MM2PX = 72. / 2.54 / 10.; /** * Position of left border of page in world coordinates. */ private double pageLeft = 0; /** * Position of lower border of page in world coordinates. */ private double pageBottom = 0; /** * Width of page in pixels or millimeters. */ private double pageWidth = PageFormatPanel.A4WIDTH * MM2PX; /** * Height of page in pixels or millimeters. */ private double pageHeight = PageFormatPanel.A4HEIGHT * MM2PX; /** * Scale number of the page, which scales world coordinates to page * coordinates in world units (not pixels or mm). */ private double pageScale = 100000.; /** * A vector of PageFormatChangeListener that are informed whenever this * PageFormat changes. */ transient private Vector eventListeners = new Vector(1); /** * If true, the page width and height are in pixels, otherwise in * millimeter. */ private boolean unitPixels = true; /** * If true, the page format is automatically adjusted to include the * complete map. This is only a flag that indicates that an external object * has to update. */ private boolean automatic = true; /** * If true, the outline of the page should be shown in the map. */ private boolean visible = true; /** * Creates a new instance of PageSize */ public PageFormat() { } @Override public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } /** * Custom deserialization to initialize the vector of * PageFormatChangeListeners. */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.eventListeners = new Vector(1); } /** * Register a PageFormatChangeListener. */ public final synchronized void addPageFormatChangeListener( PageFormatChangeListener listener) { if (listener != null && !this.eventListeners.contains(listener)) { this.eventListeners.add(listener); } } /** * Unregister a PageFormatChangeListener. */ public final synchronized void removePageFormatChangeListener( PageFormatChangeListener listener) { this.eventListeners.remove(listener); } /** * Inform each registered MapEventListener about a change. */ protected final synchronized void informListeners() { // Inform listeners in inverse order. This allows listeners to remove // themselves in the called method. for (int i = eventListeners.size() - 1; i >= 0; i--) { PageFormatChangeListener listener = (PageFormatChangeListener) eventListeners.get(i); listener.pageFormatChanged(this); } } /** * Returns the left border of the page in world coordinates. */ public double getPageLeft() { return pageLeft; } /** * Sets the left border of the page in world coordinates. */ public void setPageLeft(double pageLeft) { this.pageLeft = pageLeft; this.informListeners(); } /** * Returns the bottom border of the page in world coordinates. */ public double getPageBottom() { return pageBottom; } /** * Sets the bottom border of the page in world coordinates. */ public void setPageBottom(double pageBottom) { this.pageBottom = pageBottom; this.informListeners(); } /** * Returns the top border of the page in world coordinates. */ public double getPageTop() { return pageBottom + this.getPageHeightWorldCoordinates(); } /** * Returns the right border of the page in world coordinates. */ public double getPageRight() { return pageLeft + this.getPageWidthWorldCoordinates(); } /** * Returns the page width in pixels or millimeter. */ public double getPageWidth() { return pageWidth; } /** * Set the page width in pixels or millimeter. */ public void setPageWidth(double pageWidth) { this.pageWidth = pageWidth; this.informListeners(); } /** * Set the page width in world coordinates. Uses the current pageScale to * compute a height in pixels or mm. */ public void setPageWidthWorldCoordinates(double pageWidth) { // convert from world coordinates to millimeter double w = pageWidth / this.pageScale * 1000.; if (this.unitPixels) { w *= MM2PX; } this.pageWidth = w; this.informListeners(); } /** * Returns the page width in world coordinates. */ public double getPageWidthWorldCoordinates() { // convert from millimeters to world coordinates. double w = this.pageScale * this.pageWidth / 1000.; if (this.unitPixels) { w /= MM2PX; } return w; } /** * Returns the page height in pixels or millimeter. */ public double getPageHeight() { return pageHeight; } /** * Set the page height in pixels or millimeter. */ public void setPageHeight(double pageHeight) { this.pageHeight = pageHeight; this.informListeners(); } /** * Set the page height in world coordinates. Uses the current pageScale to * compute a height in pixels or mm. */ public void setPageHeightWorldCoordinates(double pageHeight) { // convert from world coordinates to millimeter double h = pageHeight / this.pageScale * 1000.; if (this.unitPixels) { h *= MM2PX; } this.pageHeight = h; this.informListeners(); } /** * Returns the page height in world coordinates. */ public double getPageHeightWorldCoordinates() { // convert from millimeters to world coordinates. double h = this.pageScale * this.pageHeight / 1000.; if (this.unitPixels) { h /= MM2PX; } return h; } /** * Returns the page scale. If the user enters "1:100,000", the page scale is * 100,000. */ public double getPageScale() { return pageScale; } /** * Sets the page scale. If the user enters "1:100,000", the page scale is * 100,000 */ public void setPageScale(double pageScale) { this.pageScale = pageScale; this.informListeners(); } /** * Returns the extension of the page in world coordinates. */ public Rectangle2D getPageSizeWorldCoordinates() { final double w = getPageWidthWorldCoordinates(); final double h = getPageHeightWorldCoordinates(); return new Rectangle2D.Double(pageLeft, pageBottom, w, h); } /** * Returns true if the page size is defined in pixels, false if it is * defined in millimeter. */ public boolean isUnitPixels() { return unitPixels; } /** * Returns true if the page size is defined in millimeter, false if it is * defined in pixels. */ public boolean isUnitMillimeter() { return !unitPixels; } /** * Set the unit of page dimension to pixels or millimeter. * * @param unitPixels If true, unit is pixels, if false it is in millimeter. */ public void setUnitPixels(boolean unitPixels) { if (this.unitPixels == unitPixels) { return; } if (unitPixels == true) { this.pageWidth *= MM2PX; this.pageHeight *= MM2PX; } else { this.pageWidth /= MM2PX; this.pageHeight /= MM2PX; } this.unitPixels = unitPixels; } public boolean isAutomatic() { return automatic; } public void setAutomatic(boolean automatic) { this.automatic = automatic; this.informListeners(); } /** * Adjust the position and dimension of the page to include the passed * rectangle. Uses the current pageScale to compute a height and width in * pixels or mm. * * @param bounds */ public void setPageWorldCoordinates(Rectangle2D bounds) { if (bounds == null) { return; } this.pageLeft = bounds.getMinX(); this.pageBottom = bounds.getMinY(); this.setPageHeightWorldCoordinates(bounds.getHeight()); this.setPageWidthWorldCoordinates(bounds.getWidth()); } /** * Adjusts the size of the page to cover the passed bounding box in world * coordinates. Adjust the pageScale such that the page has the passed * height and width in pixels. * * @param boundsWCS The bounding box in world coordinates. * @param width Width of the page in pixels. * @param height Height of the page in pixels. */ public void adjustToRectangle(Rectangle2D boundsWC, double width, double height) { if (boundsWC == null || width <= 0 || height <= 0) { throw new IllegalArgumentException(); } this.unitPixels = true; double vScale = boundsWC.getHeight() / (height / 1000 / MM2PX); double hScale = boundsWC.getWidth() / (width / 1000 / MM2PX); if (vScale > hScale) { this.pageScale = vScale; this.pageLeft = boundsWC.getMinX() - (width / 1000 / MM2PX * vScale - boundsWC.getWidth()) / 2; this.pageBottom = boundsWC.getMinY(); } else { this.pageScale = hScale; this.pageLeft = boundsWC.getMinX(); this.pageBottom = boundsWC.getMinY() - (height / 1000 / MM2PX * hScale - boundsWC.getHeight()) / 2; } this.pageWidth = width; this.pageHeight = height; this.informListeners(); } public boolean isVisible() { return visible; } public void setVisible(boolean visible) { this.visible = visible; this.informListeners(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("PageFormat"); sb.append(" Left: ").append(this.pageLeft); sb.append(" Bottom: ").append(this.pageBottom); sb.append(" Scale: ").append(this.pageScale); sb.append(" Width: ").append(this.pageWidth); sb.append(" Height: ").append(this.pageHeight); sb.append(" Automatic: ").append(this.automatic); sb.append(" Show: ").append(this.visible); return sb.toString(); } }