[kaffe] CVS kaffe (dalibor): Resynced with GNU Classpath.

Kaffe CVS cvs-commits at kaffe.org
Sun Aug 29 02:41:59 PDT 2004


PatchSet 5114 
Date: 2004/08/29 09:37:53
Author: dalibor
Branch: HEAD
Tag: (none) 
Log:
        Resynced with GNU Classpath.
2004-08-29  Dalibor Topic  <robilad at kaffe.org>

        * libraries/javalib/java/awt/geom/Area.java:
        Resynced with GNU Classpath.

        2004-08-27  Sven de Marothy  <sven at physto.se>

        * java/awt/geom/Area.java
        Implemented.

Members: 
	ChangeLog:1.2670->1.2671 
	libraries/javalib/java/awt/geom/Area.java:1.1->1.2 

Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.2670 kaffe/ChangeLog:1.2671
--- kaffe/ChangeLog:1.2670	Sat Aug 28 15:29:53 2004
+++ kaffe/ChangeLog	Sun Aug 29 09:37:53 2004
@@ -1,3 +1,13 @@
+2004-08-29  Dalibor Topic  <robilad at kaffe.org>
+
+	* libraries/javalib/java/awt/geom/Area.java:
+	Resynced with GNU Classpath.
+
+	2004-08-27  Sven de Marothy  <sven at physto.se>
+
+        * java/awt/geom/Area.java
+        Implemented.
+
 2004-08-28  Alexander Boettcher  <ab764283 at os.inf.tu-dresden.de>
 
 	* kaffe/kaffevm/debug.c
