Bug 393874 - Inaccuracy of Draw2d
Summary: Inaccuracy of Draw2d
Status: NEW
Alias: None
Product: GEF
Classification: Tools
Component: GEF-Legacy Draw2d (show other bugs)
Version: 3.7   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: gef-inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 392759 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-11-08 08:21 EST by Jan Krakora CLA
Modified: 2013-01-24 06:25 EST (History)
2 users (show)

See Also:


Attachments
100% zoom (4.59 KB, image/png)
2012-11-08 08:22 EST, Jan Krakora CLA
no flags Details
300% zoom (22.47 KB, image/png)
2012-11-08 08:22 EST, Jan Krakora CLA
no flags Details
50% zoom (1.86 KB, image/png)
2012-11-08 08:27 EST, Jan Krakora CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Krakora CLA 2012-11-08 08:21:44 EST
Hi,

I would like to know why is the draw2d so inaccurate when zooming is in use.
I have added two screenshots with 100%(good.png) and 300%(bad.png) zoom. You can see the gaps between cells.
Comment 1 Jan Krakora CLA 2012-11-08 08:22:20 EST
Created attachment 223351 [details]
100% zoom
Comment 2 Jan Krakora CLA 2012-11-08 08:22:44 EST
Created attachment 223352 [details]
300% zoom
Comment 3 Jan Krakora CLA 2012-11-08 08:27:06 EST
Created attachment 223353 [details]
50% zoom
Comment 4 Alexander Nyßen CLA 2012-11-12 13:31:11 EST
Did you make use of the double-precision geometry classes when performing calculations with your layout constraints. This may be caused by rounding effects that occur when using the integer-based precision.
Comment 5 Alexander Nyßen CLA 2012-11-12 13:35:28 EST
*** Bug 392759 has been marked as a duplicate of this bug. ***
Comment 6 Jan Krakora CLA 2012-11-13 06:11:42 EST
Well, there is a test case. You can see there are gaps between cells with zoom bigger than 1.2 or something. 
If you debug it, you will find that bounds are set correctly (it means all figures are just next to each other), but drawing is somehow broken.

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.GridData;
import org.eclipse.draw2d.GridLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.Layer;
import org.eclipse.draw2d.LineBorder;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.RectangleFigure;
import org.eclipse.draw2d.ScalableLayeredPane;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;


public class Test {
	
	/**
	 * This is a separator figure. Just using the LineBorder leads to double lines
	 * between all cells in the table.
	 */
	private static class Separator extends RectangleFigure {

		public Separator() {
			setOutline(false);
			setBackgroundColor(ColorConstants.black);
		}
		
	}

	public static void main(String[] args) {
		final Display display = new Display();
		final Shell shell = new Shell(display);
		shell.setLayout(new FillLayout());
		
		final FigureCanvas canvas = new FigureCanvas(shell);
		final ScalableLayeredPane pane = new ScalableLayeredPane();
		final Layer layer = new Layer();
		layer.setLayoutManager(new XYLayout());
		
		final IFigure table = new Figure();
		table.setBackgroundColor(display.getSystemColor(SWT.COLOR_WHITE));
		table.setBorder(new LineBorder(1));
		table.setOpaque(true);
		final GridLayout layout = new GridLayout();
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		layout.horizontalSpacing = 0;
		layout.verticalSpacing = 0;
		layout.numColumns = 9;
		table.setLayoutManager(layout);
		
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 5; j++) {
				final Label label = new Label("Test");
				label.setBackgroundColor(display.getSystemColor(SWT.COLOR_GRAY));
				label.setOpaque(true);
				label.setBorder(new MarginBorder(2));
				
				GridData gridData = new GridData();
		    	gridData.horizontalAlignment = SWT.FILL;
		    	gridData.verticalAlignment = SWT.FILL;
				table.add(label, gridData);
				
				if (j < 4) {
					gridData = new GridData();
					gridData.horizontalAlignment = SWT.FILL;
					gridData.verticalAlignment = SWT.FILL;
					gridData.widthHint = 1;
					table.add(new Separator(), gridData);
				}
			}
			if (i < 2) {
				GridData gridData = new GridData();
				gridData.horizontalAlignment = SWT.FILL;
				gridData.verticalAlignment = SWT.FILL;
				gridData.heightHint = 1;
				gridData.horizontalSpan = 9;
				table.add(new Separator(), gridData);
			}
		}
		
		layer.add(table, new Rectangle(50, 50, -1, -1));
		pane.add(layer, "root layer");
		
		canvas.addMouseWheelListener(new MouseWheelListener() {
			
			@Override
			public void mouseScrolled(MouseEvent e) {
				double scale = pane.getScale();
				pane.setScale(e.count < 0 ? scale * 0.95 : scale * 1.05);
			}
		});
		canvas.setContents(pane);
		
		shell.open();
		shell.setSize(600, 600);
		
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

	}

}
Comment 7 BiM Mising name CLA 2012-11-16 08:42:34 EST
Hi,

