piccolo2d/piccolo2d.java

Cannot draw veritical and horizontal lines of 0 width stroke using PPath

Closed this issue · 9 comments

mro commented

Originally reported on Google Code with ID 221

What steps will reproduce the problem?
1. Use the following code:
PPath line = PPath.createLine(5f, 10f, 5f, 100f);
line.setStroke(new BasicStroke(0));

2. The following code too:
PPath line = new PPath();
line.setStroke(new BasicStroke(0));
line.moveTo(5f, 10f);
line.lineTo(5f, 100f);

What is the expected output? What do you see instead?
A horizontal or vertical line of 1 pixel wide should be drawn  in any zoom level. However
the line just can not be seen!

What version of the product are you using? On what operating system?
Piccolo2d.java 1.3.1 is used on java 1.6.0_14-b08, Windows XP SP3.

Reported by v116mo on 2011-07-23 10:54:06

mro commented
Shouldn't a BasicStroke(0) yield a stroke that is zero pixels wide?  Maybe you need
to create a BasicStroke(1) to get a stroke of 1 pixel wide.

Reported by samrreid on 2011-07-23 16:35:23

mro commented
In the Developer's FAQ http://www.piccolo2d.org/learn/dev-faq.html
section "Why is my app so slow?", it states as follows:

"...., If you need to render the strokes, you could try setting the stroke width to
zero, which has the effect of always drawing a one-pixel wide stroke. ...."

And it brings very significant performance improvement using BasicStroke(0).

The bug occurs when either x1 == x2, or y1 == y2 in the case of
PPath.createLine(x1, y1, x2, y2);


Reported by v116mo on 2011-07-24 03:36:41

mro commented
I can confirm the bug with my system

* Piccolo2d.java 1.3.1, 
* java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.3) (fedora-59.1.10.3.fc15-i386)
OpenJDK Server VM (build 20.0-b11, mixed mode)
* Fedora 15 2.6.40.6-0.fc15.i686

If x1!=x2 or y1!=y2 then a one pixel width line is drawn in every zoom level, for stroke
width zero. Attached is a test program to show the issue.

Reported by funnyacc on 2011-10-22 16:10:31


- _Attachment: [ZeroWidthStrokeBug.java](https://storage.googleapis.com/google-code-attachments/piccolo2d/issue-221/comment-3/ZeroWidthStrokeBug.java)_
mro commented
Is this a Piccolo2D bug or an AWT one?  I don't see any mention of 1-pixel wide stroke
width with BasicStroke(0) in the JDK javadocs.

Reported by heuermh on 2011-10-26 03:12:51

mro commented
"If you need to render the strokes, you could try setting the stroke width to zero,
which has the effect of always drawing a one-pixel wide stroke."

This is true for the Win7/Java1.6.27 system I've tested it on, but afaik Piccolo doesn't
have logic that ensures this, so it would be a side effect of what the JDK does. If
the JDK doesn't document this as a contract, then it must be inadvertent or a bug and
not to be relied on.

We might want to remove that comment from the developer faq.

Reported by atdixon on 2011-11-01 23:28:11

mro commented
Adding example

$ svn commit -m "Issue 221 ; adding ZeroWidthStrokeBug to examples.issues" .
Committed revision 1169.

Reported by heuermh on 2012-08-31 16:59:34

mro commented

Reported by heuermh on 2012-08-31 20:29:30

  • Labels added: Toolkit-Piccolo2D.Java
mro commented
The attached java examples draws vertical and horizontal lines with BasicStroke(0).
It works correctly. I think the problem is not in java itself.

Reported by v116mo on 2012-12-09 06:12:21


- _Attachment: [ZeroWidthStroke.java](https://storage.googleapis.com/google-code-attachments/piccolo2d/issue-221/comment-8/ZeroWidthStroke.java)_

In PNode.setBounds(), there is the logic to check line's width and height. With BasickStroke(0), it's width will be 0 for vertical lines, it's height will be 0 for horizontal lines. The bounds is reset to EMPTY, so the horizontal and vertical lines cannot be drawn correctly. If the checking is changed to if (width < 0 || height < 0). The issue is resolved. Hope it helps!

public boolean setBounds(final double x, final double y, final double width, final double height) {
        if (bounds.x != x || bounds.y != y || bounds.width != width || bounds.height != height) {
            bounds.setRect(x, y, width, height);

            if (width < 0 || height < 0) {   /* changed to include 0 width/height */
                bounds.reset();
            }

            internalUpdateBounds(x, y, width, height);
            invalidatePaint();
            signalBoundsChanged();
            return true;
        }
        // Don't put any invalidating code here or else nodes with volatile
        // bounds will
        // create a soft infinite loop (calling Swing.invokeLater()) when they
        // validate
        // their bounds.
        return false;
    }