Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4172661
Votes 13
Synopsis GeneralPath needs double version
Category java:classes_2d
Reported Against 1.4 , 1.2.2 , 1.2beta4 , merlin-beta3
Release Fixed mustang(b77)
State 10-Fix Delivered, request for enhancement
Priority: 3-Medium
Related Bugs 6297129 , 4270230 , 4558900 , 4632108 , 6396047 , 6404847 , 4718569
Submit Date 10-SEP-1998
Description



The GeneralPath and Area classes offer one of the most powerful
GIS platforms available anywhere today, except for one problem:
float is not sufficiently precise to use for global coordinate models
(eg a float Longitude has a precision of about 3 meters, far too coarse
for modern GIS). GeneralPath needs a double version, just like the
float and double versions of Line2D, Rectangle2D etc.
(Review ID: 37513)
======================================================================
Posted Date : 2006-01-23 23:24:08.0

Suggested implementation by java.net member leouser
(Refer to attached file "4172661-Fix-Received.eml" for the entire text)

FIX DETAILS
BUG ID: 4172661 GeneralPath needs double version
FILES AFFECTED: java.awt.geom package, java.awt.geom.GeneralPath class
 JDK VERSION
 jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin


Discusion(embeded in test case as well):
/**
 * BUG ID: 4172661 GeneralPath needs double version
 * This has proven to be a vexing problem to solve.  I first looked
 * at it from a storage standpoint: maybe I can just make a Storage
 * class internal to the GeneralPath and have the GP morph its storage
 * dependant upon how the user wanted to use it.  This road proved bad.
 * There is not a good way to perform operations on a float array when
 * you are targeting a double array anc vice versa.  We could have set
 * up a flag and have the thing process differently but the code would
 * have been grotesque and repetitive.
 *
 * I thought about using generics for a solution but there is not a good way
 * to bound it to only accept Float and Double.  There are other issues to,
 * but that is the main one that I see as blocking it.
 *
 * Therefore I moved into looking at solution 3: refactoring out a superclass
 * called AbstractGeneralPath and deriving GeneralPath from it.  This wasn't
 * too difficult of a chore.  Many a method could be swapped up if a much
 * smaller utility method was implemented.  After pushing as much that seems
 * reasonable upwards I created the DoubleGeneralPath.  The DoubleGeneralPath
 * is a mirror image of the GeneralPath in terms of implementation.  The variation
 * is in swapping double for float --> and that's almost it!  Hence we have
 * 2 files with 500+ lines of quasi code duplication.  I say quasi because
 * they look the same, but when you are operating on double arrays and
 * float arrays they are different pieces of code.  Their essence is what is
 * similar.
 *
 * All of this goes back to the statement: "Unfortunately it is difficult to 
 * figure out how to integrate this new capability into the existing class
 * structure...".  Yes, as I have digged it has certainly proven difficult.
 * Then again, the mirrors are just 10 methods in each class.  On counting
 * 17 methods were able to be moved upward as well as a whole slew of fields.
 * So roughly 2/3rds of the GeneralPath could be turned into an AbstractGeneralPath.
 *
 * I have considered making the two swappable with each other.  But this would
 * entail making the AbstractGeneralPath public and adding a bunch of useless
 * mirror methods to each of the classes.  From reading the remarks in the
 * RFE report it seems the users don't want to use the GeneralPath at all
 * because of its float implementation.  The DoubleGeneralPath could be the
 * preferred solution for them.
 *
 * WHY THE NAME?  Well because I haven't come up with a better one!  We could
 * try: DBLGeneralPath, DGeneralPath, GeneralPathD, DoubleBackedGeneralPath,
 * etc... but these are worse
 * than DoubleGeneralPath.  At least with DoubleGeneralPath you think to yourself
 * hmmm Double, oh yeah double.  With the others you think what does D stand for?
 *
 * ANTI-RATIONALE:
 * This adds another public class to the awt.geom package.  The new class
 * does not mirror the structure of other Double/Float pairs in this package,
 * making it harder to remember.  It also adds 2 non-public classes to the
 * package making the file count larger.  Given these, I don't believe any
 * of this is avoidable.  Im not sure if it is even possible if we started
 * from scratch to design these things like the others.  That's something
 * I have to contemplate.
 *
 * TESTING STRATEGY:
 * 1. Create a visual test.  We compare the doodles rendered by GeneralPath
 * and DoubleGeneralPath by iterating through a cycle of these two.  The
 * doodles should appear the same.  We create the Paths by lineTo, curveTo
 * and quadTo.
 * 2. Exercise methods on the DGP and GP interface.
 * This test class is probably going to expand as time goes on.  When you
 * look at all the things that have changed it becomes apparent that doodle
 * testing isn't going to be enough.  It would be nice to the see a visual
 * test that can show off the differences between double and float.  Right
 * now the tests don't illustrate this... .
 *
 * FILES AFFECTED: java.awt.geom package, java.awt.geom.GeneralPath class
 *
 * JDK VERSION
 * jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
 *
 * test ran succesfully on a SUSE 7.3 Linux distribution
 *
 * Brian Harry
 *   xxxxx@xxxxx  
 * Jan 19, 2006
 *
 */