How could we set precision to double Alexander ?

Regards,
BiM
Comment 8 Alexander Nyßen CLA 2012-11-18 12:20:35 EST
Well, you would have to make use of the double-based "Precision*" classes instead of the integer-based ones (e.g. PrecisionRectangle). 

However, from the example you provided I have the impression that the problem does not rely within your client code. It seems Label is not robust against rounding effects on scaling. But I am not sure how well we can circumvent this. I will have to dig deeper into it.
Comment 9 BiM Mising name CLA 2012-11-19 05:50:44 EST
Ok, thank you!
Comment 10 BiM Mising name CLA 2013-01-09 09:58:04 EST
Default figures as RectangleFigure (for example) using Rectangle class and not PrecisionRectangle class. Do I need to redefine all figures ?
Comment 11 BiM Mising name CLA 2013-01-10 05:07:31 EST
Also, on normal zoom (100%), if you draw two ellipses side to side, the second should start where the first stop, but the second ellipse start one pixel after the first one. This problem is only increase by zooming.

See bug 392759 to understand what I speak about.
Comment 12 Jan Krakora CLA 2013-01-24 06:25:14 EST
There is another simple runnable example showing inaccuracy of the draw2d:
public class Example {

	public static void main(String[] args) {
		Display d = new Display();
		
		final Shell shell = new Shell();
		shell.setLayout(new FillLayout());
		
		FigureCanvas canvas = new FigureCanvas(shell);
		canvas.setBackground(ColorConstants.white);
		
		final ScalableLayeredPane pane = new ScalableLayeredPane();
		canvas.setContents(pane);
		
		Layer layer = new Layer();
		layer.setLayoutManager(new XYLayout());
		
		pane.add(layer);
		
		final IFigure panel = new Figure();
		panel.setBorder(new LineBorder());
		panel.setLayoutManager(new StackLayout());
		
		final IFigure content = new Panel();
		content.setLayoutManager(new StackLayout());

		RectangleFigure rec = new RectangleFigure();
		rec.setBackgroundColor(ColorConstants.yellow);
		content.add(rec);
		
		panel.add(content);
		
		final Point location = new PrecisionPoint(50, 50);
		final Dimension dimension = new PrecisionDimension(100, 60);
		layer.add(panel, new PrecisionRectangle(location, dimension));
		
		canvas.addMouseListener(new MouseAdapter() {
			
			@Override
			public void mouseUp(MouseEvent e) {
				if (e.button == 1) {
					pane.setScale(pane.getScale() + 0.1);
				} else {
					pane.setScale(pane.getScale() - 0.1);
				}
				shell.setText("Zoom: " + pane.getScale());
			}
			
		});
		
		shell.setText("Zoom: " + pane.getScale());
		shell.setSize(600, 400);
		shell.open();
		
		while (!shell.isDisposed()) {
			if (!d.readAndDispatch()) {
				d.sleep();
			}
		}
		d.dispose();
	}

}

click left - it scales up
click right - it scales down

I would expect yellow rectangle with black border just around that rectangle. The border line should scale.

But when you scale, it behaves really weird. The border is bad.