home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 18.2 KB | 540 lines |
- /*
- * @(#)Area.java 1.18 98/03/18
- *
- * Copyright 1997, 1998 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
- */
-
- /*
- * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
- * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
- *
- * The original version of this source code and documentation is
- * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
- * of IBM. These materials are provided under terms of a License
- * Agreement between Taligent and Sun. This technology is protected
- * by multiple US and International patents.
- *
- * This notice and attribution to Taligent may not be removed.
- * Taligent is a registered trademark of Taligent, Inc.
- *
- */
-
- package java.awt.geom;
-
- import java.awt.Polygon;
- import java.awt.Rectangle;
- import java.awt.Shape;
-
- import sun.awt.Albert.TGrafMatrix;
- import sun.awt.Albert.TGCurve;
- import sun.awt.Albert.TGEllipse;
- import sun.awt.Albert.TGLoop;
- import sun.awt.Albert.TGPoint;
- import sun.awt.Albert.TGPolygon;
- import sun.awt.Albert.TGRect;
- import sun.awt.Albert.TEllipseGeometry;
- import sun.awt.Albert.TLoopGeometry;
- import sun.awt.Albert.TPolygonGeometry;
- import sun.awt.Albert.TRectGeometry;
- import sun.awt.Albert.TCAGRoot;
- import sun.awt.Albert.TOutlineMakerVertexEngine;
- import sun.awt.Albert.TPathExtractor;
- import sun.awt.Albert.TSamplingExtractor;
- import sun.awt.Albert.MAreaGeometry;
- import sun.awt.Albert.AreaPathIterator;
-
- //--+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
- /**
- * Area is a device-independent specification of an arbitrarily-shaped area.
- * The Area object is defined as an object that performs certain binary CAG
- * (Constructive Area Geometry) operations on other area-enclosing geometries,
- * such as rectangles, ellipses, and polygons. The CAG operations are
- * Add(union), Subtract, Intersect, and ExclusiveOR. For instance, an Area
- * can be made up of the area of a rectangle minus the area of an ellipse.
- */
- public class Area implements Shape, Cloneable {
-
- /* ________________________________________________________________________
- * Constructors
- */
-
- /**
- * Default constructor which creates an empty area.
- */
- public Area() {
- }
-
- /**
- * Creates an area geometry from the specified Shape object.
- * The geometry is explicitly closed, if the shape is not already closed.
- * The fill rule (even-odd or winding) specified by the shape
- * geometry is used to determined the resulting enclosed area.
- * @param g The shape from which the area is to be constructed.
- */
- public Area(Shape g) {
- if (g == null)
- return;
-
- if (this.getClass().equals(g.getClass())) { // it's an Area!!
- fGeometry = ((Area)g).fGeometry;
- return;
- }
-
- TGCurve theCurve = new TGCurve();
- double tmp[] = new double[6]; // array of points
- TGPoint close = new TGPoint();
- TGPoint lastP = new TGPoint();
- TGPoint nextP = new TGPoint();
- TGPoint tmpP = null;
- PathIterator i = g.getPathIterator(null);
- for (; !i.isDone(); i.next()) {
- switch (i.currentSegment(tmp)) {
- default:
- case PathIterator.SEG_MOVETO:
- lastP.x = tmp[0];
- lastP.y = tmp[1];
- close.copyFrom(lastP);
- break;
- case PathIterator.SEG_LINETO:
- nextP.x = tmp[0];
- nextP.y = tmp[1];
- theCurve.concatenate(new TGCurve(lastP, nextP));
- tmpP = lastP; lastP = nextP; nextP = tmpP;
- break;
- case PathIterator.SEG_QUADTO:
- nextP.x = tmp[2];
- nextP.y = tmp[3];
- tmpP = new TGPoint(tmp[0], tmp[1]);
- theCurve.concatenate(new TGCurve(lastP, tmpP, nextP));
- tmpP = lastP; lastP = nextP; nextP = tmpP;
- break;
- case PathIterator.SEG_CUBICTO:
- nextP.x = tmp[4];
- nextP.y = tmp[5];
- tmpP = new TGPoint(tmp[0], tmp[1]);
- TGPoint p23 = new TGPoint(tmp[2], tmp[3]);
- theCurve.concatenate(new TGCurve(lastP, tmpP, p23, nextP));
- tmpP = lastP; lastP = nextP; nextP = tmpP;
- break;
- case PathIterator.SEG_CLOSE:
- theCurve.concatenate(new TGCurve(lastP, close));
- lastP.copyFrom(close);
- break;
- }
- }
- boolean EOFill = (i.getWindingRule() == PathIterator.WIND_EVEN_ODD);
- TGLoop geometry = new TGLoop(theCurve, EOFill);
- fGeometry = new TLoopGeometry(geometry);
- }
-
- /**
- * Creates an area geometry from the specified polygon.
- * Even-odd fill rule is assumed as per the definition of the
- * java.awt.Polygon class.
- * @param geometry The polygon from which the area is to be
- * constructed.
- */
- public Area(Polygon geometry) {
- TGPolygon temp = new TGPolygon(geometry);
- if ((temp.getNumberOfPoints() == 4) && temp.isRectilinear() &&
- temp.getPoint(0).equals(temp.getPoint(2)) &&
- temp.getPoint(1).equals(temp.getPoint(3)))
- fGeometry = new TRectGeometry(temp.getBounds());
- else
- fGeometry = new TPolygonGeometry(temp);
- }
-
- /**
- * Creates an area geometry from the specified rectangle.
- * @param r The rectangle from which the area is to be constructed.
- */
- public Area(Rectangle2D r) {
- TGRect geometry = new TGRect(r);
- fGeometry = new TRectGeometry(geometry);
- }
-
- /**
- * Creates an area geometry of a ellipse inside the specified rectangle.
- * @param e The ellipse geometry from which the area is to be
- * constructed
- */
- public Area(Ellipse2D e) {
- fGeometry = new TEllipseGeometry(new TGEllipse(new TGRect(e)));
- }
-
- /* ________________________________________________________________________
- * computational geometry functions
- */
-
- /**
- * Transforms the geometry of this Area using the specified transform.
- * The geometry is transformed in place permanently changing the
- * enclosed area defined by this object.
- * @param t The matrix used to transform the area.
- */
- public void transform(AffineTransform t) {
- TGrafMatrix matrix = new TGrafMatrix(t);
- if ((fGeometry != null) && !matrix.isIdentity())
- fGeometry = fGeometry.cloneAndTransform(matrix);
- }
-
- /**
- * Removes all the basic geometry from this area and restores it to
- * an empty area.
- */
- public void reset() {
- fGeometry = null;
- }
-
- /**
- * Tests whether this area contains any geometry.
- * @return True if this area contains no basic geometry, or is an
- * empty area.
- */
- public boolean isEmpty() {
- return (fGeometry == null) || fGeometry.isEmpty();
- }
-
- /**
- * Tests whether the area consists entirely of straight edged
- * polygonal geometry.
- * @return True if the area consists completely of polygon edges
- */
- public boolean isPolygonal() {
- return (fGeometry == null) || fGeometry.isPolygonal();
- }
-
- /**
- * Tests whether the area is rectangular in shape.
- * @return True if the area is rectangular in shape.
- */
- public boolean isRectangular() {
- return (fGeometry == null) || fGeometry.isRectangular();
- }
-
- /**
- * Tests whether the area is comprised of a single basic geometry.
- * @return True if the area is comprised of a single basic geometry.
- */
- public boolean isSingular() {
- return (fGeometry == null) || fGeometry.isSingular();
- }
-
- /**
- * Returns a bounding rectangle that completely encloses the area.
- * @return The bounding rectangle for the area.
- */
- public Rectangle getBounds() {
- return internalGetBounds().getBounds();
- }
-
- /**
- * Returns a high precision bounding rectangle that completely
- * encloses the area.
- * @return The bounding rectangle for the area.
- */
- public Rectangle2D getBounds2D() {
- return internalGetBounds();
- }
-
- /**
- * Tests whether the interior of the area intersects the interior
- * of the given rectangle.
- * @return True if the interior intersects the given rectangle.
- */
- public boolean intersects(double x, double y, double w, double h) {
- TGRect rect = new TGRect(x, y, x + w, y + h);
- return ((fGeometry != null) &&
- (fGeometry.intersects(rect) ||
- fGeometry.contains(rect)));
- }
-
- /**
- * Tests whether the interior of the area intersects the interior
- * of the given rectangle.
- * @param r The rectangle to test for intersection.
- * @return True if the interior intersects the given rectangle.
- */
- public boolean intersects(Rectangle2D r) {
- TGRect rect = new TGRect(r);
- return (fGeometry != null) && fGeometry.intersects(rect);
- }
-
- /**
- * Tests if a given coordinate lies inside the boundary of the shape.
- * @param x x value of the point
- * @param y y value of the point
- * @return True if the point lies completely within the interior
- * of the area
- */
- public boolean contains(double x, double y) {
- TGPoint pt = new TGPoint(x, y);
- return (fGeometry != null) && fGeometry.contains(pt);
- }
-
- /**
- * Tests if a given coordinate lies inside the boundary of the shape.
- * @param p The point to test for inclusion within the area.
- * @return True if the point lies completely within the interior
- * of the area
- */
- public boolean contains(Point2D p) {
- TGPoint pt = new TGPoint(p);
- return (fGeometry != null) && fGeometry.contains(pt);
- }
-
- /**
- * Tests whether the interior of the area completely contains the
- * given rectangle.
- * @return True if the rectangle lies completely within the interior
- * of the area
- */
- public boolean contains(double x, double y, double w, double h) {
- TGRect rect = new TGRect(x, y, x + w, y + h);
- return (fGeometry != null) && fGeometry.contains(rect);
- }
-
- /**
- * Tests whether the interior of the area completely contains the
- * given rectangle.
- * @param r The rectangle to test for inclusion within the area.
- * @return True if the rectangle lies completely within the interior
- * of the area
- */
- public boolean contains(Rectangle2D r) {
- TGRect rect = new TGRect(r);
- return (fGeometry != null) && fGeometry.contains(rect);
- }
-
- /* ________________________________________________________________________
- * Constructive Area Geometry (CAG) functions
- */
-
- /**
- * Adds the shape of the specified Area to the current shape.
- * Addition is achieved through union.
- * @param rhs The shape to be added to the current area.
- */
- public void add(Area rhs) {
- MAreaGeometry srcGeometry = rhs.fGeometry;
- if (fGeometry == null) // null + X == X
- {
- if (srcGeometry != null)
- fGeometry = srcGeometry;
- }
- else if (srcGeometry != null) // X + null == X
- fGeometry = MAreaGeometry.add(fGeometry, srcGeometry);
- }
-
- /**
- * Subtracts the shape of the specified Area from the current shape.
- * @param rhs The shape to be subtracted from the current area.
- */
- public void subtract(Area rhs) {
- if (fGeometry != null) // null - X == null
- {
- MAreaGeometry srcGeometry = rhs.fGeometry;
- if (srcGeometry != null) // null - null == null
- fGeometry = MAreaGeometry.subtract(fGeometry, srcGeometry);
- }
- }
-
- /**
- * Sets the shape of this Area to the intersection of the current
- * shape with the shape of the specified Area.
- * @param rhs The area to be intersected with this one.
- */
- public void intersect(Area rhs) {
- if (fGeometry != null) // null * X == null
- {
- MAreaGeometry srcGeometry = rhs.fGeometry;
- if (srcGeometry == null) // X * null == null
- fGeometry = srcGeometry;
- else
- fGeometry = MAreaGeometry.intersect(fGeometry, srcGeometry);
- }
- }
-
- /**
- * Sets the shape of this Area to the combined area of the current
- * shape and the shape of the specified Area, minus their intersection.
- * @param rhs The area to be exclusive ORed with this one.
- */
- public void exclusiveOr(Area rhs) {
- MAreaGeometry srcGeometry = rhs.fGeometry;
- if (srcGeometry != null) {
- if (fGeometry == null) // null ^ X == X
- fGeometry = srcGeometry;
- else
- fGeometry = MAreaGeometry.exclusiveOr(fGeometry, srcGeometry);
- }
- // else X ^ null == X
- }
-
- /* ________________________________________________________________________
- * Compatability functions
- */
-
- /**
- * clone function ... to be compatible with Cloneable
- * @return Created clone object
- */
- public Object clone() {
- return (Object)(new Area(fGeometry));
- }
-
- /**
- * Tests whether the two objects are equal.
- * @param rhs The area geometry to be compared to this one.
- * @return True if the two area geometries are equal.
- */
- public boolean equals(Area rhs) {
- MAreaGeometry that = rhs.fGeometry;
- if (fGeometry == that)
- return true;
- else
- return
- (fGeometry != null) &&
- (that != null) &&
- fGeometry.equals(that);
- }
-
- /**
- * Creates a PathIterator for the outline of this Area object.
- * This Area object is unchanged.
- * @param t an optional AffineTransform to be applied to the
- * coordinates as they are returned in the iteration, or null
- * if the untransformed coordinates are desired.
- * @return The PathIterator object which returns the geometry
- * of the outline of this area one segment at a time
- */
- public PathIterator getPathIterator(AffineTransform t) {
- if (t == null || t.isIdentity()) {
- return new AreaPathIterator(extract(Double.POSITIVE_INFINITY));
- }
- else {
- TGLoop areaPath =
- createTransformedArea(t).extract(Double.POSITIVE_INFINITY);
- return new AreaPathIterator(areaPath);
- }
- }
-
- /**
- * Create a PathIterator for the flattened outline of this Area object.
- * Only uncurved path segments represented by the SEG_MOVETO, SEG_LINETO,
- * and SEG_CLOSE point types will be returned by the iterator.
- * This Area object is unchanged.
- * @param t an optional AffineTransform to be applied to the
- * coordinates as they are returned in the iteration, or null
- * if the untransformed coordinates are desired.
- * @param flatness the maximum amount that the control points
- * for a given curve can vary from colinear before a subdivided
- * curve is replaced by a straight line connecting the endpoints.
- * @return The PathIterator object which returns the geometry
- * of the outline of this area one segment at a time
- */
- public PathIterator getPathIterator(AffineTransform t, double f) {
- if (t == null || t.isIdentity()) {
- return new AreaPathIterator(extract(f));
- }
- else {
- return new AreaPathIterator(createTransformedArea(t).extract(f));
- }
- }
-
- /**
- * Creates a new Area from this Area object representing the geometry
- * of the original transformed by the specified AffineTransform.
- * This Area object is unchanged.
- * @param t The transformation matrix used to transform the new area.
- * @return A new Area object representing the transformed geometry.
- */
- public Area createTransformedArea(AffineTransform t) {
- Area result = new Area(fGeometry);
- result.transform(t);
- return result;
- }
-
- /* ________________________________________________________________________
- * Private Internal things
- */
-
- Area(MAreaGeometry geometry) {
- fGeometry = geometry;
- }
-
- long getTimeStamp() {
- if (fGeometry == null)
- return (long)0;
- else
- return fGeometry.getTimeStamp();
- }
-
- TGRect internalGetBounds() {
- if (fGeometry != null)
- return fGeometry.getBounds();
- else
- return TGRect.kZeroRect;
- }
-
- // the Area geometry data
- private MAreaGeometry fGeometry = null;
-
- // caching what was last extracted...
- private TGLoop fCachedPath = null;
- private double fCachedTimeStamp = 0;
- private boolean fCachedVertices = false;
-
- TGLoop extract(double epsilon) {
-
- TGLoop result = null;
- long stamp = getTimeStamp();
-
- if (fGeometry != null) {
-
- boolean isPolygonal =
- (epsilon != Double.POSITIVE_INFINITY) ||
- (fGeometry.isPolygonal());
-
- // cache hit??
- if (fCachedPath != null &&
- fCachedTimeStamp == stamp &&
- fCachedVertices == isPolygonal) {
- return fCachedPath;
- }
-
- if (isPolygonal) {
- result = new TGLoop();
- TOutlineMakerVertexEngine outliner =
- new TOutlineMakerVertexEngine(result);
- TSamplingExtractor sampler =
- new TSamplingExtractor(outliner, epsilon);
-
- TCAGRoot root = new TCAGRoot();
- fGeometry.extract(sampler, root);
- sampler.render(root);
- }
- else {
- TPathExtractor pather = new TPathExtractor();
- TCAGRoot root = new TCAGRoot();
- fGeometry.extract(pather, root);
- pather.render(root);
- result = pather.getPath();
- }
- // cache it...
- fCachedTimeStamp = stamp;
- fCachedVertices = isPolygonal;
- fCachedPath = result;
- }
- return result;
- }
- }
-