Skip to main content

line2D length problem

4 replies [Last post]
aussielew
Offline
Joined: 2008-08-05

Hi All,

Hoping someone can help me with this one ...?

I need to draw lines with a width greater than 1 and the lengths may be a real value so I am using
Line2D.Float.

I need to draw exact (calculated)lengths so I am using CAP_BUTT so the line does not have any additional
apparent length (the other CAP options have the effect of adding the line width to the line)

The problem I am having is that once the line width is set to greater than 1, the lines are actually drawn 1 pixel short.
I am sure I am missing soething simple here but have spent a lot of time on it!
I know that I can work around it but do I need to, I shouldn't have to + 1 to my line lengths depending on there width?

The following demonstrates the problem. I am drawing on a JPanel within a JFrame, JDK/JRE 6, Windows

g2.setStroke(new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
g2.setColor(Color.BLACK);
g2.draw(new Line2D.Float(20,40,20,75)); // vertical line as marker only

// draw 2 lines with line width of 1
g2.setColor(Color.RED);
g2.draw(new Line2D.Float(20,60,21,60)); // draws 2 pixel line as expected
g2.draw(new Line2D.Float(22,60,23,60)); // draws 2 pixel line as expected ... total of 4 pixels

// draw 2 lines with line width of 10
g2.setStroke(new BasicStroke(10,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
g2.setColor(Color.GREEN);
g2.draw(new Line2D.Float(20,70,21,70)); // draws 1 pixel only at 20,70
g2.setColor(Color.YELLOW);
g2.draw(new Line2D.Float(22,70,23,70)); // draws 1 pixel only at 22,70... so, each line is shortened by 1 pixel
// this applies to any line width > 1

Thanks
Lew

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
aussielew
Offline
Joined: 2008-08-05

Thanks Jim,
After all the time I've spent on this it seems I still do not full understand it!

Everything I have read on this seems to confirms my thinking, it just doesn't translate when using line widths > 1.
My understanding is (or was) that the arguments to the Line2D methods , as either x,y coordinates or Points set the "endpoints" of the line.

If I draw a line (with line width of 1) from coordinates 20,60 to 20,60 it would cover 1 pixel below and to the right of the coordinate which would be the pixel 20,60 (current user space).

So as 20,60 & 21,60 are two distinct coordinate points , if I draw a line using these coordinates as the endpoints, I expected to get a 2 pixel line length (and did with line width of 1).

Similarly if i set 2 Points to the coordinates above and use ..
setLine(Point2D p1, Point2D p2) it would cover 2 pixels. ( and does with line width of 1 but not with a width > 1

From the Sun APi Class Line2D docs ..
" setLine(Point2D p1, Point2D p2) Sets the location of the end points of this Line2D to the specified Point2D coordinates."

Without wishing to take the discussion away from the points above, the end cap options raise another issue..
If I had set CAP_SQUARE or ROUND with a line width of 1, where would it decide to add the additional pixel? Normally half the line width and adding it to each end point?
I guess this issue happens any time the line width is an odd pixel number.

....Lew

Jim Graham

Hi Lew,

You are describing the default behavior which assumes CAP_SQUARE.

The line itself is infinitely thin and goes from one coordinate to the
next, don't think of pixels. So, 20,60 to 20,60 goes nowhere - it has a
length of 0. 20,60 to 21,60 goes a total distance of 1 unit and has a
length of 1.

Now with CAP_SQUARE, the first line is extended by lw/2 off the front
and back so it extends a total of lw in the "direction" of the line
(ignore for now that a 0-length line has no direction), and obviously it
extends lw perpendicular to the line (and centered on the line). If
lw=1 then it is a 1x1 square - but only with CAP_SQUARE.

Also with CAP_SQUARE, the second line is extended by the same lw/2 off
both ends, and so it is 1 unit long and extends another lw units so it
is a total of lw+1 long or 2 units long for a lw=1 line. It extends lw
perpendicular as well so it is a 2x1 line.

With CAP_BUTT, there are no extensions so the 0-length line is only 0
units long and the 1-length line is only 1 units long...

...jim

java2d@JAVADESKTOP.ORG wrote:
> Thanks Jim,
> After all the time I've spent on this it seems I still do not full understand it!
>
> Everything I have read on this seems to confirms my thinking, it just doesn't translate when using line widths > 1.
> My understanding is (or was) that the arguments to the Line2D methods , as either x,y coordinates or Points set the "endpoints" of the line.
>
> If I draw a line (with line width of 1) from coordinates 20,60 to 20,60 it would cover 1 pixel below and to the right of the coordinate which would be the pixel 20,60 (current user space).
>
> So as 20,60 & 21,60 are two distinct coordinate points , if I draw a line using these coordinates as the endpoints, I expected to get a 2 pixel line length (and did with line width of 1).
>
> Similarly if i set 2 Points to the coordinates above and use ..
> setLine(Point2D p1, Point2D p2) it would cover 2 pixels. ( and does with line width of 1 but not with a width > 1
>
> From the Sun APi Class Line2D docs ..
> " setLine(Point2D p1, Point2D p2) Sets the location of the end points of this Line2D to the specified Point2D coordinates."
>
> Without wishing to take the discussion away from the points above, the end cap options raise another issue..
> If I had set CAP_SQUARE or ROUND with a line width of 1, where would it decide to add the additional pixel? Normally half the line width and adding it to each end point?
> I guess this issue happens any time the line width is an odd pixel number.
>
> ....Lew
> [Message sent by forum member 'aussielew' (aussielew)]
>
> http://forums.java.net/jive/thread.jspa?messageID=292007
>
> ===========================================================================
> To unsubscribe, send email to listserv@java.sun.com and include in the body
> of the message "signoff JAVA2D-INTEREST". For general help, send email to
> listserv@java.sun.com and include in the body of the message "help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

aussielew
Offline
Joined: 2008-08-05

Thanks Jim,
This is a really good explanation. Obviously I had trouble grasping the coordinate system fully. This also helps to explain (to me) line2D.Float etc as the coordinates can be a float value where as pixels are defined units.

The fact that line width of 1 drew the additional pixel just wrongly confirm my errant thinking.
At least a bug was uncovered if not already known.

Thanks again!
Lew

> Hi Lew,
>
> You are describing the default behavior which assumes
> CAP_SQUARE.
>
> The line itself is infinitely thin and goes from one
> coordinate to the
> next, don't think of pixels. So, 20,60 to 20,60 goes
> nowhere - it has a
> length of 0. 20,60 to 21,60 goes a total distance of
> 1 unit and has a
> length of 1.
>
> Now with CAP_SQUARE, the first line is extended by
> lw/2 off the front
> and back so it extends a total of lw in the
> "direction" of the line
> (ignore for now that a 0-length line has no
> direction), and obviously it
> extends lw perpendicular to the line (and centered on
> the line). If
> lw=1 then it is a 1x1 square - but only with
> CAP_SQUARE.
>
> Also with CAP_SQUARE, the second line is extended by
> the same lw/2 off
> both ends, and so it is 1 unit long and extends
> another lw units so it
> is a total of lw+1 long or 2 units long for a lw=1
> line. It extends lw
> perpendicular as well so it is a 2x1 line.
>
> With CAP_BUTT, there are no extensions so the
> 0-length line is only 0
> units long and the 1-length line is only 1 units
> long...
>
> ...jim
>
> java2d@JAVADESKTOP.ORG wrote:
> > Thanks Jim,
> > After all the time I've spent on this it seems I
> still do not full understand it!
> >
> > Everything I have read on this seems to confirms my
> thinking, it just doesn't translate when using line
> widths > 1.
> > My understanding is (or was) that the arguments to
> the Line2D methods , as either x,y coordinates or
> Points set the "endpoints" of the line.
> >
> > If I draw a line (with line width of 1) from
> coordinates 20,60 to 20,60 it would cover 1 pixel
> below and to the right of the coordinate which would
> be the pixel 20,60 (current user space).
> >
> > So as 20,60 & 21,60 are two distinct coordinate
> points , if I draw a line using these coordinates as
> the endpoints, I expected to get a 2 pixel line
> length (and did with line width of 1).
> >
> > Similarly if i set 2 Points to the coordinates
> above and use ..
> > setLine(Point2D p1, Point2D p2) it would cover 2
> pixels. ( and does with line width of 1 but not with
> a width > 1
> >
> > From the Sun APi Class Line2D docs ..
> > " setLine(Point2D p1, Point2D p2) Sets the
> location of the end points of this Line2D to the
> specified Point2D coordinates."
> >
> > Without wishing to take the discussion away from
> the points above, the end cap options raise another
> issue..
> > If I had set CAP_SQUARE or ROUND with a line width
> of 1, where would it decide to add the additional
> pixel? Normally half the line width and adding it to
> each end point?
> > I guess this issue happens any time the line width
> is an odd pixel number.
> >
> > ....Lew
> > [Message sent by forum member 'aussielew'
> (aussielew)]
> >
> >
> http://forums.java.net/jive/thread.jspa?messageID=2920
> 07
> >
> >
> ======================================================
> =====================
> > To unsubscribe, send email to listserv@java.sun.com
> and include in the body
> > of the message "signoff JAVA2D-INTEREST". For
> general help, send email to
> > listserv@java.sun.com and include in the body of
> the message "help".
>
> ======================================================
> =====================
> To unsubscribe, send email to listserv@java.sun.com
> and include in the body
> of the message "signoff JAVA2D-INTEREST". For
> general help, send email to
> listserv@java.sun.com and include in the body of the
> message "help".

Jim Graham

Hi Lew,

A line "from" 20 "to" 21 should only be one pixel long as the distance
between those points is only 1 pixel.

The bug is that we drew 2 pixels when you gave us the first stroke. I
think I know what's causing that. We have a test to see if the line
width is small enough to generate "single pixel wide lines" and then we
just use bresenham. I don't have the code in front of me, but I'm 99%
sure that we don't check the CAP setting when we classify the lines as
"thin" and so we don't note that we should leave off a pixel and just
use the default bresenham which models something similar to a CAP_SQUARE
or CAP_ROUND type of a line length... :-(

...jim

java2d@JAVADESKTOP.ORG wrote:
> Hi All,
>
> Hoping someone can help me with this one ...?
>
> I need to draw lines with a width greater than 1 and the lengths may be a real value so I am using
> Line2D.Float.
>
> I need to draw exact (calculated)lengths so I am using CAP_BUTT so the line does not have any additional
> apparent length (the other CAP options have the effect of adding the line width to the line)
>
> The problem I am having is that once the line width is set to greater than 1, the lines are actually drawn 1 pixel short.
> I am sure I am missing soething simple here but have spent a lot of time on it!
> I know that I can work around it but do I need to, I shouldn't have to + 1 to my line lengths depending on there width?
>
> The following demonstrates the problem. I am drawing on a JPanel within a JFrame, JDK/JRE 6, Windows
>
> g2.setStroke(new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
> g2.setColor(Color.BLACK);
> g2.draw(new Line2D.Float(20,40,20,75)); // vertical line as marker only
>
>
> // draw 2 lines with line width of 1
> g2.setColor(Color.RED);
> g2.draw(new Line2D.Float(20,60,21,60)); // draws 2 pixel line as expected
> g2.draw(new Line2D.Float(22,60,23,60)); // draws 2 pixel line as expected ... total of 4 pixels
>
>
> // draw 2 lines with line width of 10
> g2.setStroke(new BasicStroke(10,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
> g2.setColor(Color.GREEN);
> g2.draw(new Line2D.Float(20,70,21,70)); // draws 1 pixel only at 20,70
> g2.setColor(Color.YELLOW);
> g2.draw(new Line2D.Float(22,70,23,70)); // draws 1 pixel only at 22,70... so, each line is shortened by 1 pixel
> // this applies to any line width > 1
>
>
>
> Thanks
> Lew
> [Message sent by forum member 'aussielew' (aussielew)]
>
> http://forums.java.net/jive/thread.jspa?messageID=291753
>
> ===========================================================================
> To unsubscribe, send email to listserv@java.sun.com and include in the body
> of the message "signoff JAVA2D-INTEREST". For general help, send email to
> listserv@java.sun.com and include in the body of the message "help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".