Clip.java Source code

Java tutorial

Introduction

Here is the source code for Clip.java

Source

//revised from prefuse display;

import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.logging.Logger;

/**
 * Represents a clipping rectangle in a prefuse <code>Display</code>.
 *
 * @author <a href="http://jheer.org">jeffrey heer</a>
 */
public class Clip {

    private static final byte EMPTY = 0;
    private static final byte INUSE = 1;
    private static final byte INVALID = 2;

    private double[] clip = new double[8];
    private byte status = INVALID;

    /**
     * Reset the clip to an empty status.
     */
    public void reset() {
        status = EMPTY;
    }

    /**
     * Invalidate the clip. In this state, the clip contents have no meaning.
     */
    public void invalidate() {
        status = INVALID;
    }

    /**
     * Set the clip contents, and set the status to valid and in use.
     * @param c the clip whose contents should be copied
     */
    public void setClip(Clip c) {
        status = INUSE;
        System.arraycopy(c.clip, 0, clip, 0, clip.length);
    }

    /**
     * Set the clip contents, and set the status to valid and in use.
     * @param r the clip contents to copy
     */
    public void setClip(Rectangle2D r) {
        setClip(r.getX(), r.getY(), r.getWidth(), r.getHeight());
    }

    /**
     * Set the clip contents, and set the status to valid and in use.
     * @param x the minimum x-coordinate
     * @param y the minimum y-coorindate
     * @param w the clip width
     * @param h the clip height
     */
    public void setClip(double x, double y, double w, double h) {
        status = INUSE;
        clip[0] = x;
        clip[1] = y;
        clip[6] = x + w;
        clip[7] = y + h;
    }

    /**
     * Transform the clip contents. A new clip region will be created
     * which is the bounding box of the transformed region.
     * @param at the affine transform
     */
    public void transform(AffineTransform at) {
        // make the extra corner points valid
        clip[2] = clip[0];
        clip[3] = clip[7];
        clip[4] = clip[6];
        clip[5] = clip[1];

        // transform the points
        at.transform(clip, 0, clip, 0, 4);

        // make safe against rotation
        double xmin = clip[0], ymin = clip[1];
        double xmax = clip[6], ymax = clip[7];
        for (int i = 0; i < 7; i += 2) {
            if (clip[i] < xmin)
                xmin = clip[i];
            if (clip[i] > xmax)
                xmax = clip[i];
            if (clip[i + 1] < ymin)
                ymin = clip[i + 1];
            if (clip[i + 1] > ymax)
                ymax = clip[i + 1];
        }
        clip[0] = xmin;
        clip[1] = ymin;
        clip[6] = xmax;
        clip[7] = ymax;
    }

    /**
     * Limit the clip such that it fits within the specified region.
     * @param x1 the minimum x-coordinate
     * @param y1 the minimum y-coorindate
     * @param x2 the maximum x-coordinate
     * @param y2 the maximum y-coorindate
     */
    public void limit(double x1, double y1, double x2, double y2) {
        clip[0] = Math.max(clip[0], x1);
        clip[1] = Math.max(clip[1], y1);
        clip[6] = Math.min(clip[6], x2);
        clip[7] = Math.min(clip[7], y2);
    }

