Skip to main content

A few simple Java 2D questions ...

7 replies [Last post]
dodger
Offline
Joined: 2005-11-02

Hi,

1. I don't understand why Java 2D classes such as Rectangle2D have float and double constructors, and not integer constructors? I thought these values represented pixel coordinates? Are these values rounded, or what? (I know I'm missing something huge here, so this is an embarrassing question to ask)

2. Should methods in the Graphics class, such as drawRect, ever be used? (i.e., should you always cast the Graphics object to Graphics2D, and call draw(myShape2D)?)

3. What is the best way of filling a rounded rectangle with 2 gradients, as shown here: http://ld.hostrocket.com/images/rr_grad.png

I believe the LinearGradientPaint in Mustang will make this a lot easier, but I'd like it to at least run on Tiger (I think).

What I did was set the clip to a rounded rectangle, and then fill two separate rectangles using a GradientPaint. I then 'reset' the clip, and drew the rounded rectangle border. (The corners of the border seemed to be cut off if I didn't remove the clip -- I probably did something wrong) Anyway, is this an acceptable solution? Is there a better way to do it?

Any other Java 2D tips are welcome. :)

Thanks,

D.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Jim Graham

> Without anti-aliasing, I see no difference between a rectangle at 0 and one at 0.99 (the x
> coordinate) (this is true with anti-aliasing turned on as well, but I assume it's because there are
> no curved areas). I do, however, notice a change with an ellipse, as you mentioned. There's a
> difference in rendering between an ellipse positioned at 0 and one at 0.49. Is it because the
> non-integer coordinates affect the result of calculating the position of the pixels within the arcs
> of the ellipse? If this is true, then surely regular rectangles and lines would not be affected by
> non-integer coordinates, unless perhaps they were transformed? In other words, shapes are rendered
> at integer locations, but the rounding can be affected by the calculation of curves and
> transformations? But then why would you choose to render a shape at a non-integer location in the
> first place? I hope I'm not making a fool of myself here.

First, there is a hint that affects the sub-pixel positioning of shapes.
The KEY_STROKE_CONTROL controls whether coordinate normalization is
allowed before rendering - which can include rounding coordinates to the
nearest integer or to the nearest "such-and-such part of the pixel" such
as the center of the pixel or some other interesting sub-pixel offset
which may make wide lines grow more uniformly or curves more pleasing or
...?

The default value for this hint is "DEFAULT" which says that the
implementation is allowed to normalize or not depending on its own
principles and I believe that most of our pipelines do normalization by
default. Setting it to VALUE_STROKE_PURE should turn off any
normalization and then sub-pixel positioning should be honored.

Also, whether or not the sub-pixel positioning is honored, fractional
coordinates are still useful when you are in a scaled coordinate system.
By default there is no scale in the coordinate transform so this
issue doesn't affect you...

...jim

===========================================================================
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".

dodger
Offline
Joined: 2005-11-02

Hi Jim,

By 'sub-pixel' are you referring to the sub-pixels in LCD displays, for example?

Does this then not apply to CRT monitors?

Thanks,

D.

Jim Graham

No, by "sub-pixel" I mean geometry which places coordinates at
fractional screen coordinates for purposes of expressing the locations
of those vertices more accurately than integers would allow. If the
display has sub-components that are smaller than a pixel, that could be
taken advantage of during the rendering process as it is with LCD text,
but that has nothing to do with the need that some applications have to
express their geometry with sub-pixel precision.

It may not seem obvious that sub-pixel precision in geometry matters
when you are dealing with discreet pixels, but if you consider that
antialiased rendering can show sub-pixel differences by the opacity of
the pixels on the boundary of a shape, and if you consider that even
with non-antialiased rendering the location of the "jaggies" on a sloped
line will be affected by the sub-pixel location of the endpoints, you
can start to see that allowing expression of coordinates more finely
than an integer pixel location is worthwhile...

...jim

