Bug 175163 - [Geometry] Rectangle width and height are interpreted inconsistently
Summary: [Geometry] Rectangle width and height are interpreted inconsistently
Status: NEW
Alias: None
Product: GEF
Classification: Tools
Component: GEF-Legacy Draw2d (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P3 normal with 1 vote (vote)
Target Milestone: ---   Edit
Assignee: gef-inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 292164
Blocks:
  Show dependency tree
 
Reported: 2007-02-22 13:42 EST by fictivy CLA
Modified: 2012-05-14 02:51 EDT (History)
2 users (show)

See Also:


Attachments
Code example (1.79 KB, application/octet-stream)
2007-02-22 13:44 EST, fictivy CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description fictivy CLA 2007-02-22 13:42:30 EST
The width and height of rectangles or in methods that take width/height arguments seem to have two different meaning in different places in draw2d:
 a) The difference between the rightmost and leftmost (top and bottom) pixel coordinates.
 b) The actual width in pixels.

width (b) is 1 pixel greater than width (a) for the same screen display - e.g. for a rectangle consisting of a single pixel, (a) is 0 while (b) is 1.

Graphics.drawRectangle(), Rectangle.bottom() and Rectangle.right() use meaning (a)
Graphics.fillRectangle() and clipping of figures use meaning (b)



Code example: 
============



import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Main {
	public static void main(String args[]){
		Shell shell = new Shell();
		shell.setBackground (ColorConstants.white);
		shell.open();
		
		LightweightSystem lws = new LightweightSystem(shell);
		IFigure root = new Figure() {
			@Override
			protected void paintFigure (Graphics g) {
				// drawRectangle draws 2x2 pixels (right = left + width) ...
		        g.setForegroundColor (ColorConstants.black);
				g.drawRectangle (1, 1, 1, 1);
		        
				// ... but fillRectangle fills 1 pixel (right = left + width - 1)
				g.setBackgroundColor (ColorConstants.black);
				g.fillRectangle (5, 1, 1, 1);
				
				// Rectangle.right() and Rectangle.bottom() are consistent with drawRectangle interpretation
				Rectangle rect = new Rectangle (1, 1, 1, 1);
				g.drawText (String.format ("[%s..%s, %s..%s]%n", rect.x, rect.right(), rect.y, rect.bottom()),
						5, 10);
			}
		};
		
		// clipping behavior is consistent with fillRectangle interpretation: 
		// the figure is clipped at 2x2 pixels 
		root.add (new Figure () {
			private final Rectangle r = new Rectangle (20, 1, 2, 2);
			
			@Override
			public Rectangle getBounds () {
				return r;
			}
			
			@Override
			protected void paintFigure (Graphics g) {
				g.drawRectangle (r);
			}
		});

		
		lws.setContents (root);
		Display display = Display.getDefault();
		while (!shell.isDisposed ()) {
			if (!display.readAndDispatch ())
				display.sleep ();
		}
	}
}
Comment 1 fictivy CLA 2007-02-22 13:44:26 EST
Created attachment 59595 [details]
Code example
Comment 2 Alexander Nyßen CLA 2011-06-20 15:08:02 EDT
The inconsistency w.r.t. to drawRectangle() and fillRectangle() is indeed caused by SWT (the Draw2d graphics just forwards to the SWT GC) and has (at least concerning drawRectangle() method) been addressed by bug #292164.
Comment 3 Alex Bradley CLA 2012-05-12 04:53:54 EDT
There are related oddities in the way Rectangle handles a rectangle's bottom and right boundaries; this can be seen by comparing the Rectangle(Point, Point) constructor and the getBottomRight(), etc. methods, or the contains(Rectangle) and contains(Point) methods. As can be seen from the JUnit code snippet below, Rectangle currently has the following mathematically puzzling properties:

 (1) A Rectangle is not equal to the smallest Rectangle containing its top left and bottom right corners.
 (2) A Rectangle contains itself, but does not contain its own bottom right corner.

Perhaps, at minimum, the Javadoc for Rectangle(Point, Point) should be updated to make (1) clear?

Snippet follows:

  Rectangle r1 = new Rectangle(20, 30, 44, 62);
  Rectangle r2 = new Rectangle(r1.getTopLeft(), r1.getBottomRight());
  assertEquals(r1, r2);                         // fails
  assertTrue(r1.contains(r1));                  // succeeds
  assertTrue(r1.contains(r1.getBottomRight())); // fails
Comment 4 Alexander Nyßen CLA 2012-05-14 02:51:01 EDT
(In reply to comment #3)
> There are related oddities in the way Rectangle handles a rectangle's bottom
> and right boundaries; this can be seen by comparing the Rectangle(Point, Point)
> constructor and the getBottomRight(), etc. methods, or the contains(Rectangle)
> and contains(Point) methods. As can be seen from the JUnit code snippet below,
> Rectangle currently has the following mathematically puzzling properties:
> 
>  (1) A Rectangle is not equal to the smallest Rectangle containing its top left
> and bottom right corners.
>  (2) A Rectangle contains itself, but does not contain its own bottom right
> corner.
> 
> Perhaps, at minimum, the Javadoc for Rectangle(Point, Point) should be updated
> to make (1) clear?
> 
> Snippet follows:
> 
>   Rectangle r1 = new Rectangle(20, 30, 44, 62);
>   Rectangle r2 = new Rectangle(r1.getTopLeft(), r1.getBottomRight());
>   assertEquals(r1, r2);                         // fails
>   assertTrue(r1.contains(r1));                  // succeeds
>   assertTrue(r1.contains(r1.getBottomRight())); // fails

Yes, that's quite another one. IMHO the Draw2d geometry classes are all kind of a mess and - being bound to API compatibility - there's actually not much we can do against it. I have tried to clean things up as far as API compatibility allowed in the 3.6 release train, and now I think we should simply leave it as it is and focus on the new Geometry API we have started to work on in terms of GEF4 (see bug # 355997 for details). 

GEF4's Geometry API is completely double-based (no separation between integer and double precision) and deals with above mentioned inconsistency by regarding the bottom and right corner of a rectangle to be part of it (as any other polygon does). We have not yet provided a first release (we are currently working on the last large contribution to provide implementations for Regions and Rings) but will do so for Juno and will then port the Draw2d/GEF (MVC) code base to it as a starting point for GEF4.