home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / geom / Area.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  18.2 KB  |  540 lines

  1. /*
  2.  * @(#)Area.java    1.18 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. /*
  16.  * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
  17.  * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
  18.  *
  19.  * The original version of this source code and documentation is
  20.  * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
  21.  * of IBM. These materials are provided under terms of a License
  22.  * Agreement between Taligent and Sun. This technology is protected
  23.  * by multiple US and International patents.
  24.  *
  25.  * This notice and attribution to Taligent may not be removed.
  26.  * Taligent is a registered trademark of Taligent, Inc.
  27.  *
  28.  */
  29.  
  30. package java.awt.geom;
  31.  
  32. import java.awt.Polygon;
  33. import java.awt.Rectangle;
  34. import java.awt.Shape;
  35.  
  36. import sun.awt.Albert.TGrafMatrix;
  37. import sun.awt.Albert.TGCurve;
  38. import sun.awt.Albert.TGEllipse;
  39. import sun.awt.Albert.TGLoop;
  40. import sun.awt.Albert.TGPoint;
  41. import sun.awt.Albert.TGPolygon;
  42. import sun.awt.Albert.TGRect;
  43. import sun.awt.Albert.TEllipseGeometry;
  44. import sun.awt.Albert.TLoopGeometry;
  45. import sun.awt.Albert.TPolygonGeometry;
  46. import sun.awt.Albert.TRectGeometry;
  47. import sun.awt.Albert.TCAGRoot;
  48. import sun.awt.Albert.TOutlineMakerVertexEngine;
  49. import sun.awt.Albert.TPathExtractor;
  50. import sun.awt.Albert.TSamplingExtractor;
  51. import sun.awt.Albert.MAreaGeometry;
  52. import sun.awt.Albert.AreaPathIterator;
  53.  
  54. //--+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
  55. /**
  56.  * Area is a device-independent specification of an arbitrarily-shaped area.
  57.  * The Area object is defined as an object that performs certain binary CAG
  58.  * (Constructive Area Geometry) operations on other area-enclosing geometries,
  59.  * such as rectangles, ellipses, and polygons. The CAG operations are
  60.  * Add(union), Subtract, Intersect, and ExclusiveOR. For instance, an Area
  61.  * can be made up of the area of a rectangle minus the area of an ellipse.
  62.  */
  63. public class Area implements Shape, Cloneable {
  64.  
  65. /*    ________________________________________________________________________
  66.  *    Constructors
  67.  */
  68.  
  69.     /**
  70.      * Default constructor which creates an empty area.
  71.      */
  72.     public Area() {
  73.     }
  74.  
  75.     /**
  76.      * Creates an area geometry from the specified Shape object.
  77.      * The geometry is explicitly closed, if the shape is not already closed.
  78.      * The fill rule (even-odd or winding) specified by the shape
  79.      * geometry is used to determined the resulting enclosed area.
  80.      * @param g  The shape from which the area is to be constructed.
  81.      */
  82.     public Area(Shape g) {
  83.         if (g == null)
  84.             return;
  85.  
  86.         if (this.getClass().equals(g.getClass())) {  // it's an Area!!
  87.             fGeometry = ((Area)g).fGeometry;
  88.             return;
  89.         }
  90.  
  91.         TGCurve theCurve = new TGCurve();
  92.         double tmp[] = new double[6];    // array of points
  93.         TGPoint close = new TGPoint();
  94.         TGPoint lastP = new TGPoint();
  95.         TGPoint nextP = new TGPoint();
  96.         TGPoint tmpP = null;
  97.         PathIterator i = g.getPathIterator(null);
  98.         for (; !i.isDone(); i.next()) {
  99.             switch (i.currentSegment(tmp)) {
  100.             default:
  101.             case PathIterator.SEG_MOVETO:
  102.                 lastP.x = tmp[0];
  103.                 lastP.y = tmp[1];
  104.                 close.copyFrom(lastP);
  105.                 break;
  106.             case PathIterator.SEG_LINETO:
  107.                 nextP.x = tmp[0];
  108.                 nextP.y = tmp[1];
  109.                 theCurve.concatenate(new TGCurve(lastP, nextP));
  110.                 tmpP = lastP; lastP = nextP; nextP = tmpP;
  111.                 break;
  112.             case PathIterator.SEG_QUADTO:
  113.                 nextP.x = tmp[2];
  114.                 nextP.y = tmp[3];
  115.                 tmpP = new TGPoint(tmp[0], tmp[1]);
  116.                 theCurve.concatenate(new TGCurve(lastP, tmpP, nextP));
  117.                 tmpP = lastP; lastP = nextP; nextP = tmpP;
  118.                 break;
  119.             case PathIterator.SEG_CUBICTO:
  120.                 nextP.x = tmp[4];
  121.                 nextP.y = tmp[5];
  122.                 tmpP = new TGPoint(tmp[0], tmp[1]);
  123.                 TGPoint p23 = new TGPoint(tmp[2], tmp[3]);
  124.                 theCurve.concatenate(new TGCurve(lastP, tmpP, p23, nextP));
  125.                 tmpP = lastP; lastP = nextP; nextP = tmpP;
  126.                 break;
  127.             case PathIterator.SEG_CLOSE:
  128.                 theCurve.concatenate(new TGCurve(lastP, close));
  129.                 lastP.copyFrom(close);
  130.                 break;
  131.             }
  132.         }
  133.         boolean EOFill = (i.getWindingRule() == PathIterator.WIND_EVEN_ODD);
  134.         TGLoop geometry = new TGLoop(theCurve, EOFill);
  135.         fGeometry = new TLoopGeometry(geometry);
  136.     }
  137.  
  138.     /**
  139.      * Creates an area geometry from the specified polygon.
  140.      * Even-odd fill rule is assumed as per the definition of the
  141.      * java.awt.Polygon class.
  142.      * @param geometry  The polygon from which the area is to be
  143.      * constructed.
  144.      */
  145.     public Area(Polygon geometry) {
  146.         TGPolygon temp = new TGPolygon(geometry);
  147.         if ((temp.getNumberOfPoints() == 4) && temp.isRectilinear() &&
  148.             temp.getPoint(0).equals(temp.getPoint(2)) &&
  149.             temp.getPoint(1).equals(temp.getPoint(3)))
  150.             fGeometry = new TRectGeometry(temp.getBounds());
  151.         else
  152.             fGeometry = new TPolygonGeometry(temp);
  153.     }
  154.  
  155.     /**
  156.      * Creates an area geometry from the specified rectangle.
  157.      * @param r  The rectangle from which the area is to be constructed.
  158.      */
  159.     public Area(Rectangle2D r) {
  160.         TGRect geometry = new TGRect(r);
  161.         fGeometry = new TRectGeometry(geometry);
  162.     }
  163.  
  164.     /**
  165.      * Creates an area geometry of a ellipse inside the specified rectangle.
  166.      * @param e  The ellipse geometry from which the area is to be
  167.      * constructed
  168.      */
  169.     public Area(Ellipse2D e) {
  170.         fGeometry = new TEllipseGeometry(new TGEllipse(new TGRect(e)));
  171.     }
  172.  
  173. /*    ________________________________________________________________________
  174.  *    computational geometry functions
  175.  */
  176.  
  177.     /**
  178.      * Transforms the geometry of this Area using the specified transform.
  179.      * The geometry is transformed in place permanently changing the
  180.      * enclosed area defined by this object.
  181.      * @param t  The matrix used to transform the area.
  182.      */
  183.     public void transform(AffineTransform t) {
  184.         TGrafMatrix matrix = new TGrafMatrix(t);
  185.         if ((fGeometry != null) && !matrix.isIdentity())
  186.             fGeometry = fGeometry.cloneAndTransform(matrix);
  187.     }
  188.  
  189.     /**
  190.      * Removes all the basic geometry from this area and restores it to
  191.      * an empty area.
  192.      */
  193.     public void reset() {
  194.         fGeometry = null;
  195.     }
  196.  
  197.     /**
  198.      * Tests whether this area contains any geometry.
  199.      * @return    True if this area contains no basic geometry, or is an
  200.      * empty area.
  201.      */
  202.     public boolean isEmpty() {
  203.         return (fGeometry == null) || fGeometry.isEmpty();
  204.     }
  205.  
  206.     /**
  207.      * Tests whether the area consists entirely of straight edged
  208.      * polygonal geometry.
  209.      * @return    True if the area consists completely of polygon edges
  210.      */
  211.     public boolean isPolygonal() {
  212.         return (fGeometry == null) || fGeometry.isPolygonal();
  213.     }
  214.  
  215.     /**
  216.      * Tests whether the area is rectangular in shape.
  217.      * @return    True if the area is rectangular in shape.
  218.      */
  219.     public boolean isRectangular() {
  220.         return (fGeometry == null) || fGeometry.isRectangular();
  221.     }
  222.  
  223.     /**
  224.      * Tests whether the area is comprised of a single basic geometry.
  225.      * @return    True if the area is comprised of a single basic geometry.
  226.      */
  227.     public boolean isSingular() {
  228.         return (fGeometry == null) || fGeometry.isSingular();
  229.     }
  230.  
  231.     /**
  232.      * Returns a bounding rectangle that completely encloses the area.
  233.      * @return    The bounding rectangle for the area.
  234.      */
  235.     public Rectangle getBounds() {
  236.         return internalGetBounds().getBounds();
  237.     }
  238.  
  239.     /**
  240.      * Returns a high precision bounding rectangle that completely
  241.      * encloses the area.
  242.      * @return    The bounding rectangle for the area.
  243.      */
  244.     public Rectangle2D getBounds2D() {
  245.         return internalGetBounds();
  246.     }
  247.  
  248.     /**
  249.      * Tests whether the interior of the area intersects the interior
  250.      * of the given rectangle.
  251.      * @return    True if the interior intersects the given rectangle.
  252.      */
  253.     public boolean intersects(double x, double y, double w, double h) {
  254.         TGRect rect = new TGRect(x, y, x + w, y + h);
  255.         return ((fGeometry != null) &&
  256.         (fGeometry.intersects(rect) ||
  257.          fGeometry.contains(rect)));
  258.     }
  259.  
  260.     /**
  261.      * Tests whether the interior of the area intersects the interior
  262.      * of the given rectangle.
  263.      * @param     r  The rectangle to test for intersection.
  264.      * @return    True if the interior intersects the given rectangle.
  265.      */
  266.     public boolean intersects(Rectangle2D r) {
  267.         TGRect rect = new TGRect(r);
  268.         return (fGeometry != null) && fGeometry.intersects(rect);
  269.     }
  270.  
  271.     /**
  272.      * Tests if a given coordinate lies inside the boundary of the shape.
  273.      * @param     x  x value of the point
  274.      * @param     y  y value of the point
  275.      * @return    True if the point lies completely within the interior
  276.      * of the area
  277.      */
  278.     public boolean contains(double x, double y) {
  279.         TGPoint pt = new TGPoint(x, y);
  280.         return (fGeometry != null) && fGeometry.contains(pt);
  281.     }
  282.  
  283.     /**
  284.      * Tests if a given coordinate lies inside the boundary of the shape.
  285.      * @param     p  The point to test for inclusion within the area.
  286.      * @return    True if the point lies completely within the interior
  287.      * of the area
  288.      */
  289.     public boolean contains(Point2D p) {
  290.         TGPoint pt = new TGPoint(p);
  291.         return (fGeometry != null) && fGeometry.contains(pt);
  292.     }
  293.  
  294.     /**
  295.      * Tests whether the interior of the area completely contains the
  296.      * given rectangle.
  297.      * @return    True if the rectangle lies completely within the interior
  298.      * of the area
  299.      */
  300.     public boolean contains(double x, double y, double w, double h) {
  301.         TGRect rect = new TGRect(x, y, x + w, y + h);
  302.         return (fGeometry != null) && fGeometry.contains(rect);
  303.     }
  304.  
  305.     /**
  306.      * Tests whether the interior of the area completely contains the
  307.      * given rectangle.
  308.      * @param     r  The rectangle to test for inclusion within the area.
  309.      * @return    True if the rectangle lies completely within the interior
  310.      * of the area
  311.      */
  312.     public boolean contains(Rectangle2D r) {
  313.         TGRect rect = new TGRect(r);
  314.         return (fGeometry != null) && fGeometry.contains(rect);
  315.     }
  316.  
  317. /*    ________________________________________________________________________
  318.  *    Constructive Area Geometry (CAG) functions
  319.  */
  320.  
  321.     /**
  322.      * Adds the shape of the specified Area to the current shape.
  323.      * Addition is achieved through union.
  324.      * @param     rhs  The shape to be added to the current area.
  325.      */
  326.     public void add(Area rhs) {
  327.         MAreaGeometry srcGeometry = rhs.fGeometry;
  328.         if (fGeometry == null)  // null + X == X
  329.         {
  330.             if (srcGeometry != null)
  331.                 fGeometry = srcGeometry;
  332.         }
  333.         else if (srcGeometry != null)    // X + null == X
  334.             fGeometry = MAreaGeometry.add(fGeometry, srcGeometry);
  335.     }
  336.  
  337.     /**
  338.      * Subtracts the shape of the specified Area from the current shape.
  339.      * @param     rhs  The shape to be subtracted from the current area.
  340.      */
  341.     public void subtract(Area rhs) {
  342.         if (fGeometry != null)  // null - X == null
  343.         {
  344.             MAreaGeometry srcGeometry = rhs.fGeometry;
  345.             if (srcGeometry != null)     // null - null == null
  346.                 fGeometry = MAreaGeometry.subtract(fGeometry, srcGeometry);
  347.         }
  348.     }
  349.  
  350.     /**
  351.      * Sets the shape of this Area to the intersection of the current
  352.      * shape with the shape of the specified Area.
  353.      * @param     rhs  The area to be intersected with this one.
  354.      */
  355.     public void intersect(Area rhs) {
  356.         if (fGeometry != null)  // null * X == null
  357.         {
  358.             MAreaGeometry srcGeometry = rhs.fGeometry;
  359.             if (srcGeometry == null)     // X * null == null
  360.                 fGeometry = srcGeometry;
  361.             else
  362.                 fGeometry = MAreaGeometry.intersect(fGeometry, srcGeometry);
  363.         }
  364.     }
  365.  
  366.     /**
  367.      * Sets the shape of this Area to the combined area of the current
  368.      * shape and the shape of the specified Area, minus their intersection.
  369.      * @param     rhs  The area to be exclusive ORed with this one.
  370.      */
  371.     public void exclusiveOr(Area rhs) {
  372.         MAreaGeometry srcGeometry = rhs.fGeometry;
  373.         if (srcGeometry != null) {
  374.             if (fGeometry == null)   // null ^ X == X
  375.                 fGeometry = srcGeometry;
  376.             else
  377.                 fGeometry = MAreaGeometry.exclusiveOr(fGeometry, srcGeometry);
  378.         }
  379.         // else X ^ null == X
  380.     }
  381.  
  382. /*    ________________________________________________________________________
  383.  *    Compatability functions
  384.  */
  385.  
  386.     /**
  387.      * clone function ... to be compatible with Cloneable
  388.      * @return    Created clone object
  389.      */
  390.     public Object clone() {
  391.         return (Object)(new Area(fGeometry));
  392.     }
  393.  
  394.     /**
  395.      * Tests whether the two objects are equal.
  396.      * @param     rhs  The area geometry to be compared to this one.
  397.      * @return    True if the two area geometries are equal.
  398.      */
  399.     public boolean equals(Area rhs) {
  400.         MAreaGeometry that = rhs.fGeometry;
  401.         if (fGeometry == that)
  402.             return true;
  403.         else
  404.             return
  405.                 (fGeometry != null) &&
  406.                 (that != null) &&
  407.                 fGeometry.equals(that);
  408.     }
  409.  
  410.     /**
  411.      * Creates a PathIterator for the outline of this Area object.
  412.      * This Area object is unchanged.
  413.      * @param t an optional AffineTransform to be applied to the
  414.      * coordinates as they are returned in the iteration, or null
  415.      * if the untransformed coordinates are desired.
  416.      * @return    The PathIterator object which returns the geometry
  417.      * of the outline of this area one segment at a time
  418.      */
  419.     public PathIterator getPathIterator(AffineTransform t) {
  420.         if (t == null || t.isIdentity()) {
  421.             return new AreaPathIterator(extract(Double.POSITIVE_INFINITY));
  422.         }
  423.         else {
  424.             TGLoop areaPath =
  425.         createTransformedArea(t).extract(Double.POSITIVE_INFINITY);
  426.             return new AreaPathIterator(areaPath);
  427.         }
  428.     }
  429.  
  430.     /**
  431.      * Create a PathIterator for the flattened outline of this Area object.
  432.      * Only uncurved path segments represented by the SEG_MOVETO, SEG_LINETO,
  433.      * and SEG_CLOSE point types will be returned by the iterator.
  434.      * This Area object is unchanged.
  435.      * @param t an optional AffineTransform to be applied to the
  436.      * coordinates as they are returned in the iteration, or null
  437.      * if the untransformed coordinates are desired.
  438.      * @param flatness the maximum amount that the control points
  439.      * for a given curve can vary from colinear before a subdivided
  440.      * curve is replaced by a straight line connecting the endpoints.
  441.      * @return    The PathIterator object which returns the geometry
  442.      * of the outline of this area one segment at a time
  443.      */
  444.     public PathIterator getPathIterator(AffineTransform t, double f) {
  445.         if (t == null || t.isIdentity()) {
  446.             return new AreaPathIterator(extract(f));
  447.         }
  448.         else {
  449.             return new AreaPathIterator(createTransformedArea(t).extract(f));
  450.         }
  451.     }
  452.  
  453.     /**
  454.      * Creates a new Area from this Area object representing the geometry
  455.      * of the original transformed by the specified AffineTransform.
  456.      * This Area object is unchanged.
  457.      * @param t  The transformation matrix used to transform the new area.
  458.      * @return    A new Area object representing the transformed geometry.
  459.      */
  460.     public Area createTransformedArea(AffineTransform t) {
  461.         Area result = new Area(fGeometry);
  462.         result.transform(t);
  463.         return result;
  464.     }
  465.  
  466. /*    ________________________________________________________________________
  467.  *    Private Internal things
  468.  */
  469.  
  470.     Area(MAreaGeometry geometry) {
  471.         fGeometry = geometry;
  472.     }
  473.  
  474.     long getTimeStamp() {
  475.         if (fGeometry == null)
  476.             return (long)0;
  477.         else
  478.             return fGeometry.getTimeStamp();
  479.     }
  480.  
  481.     TGRect internalGetBounds() {
  482.         if (fGeometry != null)
  483.             return fGeometry.getBounds();
  484.         else
  485.             return TGRect.kZeroRect;
  486.     }
  487.  
  488.     // the Area geometry data
  489.     private MAreaGeometry fGeometry = null;
  490.  
  491.     // caching what was last extracted...
  492.     private TGLoop fCachedPath = null;
  493.     private double fCachedTimeStamp = 0;
  494.     private boolean fCachedVertices = false;
  495.  
  496.     TGLoop extract(double epsilon) {
  497.  
  498.         TGLoop result = null;
  499.         long stamp = getTimeStamp();
  500.  
  501.         if (fGeometry != null) {
  502.  
  503.             boolean isPolygonal =
  504.                 (epsilon != Double.POSITIVE_INFINITY) ||
  505.                 (fGeometry.isPolygonal());
  506.  
  507.             // cache hit??
  508.             if (fCachedPath != null &&
  509.                 fCachedTimeStamp == stamp &&
  510.                 fCachedVertices == isPolygonal) {
  511.                 return fCachedPath;
  512.             }
  513.  
  514.             if (isPolygonal) {
  515.                 result = new TGLoop();
  516.                 TOutlineMakerVertexEngine outliner =
  517.                     new TOutlineMakerVertexEngine(result);
  518.                 TSamplingExtractor sampler =
  519.                     new TSamplingExtractor(outliner, epsilon);
  520.  
  521.                 TCAGRoot root = new TCAGRoot();
  522.                 fGeometry.extract(sampler, root);
  523.                 sampler.render(root);
  524.             }
  525.             else {
  526.                 TPathExtractor pather = new TPathExtractor();
  527.                 TCAGRoot root = new TCAGRoot();
  528.                 fGeometry.extract(pather, root);
  529.                 pather.render(root);
  530.                 result = pather.getPath();
  531.             }
  532.             // cache it...
  533.             fCachedTimeStamp = stamp;
  534.             fCachedVertices = isPolygonal;
  535.             fCachedPath = result;
  536.         }
  537.         return result;
  538.     }
  539. }
  540.