org.geowebcache.grid.BoundingBox.java Source code

Java tutorial

Introduction

Here is the source code for org.geowebcache.grid.BoundingBox.java

Source

/**
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @author Chris Whitney
 *  
 */
package org.geowebcache.grid;

import java.io.Serializable;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Locale;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class BoundingBox implements Serializable {

    private static final long serialVersionUID = -2555598825074884627L;

    private static NumberFormat COORD_FORMATTER = NumberFormat.getNumberInstance(Locale.ENGLISH);
    static {
        COORD_FORMATTER.setMinimumFractionDigits(1);
        COORD_FORMATTER.setGroupingUsed(false);
        COORD_FORMATTER.setMaximumFractionDigits(16);
    }

    private static Log log = LogFactory.getLog(org.geowebcache.grid.BoundingBox.class);

    private static String DELIMITER = ",";

    private static double EQUALITYTHRESHOLD = 0.03;

    public static final BoundingBox WORLD4326 = new BoundingBox(-180.0, -90.0, 180.0, 90.0);

    public static final BoundingBox WORLD3857 = new BoundingBox(-20037508.34, -20037508.34, 20037508.34,
            20037508.34);

    // minx, miny, maxx, maxy
    private double[] coords = new double[4];

    BoundingBox() {
        // default constructor for XStream
    }

    public BoundingBox(BoundingBox bbox) {
        coords[0] = bbox.coords[0];
        coords[1] = bbox.coords[1];
        coords[2] = bbox.coords[2];
        coords[3] = bbox.coords[3];
    }

    public BoundingBox(String BBOX) {
        setFromBBOXString(BBOX, 0);
        if (log.isTraceEnabled()) {
            log.trace("Created BBOX: " + getReadableString());
        }
    }

    public BoundingBox(String[] BBOX) {
        setFromStringArray(BBOX);
        if (log.isTraceEnabled()) {
            log.trace("Created BBOX: " + getReadableString());
        }
    }

    public BoundingBox(double minx, double miny, double maxx, double maxy) {
        coords[0] = minx;
        coords[1] = miny;
        coords[2] = maxx;
        coords[3] = maxy;

        if (log.isTraceEnabled()) {
            log.trace("Created BBOX: " + getReadableString());
        }
    }

    public double getMinX() {
        return coords[0];
    }

    public void setMinX(double minx) {
        coords[0] = minx;
    }

    public double getMinY() {
        return coords[1];
    }

    public void setMinY(double miny) {
        coords[1] = miny;
    }

    public double getMaxX() {
        return coords[2];
    }

    public void setMaxX(double maxx) {
        coords[2] = maxx;
    }

    public double getMaxY() {
        return coords[3];
    }

    public void setMaxY(double maxy) {
        coords[3] = maxy;
    }

    /**
     * @return [minx, miny, maxx, maxy]
     */
    public double[] getCoords() {
        return coords.clone();
    }

    public double getWidth() {
        return coords[2] - coords[0];
    }

    public double getHeight() {
        return coords[3] - coords[1];
    }

    /**
     * Sets from an array of strings
     * 
     * @param BBOX
     */
    public void setFromStringArray(String[] BBOX) {
        setFromStringArray(BBOX, 0);
    }

    public void setFromStringArray(String[] BBOX, int recWatch) {
        if (BBOX.length == 4) {
            coords[0] = Double.parseDouble(BBOX[0]);
            coords[1] = Double.parseDouble(BBOX[1]);
            coords[2] = Double.parseDouble(BBOX[2]);
            coords[3] = Double.parseDouble(BBOX[3]);

        } else if (recWatch < 4) {
            setFromBBOXString(BBOX[0], recWatch);
        } else {
            log.error("Doesnt understand " + Arrays.toString(BBOX));
        }
    }

    /**
     * Parses the BBOX parameters from a comma separted value list
     * 
     * @param BBOX
     */
    public void setFromBBOXString(String BBOX, int recWatch) {
        String[] tokens = BBOX.split(DELIMITER);
        setFromStringArray(tokens, recWatch + 1);
    }

    /**
     * Outputs a string suitable for logging and other human-readable tasks
     * 
     * @return a readable string
     */
    public String getReadableString() {
        return "Min X: " + coords[0] + " Min Y: " + coords[1] + " Max X: " + coords[2] + " Max Y: " + coords[3];
    }

    /**
     * Returns a comma separated value String suitable for URL output
     */
    @Override
    public String toString() {
        StringBuilder buff = new StringBuilder(40);
        buff.append(COORD_FORMATTER.format(coords[0]));
        buff.append(',');
        buff.append(COORD_FORMATTER.format(coords[1]));
        buff.append(',');
        buff.append(COORD_FORMATTER.format(coords[2]));
        buff.append(',');
        buff.append(COORD_FORMATTER.format(coords[3]));
        return buff.toString();
    }

    public String toKMLLatLonBox() {
        return "<LatLonBox>" + "<north>" + Double.toString(coords[3]) + "</north>" + "<south>"
                + Double.toString(coords[1]) + "</south>" + "<east>" + Double.toString(coords[2]) + "</east>"
                + "<west>" + Double.toString(coords[0]) + "</west>" + "</LatLonBox>";
    }

    public String toKMLLatLonAltBox() {
        return "<LatLonAltBox>" + "<north>" + Double.toString(coords[3]) + "</north>" + "<south>"
                + Double.toString(coords[1]) + "</south>" + "<east>" + Double.toString(coords[2]) + "</east>"
                + "<west>" + Double.toString(coords[0]) + "</west>" + "</LatLonAltBox>";
    }

    /**
     * Comparing whether the differences between the bounding boxes can be ignored.
     * 
     * @param other
     * @return whether the boxes are equal
     */
    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj.getClass() == this.getClass()) {
            BoundingBox other = (BoundingBox) obj;
            return this.equals(other, EQUALITYTHRESHOLD);
        }
        return false;
    }

    public boolean equals(BoundingBox other, double threshold) {
        return Math.abs(getMinX() - other.getMinX()) < threshold
                && Math.abs(getMinY() - other.getMinY()) < threshold
                && Math.abs(getWidth() - other.getWidth()) < threshold
                && Math.abs(getHeight() - other.getHeight()) < threshold;
    }

    /**
     * Check whether this bbox contains the bbox
     * 
     * @param other
     * @return whether other is contained by this
     */
    public boolean contains(BoundingBox other) {
        return (coords[0] - EQUALITYTHRESHOLD <= other.coords[0] && coords[1] - EQUALITYTHRESHOLD <= other.coords[1]
                && coords[2] + EQUALITYTHRESHOLD >= other.coords[2]
                && coords[3] + EQUALITYTHRESHOLD >= other.coords[3]);
    }

    /**
     * Minimal sanity check
     * 
     * @return whether min x < max x, min y < max y
     */
    public boolean isSane() {
        return (coords[0] < coords[2] && coords[1] < coords[3]);
    }

    public boolean isNull() {
        return (coords[0] > coords[2] || coords[1] > coords[3]);
    }

    @Override
    public int hashCode() {
        return Float.floatToIntBits((float) coords[0]) ^ Float.floatToIntBits((float) coords[1]);
    }

    public boolean intersects(BoundingBox other) {
        if (isNull() || other.isNull()) {
            return false;
        }
        return !(other.getMinX() > getMaxX() || other.getMaxX() < getMinX() || other.getMinY() > getMaxY()
                || other.getMaxY() < getMinY());
    }

    public BoundingBox intersection(BoundingBox bboxB) {
        return intersection(this, bboxB);
    }

    public static BoundingBox intersection(BoundingBox bboxA, BoundingBox bboxB) {
        BoundingBox retBbox = new BoundingBox(0, 0, -1, -1);
        if (bboxA.intersects(bboxB)) {
            for (int i = 0; i < 2; i++) {
                if (bboxA.coords[i] > bboxB.coords[i]) {
                    retBbox.coords[i] = bboxA.coords[i];
                } else {
                    retBbox.coords[i] = bboxB.coords[i];
                }
            }

            for (int i = 2; i < 4; i++) {
                if (bboxA.coords[i] < bboxB.coords[i]) {
                    retBbox.coords[i] = bboxA.coords[i];
                } else {
                    retBbox.coords[i] = bboxB.coords[i];
                }
            }
        }
        return retBbox;
    }

    public void scale(double xFactor, double yFactor) {
        double x = coords[2] - coords[0];
        double xdiff = (x * xFactor - x) / 2;
        double y = coords[3] - coords[1];
        double ydiff = (y * yFactor - y) / 2;

        coords[0] = coords[0] - xdiff;
        coords[1] = coords[1] - ydiff;
        coords[2] = coords[2] + xdiff;
        coords[3] = coords[3] + ydiff;
    }

    public void scale(double factor) {
        scale(factor, factor);
    }
}