java2d@javadesktop.org wrote:
> Hi Jim,
>
> By 'sub-pixel' are you referring to the sub-pixels in LCD displays, for example?
>
> Does this then not apply to CRT monitors?
>
> Thanks,
>
> D.
> [Message sent by forum member 'dodger' (dodger)]
>
> http://forums.java.net/jive/thread.jspa?messageID=116601
>
> ===========================================================================
> 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".

dodger
Offline
Joined: 2005-11-02

"Why not take a few seconds and try it yourself?"

I had done so, without ... thinking. I passed one of the constructors the result of a method with an integer return value.

"Depends on the application; double is really important in the mapping/GIS industry, for example."

OK.

"It sounds like you have a pretty good grasp already, so I wouldn't fret too much if I were you."

Too late, LOL.

"Sorry, that's what I meant."

NP.

"Sorry, that was an old joke. We have seen some rather creative approaches to rendering simple primitives over the years"

I see. Well, you don't have to worry about me -- I use an ellipse. ;)

Thanks again.

dodger
Offline
Joined: 2005-11-02

Hi Chris,

Thanks very much for your reply.

"You can pass int parameters to either of the Float or Double constructors ..."

You're right, although I thought you'd have to cast the values first?

"As for your second question ..."

Without anti-aliasing, I see no difference between a rectangle at 0 and one at 0.99 (the x coordinate) (this is true with anti-aliasing turned on as well, but I assume it's because there are no curved areas). I do, however, notice a change with an ellipse, as you mentioned. There's a difference in rendering between an ellipse positioned at 0 and one at 0.49. Is it because the non-integer coordinates affect the result of calculating the position of the pixels within the arcs of the ellipse? If this is true, then surely regular rectangles and lines would not be affected by non-integer coordinates, unless perhaps they were transformed? In other words, shapes are rendered at integer locations, but the rounding can be affected by the calculation of curves and transformations? But then why would you choose to render a shape at a non-integer location in the first place? I hope I'm not making a fool of myself here.

It also brings another question to my mind -- When should you use the float constructors, and when should you use the double constructors? I assume double is more precise, but uses more memory? Would it be used where accuracy is important, such as in CAD applications?

"The drawRect(), fillRect(), etc methods on the Graphics class are still your best bet ..."

OK, but this assumes you wish to position a shape in an integer location only?

*sigh* Maybe I should just forget about understanding this stuff.

"On Tiger, you pretty much have no choice but to use the two-pass technique you describe ..."

Actually, my technique is (clip, fillR, fillR, reset clip, drawRR) (5 steps, as apposed to 6).

"The behavior you're seeing where the corners are clipped off is caused by slight differences between the clip region and the way the rounded rect shape is stroked ..."

Yeah, I think some of the anti-aliasing of the stroke is being rendered outside of the clip.

"1. Don't use drawRoundRect() to draw one-pixel tall horizontal lines."

Hmmm ... I never did that? Or are you joking?

Anyway, thanks again.

Regards,

D.

campbell
Offline
Joined: 2003-06-24

> Hi Chris,
>
> Thanks very much for your reply.
>
> "You can pass int parameters to either of the Float
> or Double constructors ..."
>
> You're right, although I thought you'd have to cast
> the values first?
>

Why not take a few seconds and try it yourself?

> "As for your second question ..."
>
> Without anti-aliasing, I see no difference between a
> rectangle at 0 and one at 0.99 (the x coordinate)
> (this is true with anti-aliasing turned on as well,
> but I assume it's because there are no curved areas).
> I do, however, notice a change with an ellipse, as
> you mentioned. There's a difference in rendering
> between an ellipse positioned at 0 and one at 0.49.
> Is it because the non-integer coordinates affect the
> result of calculating the position of the pixels
> within the arcs of the ellipse? If this is true, then
> surely regular rectangles and lines would not be
> affected by non-integer coordinates, unless perhaps
> they were transformed? In other words, shapes are
> rendered at integer locations, but the rounding can
> be affected by the calculation of curves and
> transformations? But then why would you choose to
> render a shape at a non-integer location in the first
> place? I hope I'm not making a fool of myself here.
>
> It also brings another question to my mind -- When
> should you use the float constructors, and when
> should you use the double constructors? I assume
> double is more precise, but uses more memory? Would
> it be used where accuracy is important, such as in
> CAD applications?
>

Depends on the application; double is really important in the mapping/GIS industry, for example.

> "The drawRect(), fillRect(), etc methods on the
> Graphics class are still your best bet ..."
>
> OK, but this assumes you wish to position a shape in
> an integer location only?
>

Yep.

> *sigh* Maybe I should just forget about understanding
> this stuff.
>

It sounds like you have a pretty good grasp already, so I wouldn't fret too much if I were you.

> "On Tiger, you pretty much have no choice but to use
> the two-pass technique you describe ..."
>
> Actually, my technique is (clip, fillR, fillR, reset
> clip, drawRR) (5 steps, as apposed to 6).
>

Sorry, that's what I meant.

> "The behavior you're seeing where the corners are
> clipped off is caused by slight differences between
> the clip region and the way the rounded rect shape is
> stroked ..."
>
> Yeah, I think some of the anti-aliasing of the stroke
> is being rendered outside of the clip.
>

Right.

> "1. Don't use drawRoundRect() to draw one-pixel tall
> horizontal lines."
>
> Hmmm ... I never did that? Or are you joking?
>

Sorry, that was an old joke. We have seen some rather creative approaches to rendering simple primitives over the years :)

Chris

campbell
Offline
Joined: 2003-06-24

> Hi,
>
> 1. I don't understand why Java 2D classes such as
> Rectangle2D have float and double constructors, and
> not integer constructors? I thought these values
> represented pixel coordinates? Are these values
> rounded, or what? (I know I'm missing something huge
> here, so this is an embarrassing question to ask)
>

You can pass int parameters to either of the Float or Double constructors, or you could use the legacy java.awt.Rectangle class, which operates on int parameters only. As for your second question, Java 2D is a vector graphics library, and as such there isn't necessarily a one-to-one mapping between coordinates (integer or otherwise) and pixel locations on screen. For example, you could have an ellipse positioned at (1.345, 2.2), which could be rendered slightly differently than one rounded down to (1, 2), especially when you're talking about antialiased rendering, or if you're printing, or...

> 2. Should methods in the Graphics class, such as
> drawRect, ever be used? (i.e., should you always cast
> the Graphics object to Graphics2D, and call
> draw(myShape2D)?)
>

The drawRect(), fillRect(), etc methods on the Graphics class are still your best bet, especially if you're concerned with performance. It's the principle of "tell us exactly what you mean". If you want to fill a rectangle, it's much better to use fillRect() as we can use our fast/dedicated filling code under the hood. If you use fill(Rectangle2D), we'll jump through all kinds of hoops to end up with the same visual results.

> 3. What is the best way of filling a rounded
> rectangle with 2 gradients, as shown here:
> http://ld.hostrocket.com/images/rr_grad.png
>
> I believe the LinearGradientPaint in Mustang will
> make this a lot easier, but I'd like it to at least
> run on Tiger (I think).
>
> What I did was set the clip to a rounded rectangle,
> and then fill two separate rectangles using a
> GradientPaint. I then 'reset' the clip, and drew the
> rounded rectangle border. (The corners of the border
> seemed to be cut off if I didn't remove the clip -- I
> probably did something wrong) Anyway, is this an
> acceptable solution? Is there a better way to do it?
>

On Tiger, you pretty much have no choice but to use the two-pass technique you describe (clip, fillRR, clip, fillRR, reset clip, drawRR). The behavior you're seeing where the corners are clipped off is caused by slight differences between the clip region and the way the rounded rect shape is stroked, so if you don't need the clip set, the resetting the clip to its previous value is not a bad idea (as you've found).

On Mustang, you can do the fill in one pass using LinearGradientPaint and CycleMethod.REPEAT, where the repeat boundary is in the middle of your button (such that you get a hard boundary between the first and last colors, as in your screenshot).

> Any other Java 2D tips are welcome. :)
>

1. Don't use drawRoundRect() to draw one-pixel tall horizontal lines.
2. See #1.

:)

Thanks,
Chris