CODE(DIFFS FIRST, then new files):

--- /home/nstuff/java6/jdk1.6.0/java/awt/geom/GeneralPath.java	Thu Dec 15 02:16:27 2005
+++ /home/javarefs/java/awt/geom/GeneralPath.java	Thu Jan 19 12:21:09 2006
@@ -33,39 +33,15 @@
[... snip ...]
Posted Date : 2006-01-23 23:24:09.0
Work Around
N/A
Evaluation
This is a frequent request.  Unfortunately it is difficult to figure out
how to integrate this new capability into the existing class structure
since GeneralPath doesn't follow the regular 2D.{Float,Double} class
design of java.awt.geom.  We don't have any resources to solve this right
now either, unfortunately.

  xxxxx@xxxxx   2000-09-27

Two more floating point precision issues have been identified.

See 4632108 which discusses float precision issues when transforming Area
objects (even though they have double precision internally they depend
on other mechanisms for the transformation which do not have double
precision).

Also see 6297129 which discusses float precision issues in the
AffineTransform class in its createTransformedShape method which uses
a GeneralPath object to store the transformed geometry.  That bug
cannot be fixed until this bug is addressed.

  xxxxx@xxxxx   2005-07-15 00:55:10 GMT
Posted Date : 2005-07-15 00:55:10.0

Contribution-forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?forumID=1463&messageID=10989
Posted Date : 2006-01-23 23:24:09.0

The contributed fix was reviewed and we decided to go with a slightly
modified version of the contributed fix.  We introduced a new parent
class that more closely resembles the design of the existing classes
in the java.awt.geom package:

                Path2D
                /    \
            Float    Double
              |
         GeneralPath

GeneralPath becomes a "legacy class", but maintains the same exact API
as it originally had with the addition of inheriting (and implementing
via its Float parent) double versions of all of its path construction
methods from the base Path2D class.
Posted Date : 2006-03-09 21:48:43.0
Comments
  
  Include a link with my name & email   

Submitted On 07-MAY-2002
johnatha
Why not replace the existing single precision GeneralPath 
code with double precision code? Then there's no need to 
add another class.


Submitted On 07-MAY-2002
johnatha
BTW, try this workaround for GIS -- it's what I do. This 
works for small geographic polygons on a flat world.

1. Keep double precision values for the geographic points.

2. Create an internal mapping of the geographic polygon 
using a GeneralPath object. When creating the internal 
representation, subtract the southernmost latitude from 
each latitude and the westernmost longitude from each 
longitude before converting to single precision. This will 
minimize the magnitude of the values, making the most of 
the precision a single-precision value offers. (If the 
geographic polygon is really small, you may suffer a 
serious loss of precision. However, you are probably no 
worse off than before.)

3. Test for point containment by shifting the point into 
the "mapped polygon space" before calling 
GeneralPath.contains(point).

4. For polygon intersection tests, map the whole other 
geographic polygon into the mapped polygon space before 
checking for polygon intersection with Area.intersects().

Don't forget to handle the dateline discontinuity!


Submitted On 19-JUL-2003
Nikita04
The documentation of GeneralPath should at least mention 
that it internally stores coordinates in floats because its 
methods take doubles. This could potentially confuse the 
client.


Submitted On 23-SEP-2004
kbarthel
Creating versions of  GeneralPath based on double or even Point2D should not take more than an hour.  So resources seem to be very scarce...


Submitted On 08-JAN-2005
Ernimril
A simple solution is to have an internal flag "useFloat" and add a constructor that can take that flag. Methods that add data will then have to check the flag and fill in the right array, a bit ugly, but trivial and from the outside nothing changes. 
Always storing points as double is also a possible solution, but that will require lots of more memory. 


Submitted On 30-MAR-2005
bilco
I've just had to create a Double Implementation of the 
GeneralPath class, by literally changing the internal
array variable type. (Plus a couple of other minor changes
caused by package differences).

Come on Sun, get the Finger out !
All rendering nees to be double-based.



PLEASE NOTE: JDK6 is formerly known as Project Mustang