JDK-4558900 : Pathiterator is inconsistent between GeneralPath and Area objects
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: solaris_2.6
  • CPU: sparc
  • Submitted: 2001-12-07
  • Updated: 2006-03-09
  • Resolved: 2006-03-09
Related Reports
Duplicate :  
Description
Name: jk109818			Date: 12/07/2001


java version "1.2.1"
Solaris VM (build Solaris_JDK_1.2.2_05,native threads,subwjit)

Querying the pathiterator returns two different set of coordinates for the same
geometry.

Run this example:

import java.io.*;
import java.util.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.*;
import java.awt.*;

import java.lang.Math;

public class tempShape  {


 public static void getPoints(PathIterator pi){
  double [] coords = new double[6];
  int curseg;
  Point2D.Double p;
  while (!pi.isDone()){
    curseg = pi.currentSegment(coords);
    switch(curseg){
      case PathIterator.SEG_MOVETO:{
         p = new Point2D.Double(coords[0],coords[1]);
	  System.out.println("MOVE TO:"+p.x+" "+p.y);
          break;
      }
      case PathIterator.SEG_LINETO:{
         p = new Point2D.Double(coords[0],coords[1]);
	 System.out.println("LINE TO:"+p.x+" "+p.y);
          break;
      }
      case PathIterator.SEG_CLOSE:{
	   System.out.println("CLOSE");
           break;
      }
      default:{
        System.out.println("Undefined Seg type");
        break;
      }
    }
    pi.next();
  }
 }
 public static void main(String args[]){
    GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
    gp.moveTo(40705662f, 104785693f);
    gp.lineTo(40705878f, 104785687f);
    gp.lineTo(40705845f, 104785332f);
    gp.lineTo(40705799f,104784340f);
    gp.lineTo(40706901f, 104784342f);
    gp.lineTo(40706896f, 104785325f);
    gp.lineTo(40706900f, 104785409f);
    gp.lineTo(40706878f, 104785483f);
    gp.lineTo(40706813f, 104785578f);
    gp.lineTo(40706776f, 104785621f);
    gp.lineTo(40706720f, 104785684f);
    gp.lineTo(40705846f, 104785691f);
    gp.lineTo(40705662f, 104785693f);
    gp.closePath();
    Area a = new Area(gp);
    System.out.println("****POINTS FROM GENERALPATH OBJECT****");
    getPoints(gp.getPathIterator(null));
    System.out.println("****POINTS FROM AREA OBJECT****");
    getPoints(a.getPathIterator(null));
 }
}



The results from gp.getPathIterator and a.getPathIterator should be the same.
But they are not.

Results returned:

****POINTS FROM GENERALPATH OBJECT****
MOVE TO:4.0705664E7 1.04785696E8
LINE TO:4.070588E7 1.04785688E8
LINE TO:4.0705844E7 1.04785328E8
LINE TO:4.07058E7 1.04784336E8
LINE TO:4.07069E7 1.04784344E8
LINE TO:4.0706896E7 1.04785328E8
LINE TO:4.07069E7 1.04785408E8
LINE TO:4.070688E7 1.0478548E8
LINE TO:4.0706812E7 1.04785576E8
LINE TO:4.0706776E7 1.04785624E8
LINE TO:4.070672E7 1.0478568E8
LINE TO:4.0705848E7 1.04785688E8
LINE TO:4.0705664E7 1.04785696E8
CLOSE
****POINTS FROM AREA OBJECT****
MOVE TO:4.07058E7 1.04784336E8
LINE TO:4.0705844E7 1.04785328E8
LINE TO:4.070587997066911E7 1.0478568770669112E8
LINE TO:4.0705879970668346E7 1.0478568770669112E8
LINE TO:4.070672E7 1.0478568E8
LINE TO:4.0706776E7 1.04785624E8
LINE TO:4.0706812E7 1.04785576E8
LINE TO:4.070688E7 1.0478548E8
LINE TO:4.07069E7 1.04785408E8
LINE TO:4.0706896E7 1.04785328E8
LINE TO:4.07069E7 1.04784344E8
LINE TO:4.07058E7 1.04784336E8
CLOSE
MOVE TO:4.0705879970668346E7 1.0478568770669112E8
LINE TO:4.0705848E7 1.04785688E8
LINE TO:4.0705664E7 1.04785696E8
LINE TO:4.070588E7 1.04785688E8
LINE TO:4.070587997066911E7 1.0478568770669112E8
CLOSE

The same problem was duplicated on java version 1.3.1-b24 on NT. The second path
 (5 points) returned from the Area object is inaccuarate and extraneous.
(Review ID: 136975) 
======================================================================

Comments
EVALUATION There are two, somewhat related, bugs here. The first bug is that the example path cannot be expressed in single precision floating point numbers. Since GeneralPath only offers floating point path construction methods, there is no way to represent this path in a GeneralPath object. The precision limitation of the GeneralPath object was actually a conscious design choice, but not very well documented. In fact, only the types of the path construction methods give any clue as to the internal precision it maintains. The float precision is enough for 99% of all cases, but not enough for cases where huge datasets require a large domain of coordinates from which only tiny subsets are extracted at a time for display. As a result, the path that ends up in the GeneralPath object is not the path that would seem to be intended from looking at the numbers (in particular, in looking at what the numbers would be if they weren't explicitly turned into float constants by their trailing "f" format). The second bug is that the Area object seems to produce a "different" answer for what the path is. The Area object does do a faithful job of representing the same path as was stored in the GeneralPath object, but it may not look like the same path for two reasons. The first reason is that the float precision caused the path to change its outline subtly and the Area class is representing the new modified path, not the original intended path. With the loss of precision, the shape became a self-intersecting shape and so the Area class separates that self-intersecting shape into 2 non-intersecting shapes. Since the full precision shape was not self-intersecting, this sudden presence of 2 sub-paths may seem jarring, but is accurate with respect to the float expression of the path. The second reason that the shape does not appear to be the same is that the Area class digests the geometry of the outline and then reexpresses the shape in its own way. Even if there was no precision loss, the path readback would be different because the Area normalizes a Shape into top-down non-intersecting shapes and so not only can there be more or fewer sub-paths, but the ordering of the segments can be very different. Indeed, repeating the experiment with a prototype "double GeneralPath" shows that the Area class chooses to store the path in reverse order starting with the fourth coordinate (which is the coordinate with the smallest Y coordinate). Bug 4172661 requests a double precision version of GeneralPath and so this bug is essentially a duplicate of that bug as a double precision path object would not suffer from these limitations. As such, I will close this bug as a duplicate of 4172661.
09-03-2006

WORK AROUND Name: jk109818 Date: 12/07/2001 The workaround is not to use the Area object. But that restricts functionality as add() and subtract() methods of the Area object are essential for the application. ======================================================================
11-06-2004