    /**
     * Indicates if this Clip intersects the given rectangle expanded
     * by the additional margin pace.
     * @param r the rectangle to test for intersect
     * @param margin additional margin "bleed" to include in the intersection
     * @return true if the clip intersects the expanded region, false otherwise
     */
    public boolean intersects(Rectangle2D r, double margin) {
        double tw = clip[6] - clip[0];
        double th = clip[7] - clip[1];
        double rw = r.getWidth();
        double rh = r.getHeight();
        if (rw < 0 || rh < 0 || tw < 0 || th < 0) {
            return false;
        }
        double tx = clip[0];
        double ty = clip[1];
        double rx = r.getX() - margin;
        double ry = r.getY() - margin;
        rw += rx + 2 * margin;
        rh += ry + 2 * margin;
        tw += tx;
        th += ty;
        //      overflow || intersect
        return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry));
    }

    /**
     * Union this clip with another clip. As a result, this clip
     * will become a bounding box around the two original clips.
     * @param c the clip to union with
     */
    public void union(Clip c) {
        if (status == INVALID)
            return;
        if (status == EMPTY) {
            setClip(c);
            status = INUSE;
            return;
        }
        clip[0] = Math.min(clip[0], c.clip[0]);
        clip[1] = Math.min(clip[1], c.clip[1]);
        clip[6] = Math.max(clip[6], c.clip[6]);
        clip[7] = Math.max(clip[7], c.clip[7]);
    }

    /**
     * Union this clip with another region. As a result, this clip
     * will become a bounding box around the two original regions.
     * @param r the rectangle to union with
     */
    public void union(Rectangle2D r) {
        if (status == INVALID)
            return;

        double minx = r.getMinX();
        double miny = r.getMinY();
        double maxx = r.getMaxX();
        double maxy = r.getMaxY();

        if (Double.isNaN(minx) || Double.isNaN(miny) || Double.isNaN(maxx) || Double.isNaN(maxy)) {
            Logger.getLogger(getClass().getName()).warning("Union with invalid clip region: " + r);
            return;
        }

        if (status == EMPTY) {
            setClip(r);
            status = INUSE;
            return;
        }
        clip[0] = Math.min(clip[0], minx);
        clip[1] = Math.min(clip[1], miny);
        clip[6] = Math.max(clip[6], maxx);
        clip[7] = Math.max(clip[7], maxy);
    }

    /**
     * Union this clip with another region. As a result, this clip
     * will become a bounding box around the two original regions.
     * @param x the x-coordinate of the region to union with
     * @param y the y-coordinate of the region to union with
     * @param w the width of the region to union with
     * @param h the height of the region to union with
     */
    public void union(double x, double y, double w, double h) {
        if (status == INVALID)
            return;
        if (status == EMPTY) {
            setClip(x, y, w, h);
            status = INUSE;
            return;
        }
        clip[0] = Math.min(clip[0], x);
        clip[1] = Math.min(clip[1], y);
        clip[6] = Math.max(clip[6], x + w);
        clip[7] = Math.max(clip[7], y + h);
    }

    /**
     * Intersect this clip with another region. As a result, this
     * clip will become the intersecting area of the two regions.
     * @param c the clip to intersect with
     */
    public void intersection(Clip c) {
        if (status == INVALID)
            return;
        if (status == EMPTY) {
            setClip(c);
            status = INUSE;
            return;
        }
        clip[0] = Math.max(clip[0], c.clip[0]);
        clip[1] = Math.max(clip[1], c.clip[1]);
        clip[6] = Math.min(clip[6], c.clip[6]);
        clip[7] = Math.min(clip[7], c.clip[7]);
    }

    /**
     * Intersect this clip with another region. As a result, this
     * clip will become the intersecting area of the two regions.
     * @param r the rectangle to intersect with
     */
    public void intersection(Rectangle2D r) {
        if (status == INVALID)
            return;
        if (status == EMPTY) {
            setClip(r);
            status = INUSE;
            return;
        }
        clip[0] = Math.max(clip[0], r.getMinX());
        clip[1] = Math.max(clip[1], r.getMinY());
        clip[6] = Math.min(clip[6], r.getMaxX());
        clip[7] = Math.min(clip[7], r.getMaxY());
    }

    /**
     * Intersect this clip with another region. As a result, this
     * clip will become the intersecting area of the two regions.
     * @param x the x-coordinate of the region to intersect with
     * @param y the y-coordinate of the region to intersect with
     * @param w the width of the region to intersect with
     * @param h the height of the region to intersect with
     */
    public void intersection(double x, double y, double w, double h) {
        if (status == INVALID)
            return;
        if (status == EMPTY) {
            setClip(x, y, w, h);
            status = INUSE;
            return;
        }
        clip[0] = Math.max(clip[0], x);
        clip[1] = Math.max(clip[1], y);
        clip[6] = Math.min(clip[6], x + w);
        clip[7] = Math.min(clip[7], y + h);
    }

    /**
     * Minimally expand the clip such that each coordinate is an integer.
     */
    public void expandToIntegerLimits() {
        clip[0] = Math.floor(clip[0]);
        clip[1] = Math.floor(clip[1]);
        clip[6] = Math.ceil(clip[6]);
        clip[7] = Math.ceil(clip[7]);
    }

    /**
     * Expand the clip in all directions by the given value.
     * @param b the value to expand by
     */
    public void expand(double b) {
        clip[0] -= b;
        clip[1] -= b;
        clip[6] += b;
        clip[7] += b;
    }

    /**
     * Grow the clip width and height by the given value. The minimum
     * coordinates will be unchanged.
     * @param b the value to grow the width and height by
     */
    public void grow(double b) {
        clip[6] += b;
        clip[7] += b;
    }

    /**
     * Get the minimum x-coordinate.
     * @return the minimum x-coordinate
     */
    public double getMinX() {
        return clip[0];
    }

    /**
     * Get the minimum y-coordinate.
     * @return the minimum y-coordinate
     */
    public double getMinY() {
        return clip[1];
    }

    /**
     * Get the maximum x-coordinate.
     * @return the maximum x-coordinate
     */
    public double getMaxX() {
        return clip[6];
    }

    /**
     * Get the maximum y-coordinate.
     * @return the maximum y-coordinate
     */
    public double getMaxY() {
        return clip[7];
    }

    /**
     * Get the clip's width
     * @return the clip width
     */
    public double getWidth() {
        return clip[6] - clip[0];
    }

    /**
     * Get the clip's height
     * @return the clip height
     */
    public double getHeight() {
        return clip[7] - clip[1];
    }

    /**
     * Indicates if the clip is set to an empty status.
     * @return true if the clip is set to empty, false otherwise
     */
    public boolean isEmpty() {
        return status == EMPTY;
    }

    /**
     * Indicates if the clip is set to an invalid status.
     * @return true if the clip is set to invalid, false otherwise
     */
    public boolean isInvalid() {
        return status == INVALID;
    }

    // ------------------------------------------------------------------------

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object o) {
        if (o instanceof Rectangle2D) {
            Rectangle2D r = (Rectangle2D) o;
            return (r.getMinX() == clip[0] && r.getMinY() == clip[1] && r.getMaxX() == clip[6]
                    && r.getMaxY() == clip[7]);
        } else if (o instanceof Clip) {
            Clip r = (Clip) o;
            if (r.status == status) {
                if (status == Clip.INUSE)
                    return (r.clip[0] == clip[0] && r.clip[1] == clip[1] && r.clip[6] == clip[6]
                            && r.clip[7] == clip[7]);
                else
                    return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * @see java.lang.Object#toString()
     */
    public String toString() {
        StringBuffer sb = new StringBuffer(20);
        sb.append("Clip[");
        switch (status) {
        case INVALID:
            sb.append("invalid");
            break;
        case EMPTY:
            sb.append("empty");
            break;
        default:
            sb.append(clip[0]).append(",");
            sb.append(clip[1]).append(",");
            sb.append(clip[6]).append(",");
            sb.append(clip[7]);
        }
        sb.append("]");
        return sb.toString();
    }

} // end of class Clip