Index: kaffe/libraries/javalib/java/awt/geom/Area.java
diff -u kaffe/libraries/javalib/java/awt/geom/Area.java:1.1 kaffe/libraries/javalib/java/awt/geom/Area.java:1.2
--- kaffe/libraries/javalib/java/awt/geom/Area.java:1.1	Wed Nov  6 11:52:24 2002
+++ kaffe/libraries/javalib/java/awt/geom/Area.java	Sun Aug 29 09:37:56 2004
@@ -1,5 +1,5 @@
 /* Area.java -- represents a shape built by constructive area geometry
-   Copyright (C) 2002 Free Software Foundation
+   Copyright (C) 2002, 2004 Free Software Foundation
 
 This file is part of GNU Classpath.
 
@@ -35,74 +35,636 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
-
 package java.awt.geom;
 
 import java.awt.Rectangle;
 import java.awt.Shape;
+import java.util.Vector;
+
 
 /**
- * STUBS ONLY
- * XXX Implement and document.
+ * The Area class represents any area for the purpose of
+ * Constructive Area Geometry (CAG) manipulations. CAG manipulations
+ * work as an area-wise form of boolean logic, where the basic operations are:
+ * <P><li>Add (in boolean algebra: A <B>or</B> B)<BR>
+ * <li>Subtract (in boolean algebra: A <B>and</B> (<B>not</B> B) )<BR>
+ * <li>Intersect (in boolean algebra: A <B>and</B> B)<BR>
+ * <li>Exclusive Or <BR>
+ * <img src="doc-files/Area-1.png" width="342" height="302"
+ * alt="Illustration of CAG operations" /><BR>
+ * Above is an illustration of the CAG operations on two ring shapes.<P>
+ *
+ * The contains and intersects() methods are also more accurate than the
+ * specification of #Shape requires.<P>
+ *
+ * Please note that constructing an Area can be slow
+ * (Self-intersection resolving is proportional to the square of
+ * the number of segments).<P>
+ * @see #add(Area)
+ * @see #subtract(Area)
+ * @see #intersect(Area)
+ * @see #exclusiveOr(Area)
+ *
+ * @author Sven de Marothy (sven at physto.se)
+ *
+ * @since 1.2
+ * @status Works, but could be faster and more reliable.
  */
 public class Area implements Shape, Cloneable
 {
+  /**
+   * General numerical precision
+   */
+  private final double EPSILON = 1E-11;
+
+  /**
+   * recursive subdivision epsilon - (see getRecursionDepth)
+   */
+  private final double RS_EPSILON = 1E-13;
+
+  /**
+   * Snap distance - points within this distance are considered equal
+   */
+  private final double PE_EPSILON = 1E-11;
+
+  /**
+   * Segment vectors containing solid areas and holes
+   */
+  private Vector solids;
+
+  /**
+   * Segment vectors containing solid areas and holes
+   */
+  private Vector holes;
+
+  /**
+   * Vector (temporary) storing curve-curve intersections
+   */
+  private Vector cc_intersections;
+
+  /**
+   * Winding rule WIND_NON_ZERO used, after construction,
+   * this is irrelevant.
+   */
+  private int windingRule;
+
+  /**
+   * Constructs an empty Area
+   */
   public Area()
   {
+    solids = new Vector();
+    holes = new Vector();
   }
+
+  /**
+   * Constructs an Area from any given Shape. <P>
+   *
+   * If the Shape is self-intersecting, the created Area will consist
+   * of non-self-intersecting subpaths, and any inner paths which
+   * are found redundant in accordance with the Shape's winding rule
+   * will not be included.
+   */
   public Area(Shape s)
   {
+    this();
+
+    Vector p = makeSegment(s);
+
+    // empty path
+    if (p == null)
+      return;
+
+    // delete empty paths
+    for (int i = 0; i < p.size(); i++)
+      if (((Segment) p.elementAt(i)).getSignedArea() == 0.0)
+	p.remove(i--);
+
+    /*
+     * Resolve self intersecting paths into non-intersecting
+     * solids and holes.
+     * Algorithm is as follows:
+     * 1: Create nodes at all self intersections
+     * 2: Put all segments into a list
+     * 3: Grab a segment, follow it, change direction at each node,
+     *    removing segments from the list in the process
+     * 4: Repeat (3) until no segments remain in the list
+     * 5: Remove redundant paths and sort into solids and holes
+     */
+    Vector paths = new Vector();
+    Segment v;
+
+    for (int i = 0; i < p.size(); i++)
+      {
+	Segment path = (Segment) p.elementAt(i);
+	createNodesSelf(path);
+      }
+
+    if (p.size() > 1)
+      {
+	for (int i = 0; i < p.size() - 1; i++)
+	  for (int j = i + 1; j < p.size(); j++)
+	    {
+	      Segment path1 = (Segment) p.elementAt(i);
+	      Segment path2 = (Segment) p.elementAt(j);
+	      createNodes(path1, path2);
+	    }
+      }
+
+    // we have intersecting points.
+    Vector segments = new Vector();
+
+    for (int i = 0; i < p.size(); i++)
+      {
+	Segment path = v = (Segment) p.elementAt(i);
+	do
+	  {
+	    segments.add(v);
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    paths = weilerAtherton(segments);
+    deleteRedundantPaths(paths);
   }
-  public void add(Area a)
+
+  /**
+   * Performs an add (union) operation on this area with another Area.<BR>
+   * @param area - the area to be unioned with this one
+   */
+  public void add(Area area)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (equals(area))
+      return;
+    if (area.isEmpty())
+      return;
+
+    Area B = (Area) area.clone();
+
+    Vector pathA = new Vector();
+    Vector pathB = new Vector();
+    pathA.addAll(solids);
+    pathA.addAll(holes);
+    pathB.addAll(B.solids);
+    pathB.addAll(B.holes);
+
+    int nNodes = 0;
+
+    for (int i = 0; i < pathA.size(); i++)
+      {
+	Segment a = (Segment) pathA.elementAt(i);
+	for (int j = 0; j < pathB.size(); j++)
+	  {
+	    Segment b = (Segment) pathB.elementAt(j);
+	    nNodes += createNodes(a, b);
+	  }
+      }
+
+    Vector paths = new Vector();
+    Segment v;
+
+    // we have intersecting points.
+    Vector segments = new Vector();
+
+    // In a union operation, we keep all
+    // segments of A oustide B and all B outside A
+    for (int i = 0; i < pathA.size(); i++)
+      {
+	v = (Segment) pathA.elementAt(i);
+	Segment path = v;
+	do
+	  {
+	    if (v.isSegmentOutside(area))
+	      segments.add(v);
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    for (int i = 0; i < pathB.size(); i++)
+      {
+	v = (Segment) pathB.elementAt(i);
+	Segment path = v;
+	do
+	  {
+	    if (v.isSegmentOutside(this))
+	      segments.add(v);
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    paths = weilerAtherton(segments);
+    deleteRedundantPaths(paths);
   }
-  public void subtract(Area a)
+
+  /**
+   * Performs a subtraction operation on this Area.<BR>
+   * @param area - the area to be subtracted from this area.
+   */
+  public void subtract(Area area)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (isEmpty() || area.isEmpty())
+      return;
+
+    if (equals(area))
+      {
+	reset();
+	return;
+      }
+
+    Vector pathA = new Vector();
+    Area B = (Area) area.clone();
+    pathA.addAll(solids);
+    pathA.addAll(holes);
+
+    // reverse the directions of B paths.
+    setDirection(B.holes, true);
+    setDirection(B.solids, false);
+
+    Vector pathB = new Vector();
+    pathB.addAll(B.solids);
+    pathB.addAll(B.holes);
+
+    int nNodes = 0;
+
+    // create nodes
+    for (int i = 0; i < pathA.size(); i++)
+      {
+	Segment a = (Segment) pathA.elementAt(i);
+	for (int j = 0; j < pathB.size(); j++)
+	  {
+	    Segment b = (Segment) pathB.elementAt(j);
+	    nNodes += createNodes(a, b);
+	  }
+      }
+
+    Vector paths = new Vector();
+
+    // we have intersecting points.
+    Vector segments = new Vector();
+
+    // In a subtraction operation, we keep all
+    // segments of A oustide B and all B within A
+    // We outsideness-test only one segment in each path
+    // and the segments before and after any node
+    for (int i = 0; i < pathA.size(); i++)
+      {
+	Segment v = (Segment) pathA.elementAt(i);
+	Segment path = v;
+	if (v.isSegmentOutside(area) && v.node == null)
+	  segments.add(v);
+	boolean node = false;
+	do
+	  {
+	    if ((v.node != null || node))
+	      {
+		node = (v.node != null);
+		if (v.isSegmentOutside(area))
+		  segments.add(v);
+	      }
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    for (int i = 0; i < pathB.size(); i++)
+      {
+	Segment v = (Segment) pathB.elementAt(i);
+	Segment path = v;
+	if (! v.isSegmentOutside(this) && v.node == null)
+	  segments.add(v);
+	v = v.next;
+	boolean node = false;
+	do
+	  {
+	    if ((v.node != null || node))
+	      {
+		node = (v.node != null);
+		if (! v.isSegmentOutside(this))
+		  segments.add(v);
+	      }
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    paths = weilerAtherton(segments);
+    deleteRedundantPaths(paths);
   }
-  public void intersect(Area a)
+
+  /**
+   * Performs an intersection operation on this Area.<BR>
+   * @param area - the area to be intersected with this area.
+   */
+  public void intersect(Area area)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (isEmpty() || area.isEmpty())
+      {
+	reset();
+	return;
+      }
+    if (equals(area))
+      return;
+
+    Vector pathA = new Vector();
+    Area B = (Area) area.clone();
+    pathA.addAll(solids);
+    pathA.addAll(holes);
+
+    Vector pathB = new Vector();
+    pathB.addAll(B.solids);
+    pathB.addAll(B.holes);
+
+    int nNodes = 0;
+
+    // create nodes
+    for (int i = 0; i < pathA.size(); i++)
+      {
+	Segment a = (Segment) pathA.elementAt(i);
+	for (int j = 0; j < pathB.size(); j++)
+	  {
+	    Segment b = (Segment) pathB.elementAt(j);
+	    nNodes += createNodes(a, b);
+	  }
+      }
+
+    Vector paths = new Vector();
+
+    // we have intersecting points.
+    Vector segments = new Vector();
+
+    // In an intersection operation, we keep all
+    // segments of A within B and all B within A
+    // (The rest must be redundant)
+    // We outsideness-test only one segment in each path
+    // and the segments before and after any node
+    for (int i = 0; i < pathA.size(); i++)
+      {
+	Segment v = (Segment) pathA.elementAt(i);
+	Segment path = v;
+	if (! v.isSegmentOutside(area) && v.node == null)
+	  segments.add(v);
+	boolean node = false;
+	do
+	  {
+	    if ((v.node != null || node))
+	      {
+		node = (v.node != null);
+		if (! v.isSegmentOutside(area))
+		  segments.add(v);
+	      }
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    for (int i = 0; i < pathB.size(); i++)
+      {
+	Segment v = (Segment) pathB.elementAt(i);
+	Segment path = v;
+	if (! v.isSegmentOutside(this) && v.node == null)
+	  segments.add(v);
+	v = v.next;
+	boolean node = false;
+	do
+	  {
+	    if ((v.node != null || node))
+	      {
+		node = (v.node != null);
+		if (! v.isSegmentOutside(this))
+		  segments.add(v);
+	      }
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    paths = weilerAtherton(segments);
+    deleteRedundantPaths(paths);
   }
-  public void exclusiveOr(Area a)
+
+  /**
+   * Performs an exclusive-or operation on this Area.<BR>
+   * @param area - the area to be XORed with this area.
+   */
+  public void exclusiveOr(Area area)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (area.isEmpty())
+      return;
+
+    if (isEmpty())
+      {
+	Area B = (Area) area.clone();
+	solids = B.solids;
+	holes = B.holes;
+	return;
+      }
+    if (equals(area))
+      {
+	reset();
+	return;
+      }
+
+    Vector pathA = new Vector();
+
+    Area B = (Area) area.clone();
+    Vector pathB = new Vector();
+    pathA.addAll(solids);
+    pathA.addAll(holes);
+
+    // reverse the directions of B paths.
+    setDirection(B.holes, true);
+    setDirection(B.solids, false);
+    pathB.addAll(B.solids);
+    pathB.addAll(B.holes);
+
+    int nNodes = 0;
+
+    for (int i = 0; i < pathA.size(); i++)
+      {
+	Segment a = (Segment) pathA.elementAt(i);
+	for (int j = 0; j < pathB.size(); j++)
+	  {
+	    Segment b = (Segment) pathB.elementAt(j);
+	    nNodes += createNodes(a, b);
+	  }
+      }
+
+    Vector paths = new Vector();
+    Segment v;
+
+    // we have intersecting points.
+    Vector segments = new Vector();
+
+    // In an XOR operation, we operate on all segments
+    for (int i = 0; i < pathA.size(); i++)
+      {
+	v = (Segment) pathA.elementAt(i);
+	Segment path = v;
+	do
+	  {
+	    segments.add(v);
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    for (int i = 0; i < pathB.size(); i++)
+      {
+	v = (Segment) pathB.elementAt(i);
+	Segment path = v;
+	do
+	  {
+	    segments.add(v);
+	    v = v.next;
+	  }
+	while (v != path);
+      }
+
+    paths = weilerAtherton(segments);
+    deleteRedundantPaths(paths);
   }
+
+  /**
+   * Clears the Area object, creating an empty area.
+   */
   public void reset()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    solids = new Vector();
+    holes = new Vector();
   }
+
+  /**
+   * Returns whether this area encloses any area.
+   * @return true if the object encloses any area.
+   */
   public boolean isEmpty()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (solids.size() == 0)
+      return true;
+
+    double totalArea = 0;
+    for (int i = 0; i < solids.size(); i++)
+      totalArea += Math.abs(((Segment) solids.elementAt(i)).getSignedArea());
+    for (int i = 0; i < holes.size(); i++)
+      totalArea -= Math.abs(((Segment) holes.elementAt(i)).getSignedArea());
+    if (totalArea <= EPSILON)
+      return true;
+
+    return false;
   }
+
+  /**
+   * Determines whether the Area consists entirely of line segments
+   * @return true if the Area lines-only, false otherwise
+   */
   public boolean isPolygonal()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    for (int i = 0; i < holes.size(); i++)
+      if (! ((Segment) holes.elementAt(i)).isPolygonal())
+	return false;
+    for (int i = 0; i < solids.size(); i++)
+      if (! ((Segment) solids.elementAt(i)).isPolygonal())
+	return false;
+    return true;
   }
+
+  /**
+   * Determines if the Area is rectangular.<P>
+   *
+   * This is strictly qualified. An area is considered rectangular if:<BR>
+   * <li>It consists of a single polygonal path.<BR>
+   * <li>It is oriented parallel/perpendicular to the xy axis<BR>
+   * <li>It must be exactly rectangular, i.e. small errors induced by
+   * transformations may cause a false result, although the area is
+   * visibly rectangular.<P>
+   * @return true if the above criteria are met, false otherwise
+   */
   public boolean isRectangular()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (holes.size() != 0 || solids.size() != 1)
+      return false;
+
+    Segment path = (Segment) solids.elementAt(0);
+    if (! path.isPolygonal())
+      return false;
+
+    int nCorners = 0;
+    Segment s = path;
+    do
+      {
+	Segment s2 = s.next;
+	double d1 = (s.P2.getX() - s.P1.getX())*(s2.P2.getX() - s2.P1.getX())/
+	    ((s.P1.distance(s.P2)) * (s2.P1.distance(s2.P2)));
+	double d2 = (s.P2.getY() - s.P1.getY())*(s2.P2.getY() - s2.P1.getY())/ 
+	    ((s.P1.distance(s.P2)) * (s2.P1.distance(s2.P2)));
+	double dotproduct = d1 + d2;
+
+	// For some reason, only rectangles on the XY axis count.
+	if (d1 != 0 && d2 != 0)
+	  return false;
+
+	if (Math.abs(dotproduct) == 0) // 90 degree angle
+	  nCorners++;
+	else if ((Math.abs(1.0 - dotproduct) > 0)) // 0 degree angle?
+	  return false; // if not, return false
+
+	s = s.next;
+      }
+    while (s != path);
+
+    return nCorners == 4;
   }
+
+  /**
+   * Returns whether the Area consists of more than one simple
+   * (non self-intersecting) subpath.
+   *
+   * @return true if the Area consists of none or one simple subpath,
+   * false otherwise.
+   */
   public boolean isSingular()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    return (holes.size() == 0 && solids.size() <= 1);
   }
+
+  /**
+   * Returns the bounding box of the Area.<P> Unlike the CubicCurve2D and
+   * QuadraticCurve2D classes, this method will return the tightest possible
+   * bounding box, evaluating the extreme points of each curved segment.<P>
+   * @return the bounding box
+   */
   public Rectangle2D getBounds2D()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (solids.size() == 0)
+      return new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0);
+
+    double xmin;
+    double xmax;
+    double ymin;
+    double ymax;
+    xmin = xmax = ((Segment) solids.elementAt(0)).P1.getX();
+    ymin = ymax = ((Segment) solids.elementAt(0)).P1.getY();
+
+    for (int path = 0; path < solids.size(); path++)
+      {
+	Rectangle2D r = ((Segment) solids.elementAt(path)).getPathBounds();
+	xmin = Math.min(r.getMinX(), xmin);
+	ymin = Math.min(r.getMinY(), ymin);
+	xmax = Math.max(r.getMaxX(), xmax);
+	ymax = Math.max(r.getMaxY(), ymax);
+      }
+
+    return (new Rectangle2D.Double(xmin, ymin, (xmax - xmin), (ymax - ymin)));
   }
+
+  /**
+   * Returns the bounds of this object in Rectangle format.
+   * Please note that this may lead to loss of precision.
+   * @see #getBounds2D()
+   */
   public Rectangle getBounds()
   {
     return getBounds2D().getBounds();
@@ -118,66 +680,2576 @@
   {
     try
       {
-        return super.clone();
+	Area clone = new Area();
+	for (int i = 0; i < solids.size(); i++)
+	  clone.solids.add(((Segment) solids.elementAt(i)).cloneSegmentList());
+	for (int i = 0; i < holes.size(); i++)
+	  clone.holes.add(((Segment) holes.elementAt(i)).cloneSegmentList());
+	return clone;
       }
     catch (CloneNotSupportedException e)
       {
-        throw (Error) new InternalError().initCause(e); // Impossible
+	throw (Error) new InternalError().initCause(e); // Impossible
       }
   }
 
-  public boolean equals(Area a)
+  /**
+   * Compares two Areas.
+   *
+   * @return true if the areas are equal. False otherwise.
+   */
+  public boolean equals(Area area)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (! getBounds2D().equals(area.getBounds2D()))
+      return false;
+
+    if (solids.size() != area.solids.size()
+        || holes.size() != area.holes.size())
+      return false;
+
+    Vector pathA = new Vector();
+    pathA.addAll(solids);
+    pathA.addAll(holes);
+    Vector pathB = new Vector();
+    pathB.addAll(area.solids);
+    pathB.addAll(area.holes);
+
+    int nPaths = pathA.size();
+    boolean[][] match = new boolean[2][nPaths];
+
+    for (int i = 0; i < nPaths; i++)
+      {
+	for (int j = 0; j < nPaths; j++)
+	  {
+	    Segment p1 = (Segment) pathA.elementAt(i);
+	    Segment p2 = (Segment) pathB.elementAt(j);
+	    if (! match[0][i] && ! match[1][j])
+	      if (p1.pathEquals(p2))
+		match[0][i] = match[1][j] = true;
+	  }
+      }
+
+    boolean result = true;
+    for (int i = 0; i < nPaths; i++)
+      result = result && match[0][i] && match[1][i];
+    return result;
   }
 
+  /**
+   * Transforms this area by the AffineTransform at
+   */
   public void transform(AffineTransform at)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    for (int i = 0; i < solids.size(); i++)
+      ((Segment) solids.elementAt(i)).transformSegmentList(at);
+    for (int i = 0; i < holes.size(); i++)
+      ((Segment) holes.elementAt(i)).transformSegmentList(at);
+
+    // Note that the orientation is not invariant under inversion
+    if ((at.getType() & AffineTransform.TYPE_FLIP) != 0)
+      {
+	setDirection(holes, false);
+	setDirection(solids, true);
+      }
   }
+
+  /**
+   * Returns a new Area equal to this one, transformed
+   * by the AffineTransform at
+   * @return the transformed area
+   */
   public Area createTransformedArea(AffineTransform at)
   {
     Area a = (Area) clone();
     a.transform(at);
     return a;
   }
+
+  /**
+   * Determines if the point (x,y) is contained within this Area.
+   *
+   * @return true if the point is contained, false otherwise.
+   */
   public boolean contains(double x, double y)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    int n = 0;
+    for (int i = 0; i < solids.size(); i++)
+      if (((Segment) solids.elementAt(i)).contains(x, y))
+	n++;
+
+    for (int i = 0; i < holes.size(); i++)
+      if (((Segment) holes.elementAt(i)).contains(x, y))
+	n--;
+
+    return (n != 0);
   }
+
+  /**
+   * Determines if the Point2D p is contained within this Area.
+   *
+   * @return true if the point is contained, false otherwise.
+   */
   public boolean contains(Point2D p)
   {
     return contains(p.getX(), p.getY());
   }
+
+  /**
+   * Determines if the rectangle specified by (x,y) as the upper-left
+   * and with width w and height h is completely contained within this Area,
+   * returns false otherwise.<P>
+   *
+   * This method should always produce the correct results, unlike for other
+   * classes in geom.
+   * @return true if the rectangle is considered contained
+   */
   public boolean contains(double x, double y, double w, double h)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    LineSegment[] l = new LineSegment[4];
+    l[0] = new LineSegment(x, y, x + w, y);
+    l[1] = new LineSegment(x, y + h, x + w, y + h);
+    l[2] = new LineSegment(x, y, x, y + h);
+    l[3] = new LineSegment(x + w, y, x + w, y + h);
+
+    // Since every segment in the area must a contour
+    // between inside/outside segments, ANY intersection
+    // will mean the rectangle is not entirely contained.
+    for (int i = 0; i < 4; i++)
+      {
+	for (int path = 0; path < solids.size(); path++)
+	  {
+	    Segment v;
+	    Segment start;
+	    start = v = (Segment) solids.elementAt(path);
+	    do
+	      {
+		if (l[i].hasIntersections(v))
+		  return false;
+		v = v.next;
+	      }
+	    while (v != start);
+	  }
+	for (int path = 0; path < holes.size(); path++)
+	  {
+	    Segment v;
+	    Segment start;
+	    start = v = (Segment) holes.elementAt(path);
+	    do
+	      {
+		if (l[i].hasIntersections(v))
+		  return false;
+		v = v.next;
+	      }
+	    while (v != start);
+	  }
+      }
+
+    // Is any point inside?
+    if (! contains(x, y))
+      return false;
+
+    // Final hoop: Is the rectangle non-intersecting and inside, 
+    // but encloses a hole?
+    Rectangle2D r = new Rectangle2D.Double(x, y, w, h);
+    for (int path = 0; path < holes.size(); path++)
+      if (! ((Segment) holes.elementAt(path)).isSegmentOutside(r))
+	return false;
+
+    return true;
   }
+
+  /**
+   * Determines if the Rectangle2D specified by r is completely contained
+   * within this Area, returns false otherwise.<P>
+   *
+   * This method should always produce the correct results, unlike for other
+   * classes in geom.
+   * @return true if the rectangle is considered contained
+   */
   public boolean contains(Rectangle2D r)
   {
     return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
   }
 
+  /**
+   * Determines if the rectangle specified by (x,y) as the upper-left
+   * and with width w and height h intersects any part of this Area.
+   * @return true if the rectangle intersects the area, false otherwise.
+   */
   public boolean intersects(double x, double y, double w, double h)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (solids.size() == 0)
+      return false;
+
+    LineSegment[] l = new LineSegment[4];
+    l[0] = new LineSegment(x, y, x + w, y);
+    l[1] = new LineSegment(x, y + h, x + w, y + h);
+    l[2] = new LineSegment(x, y, x, y + h);
+    l[3] = new LineSegment(x + w, y, x + w, y + h);
+
+    // Return true on any intersection
+    for (int i = 0; i < 4; i++)
+      {
+	for (int path = 0; path < solids.size(); path++)
+	  {
+	    Segment v;
+	    Segment start;
+	    start = v = (Segment) solids.elementAt(path);
+	    do
+	      {
+		if (l[i].hasIntersections(v))
+		  return true;
+		v = v.next;
+	      }
+	    while (v != start);
+	  }
+	for (int path = 0; path < holes.size(); path++)
+	  {
+	    Segment v;
+	    Segment start;
+	    start = v = (Segment) holes.elementAt(path);
+	    do
+	      {
+		if (l[i].hasIntersections(v))
+		  return true;
+		v = v.next;
+	      }
+	    while (v != start);
+	  }
+      }
+
+    // Non-intersecting, Is any point inside?
+    if (contains(x, y))
+      return true;
+
+    // What if the rectangle encloses the whole shape?
+    Point2D p = ((Segment) solids.elementAt(0)).getMidPoint();
+    if ((new Rectangle2D.Double(x, y, w, h)).contains(p))
+      return true;
+    return false;
   }
+
+  /**
+   * Determines if the Rectangle2D specified by r intersects any
+   * part of this Area.
+   * @return true if the rectangle intersects the area, false otherwise.
+   */
   public boolean intersects(Rectangle2D r)
   {
     return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
   }
+
+  /**
+   * Returns a PathIterator object defining the contour of this Area,
+   * transformed by at.
+   */
   public PathIterator getPathIterator(AffineTransform at)
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    return (new AreaIterator(at));
   }

*** Patch too long, truncated ***



More information about the kaffe mailing list