Node Bounding Rectangles & Coordinates

A FX Node has 3 Bounding Rectangles. I think it is important to understand what they mean exactly, how each bounding rectangle is calculated and when they should be used.

layoutBounds

The rectangular bounds that should be used in calculations for both manual and automatic layout of the Node. This rectangle is used as a base layout information for a particular node. The actual layout position should be calculated after applying layoutX/layoutY on top of the layoutBounds. As a Node extended class may need its own special layout bounds, layoutBounds is defined as "public-read protected" while other 2 bounds (boundsInLocal and boundsInParent) are defined as "public-read" only. While a sub class of Node may have a different definition, the default includes only geometric bounds. 

+ geometric bounds(shape, non-zero strokes)

boundsInLocal

The rectangular bounds of this Node in the Node's untransformed local coordinate space. In this context, 'transform' includes transforms, layoutX, layoutY, translateX, translateY, scaleX, scaleY and rotate. So these transforms won't be included in the boundsInLocal. However the clip and effect are applied.

+ geometric bounds(shape, non-zero strokes)
+ clip
+ effect

boundsInParent

The rectangular bounds of the Node which includes its transforms Again in this context, 'transform' includes transforms, layoutX, layoutY, translateX, translateY, scaleX, scaleY and rotate. All these transforms are applied. So this bounding box is the surrounding box of what we actually see from the scene. Now the translation by "transforms: Translate{x: n}", "translateX: n", and "layoutX: n" has the same meaning in the calculation of the bounding box. The followings are applied in order.

+ boundsInLocal
+ transforms variable
+ layoutX/Y varibales
+ explicit transforms(translateX/Y, scaleX/Y, rotate)

All 3 bounding boxes are automatically recomputed whenever the geometry of a node changes. For this reason,

1) A variable that decides the geometry of a node should never be bound to any 3 bounding boxes. If so, java.lang.StackOverflowError will be thrown. For example, in the following code snippet, the boundsInLocal change will cause the x value change which will cause recomputation of boundsInLocal. At the end, StackOverflowError will be thrown.

var anode:Rectangle = Rectangle {
x: bind
anode.boundsInLocal.minX+anode.boundsInLocal.width\*0.5
    ...
}

2) A variable that decide a bounding box should never be bound to the same bounding box. This will also result in java.lang.StackOverflowError. For example, in the following code snippet, the  pivotX change will rescale and  recompute the boundsInParent, which will update the pivotX again. At the end, StackOverflowError will be thrown.

var anode:Path = Path {
    transforms: [
        Scale {
x: bind scaleSlider.value y: bind scaleSlider.value
pivotX: bind anode.boundsInParent.minX+anode.boundsInParent.width\*0.5 // java.lang.StackOverflowError
        }
    ]
    ...
}

Here is the little toy you can try out by yourself.

The source bundle can be downloaded from HERE.

There are 3 known issues on this demo and FX API description, which I had submitted at the time of this writing.

  1. http://javafx-jira.kenai.com/browse/RT-4954: Slider knob issue when value is between - min value and + max value.
  2. http://javafx-jira.kenai.com/browse/RT-4953: boundsInParent calculation issue when a clip/effect is set.
  3. http://javafx-jira.kenai.com/browse/RT-4951: Node class description is incorrect on the layoutBounds.


Comments:

Impresive demo.

Posted by peter on June 17, 2009 at 11:28 AM PDT #

Superb explanation, I confusedly wondered why there was so many bounds...
The demo is an excellent way to visually grasp the concepts.
Many thanks for the article.

Posted by Philippe Lhoste on June 17, 2009 at 10:07 PM PDT #

Some remarks on the demo (some might be JavaFX bugs, I will dig and report if needed):
- Scale as integer shows only 0, 1, or 2, not very informative. I replaced the {slider.value as Integer} with {%.1f slider.value};
- Perhaps that's because of a negative min value, but TransX slider has a erratic behavior (on Windows XP Pro SP3, Java 1.6.0_13): when I release the thumb, it goes to 100, and it is hard to make it go back to another value (mostly by clicking on the track);
- If I rotate the shape, the boundsInParent rectangle is OK. Idem if scale the image. Unrotated, scaled or not, shape with effect and/or clip is still OK. But rotated shape on which you apply an effect and/or a clip has an incorrect boundsInParent, a bit too big.

Posted by Philippe Lhoste on June 17, 2009 at 10:51 PM PDT #

That's me again... I haven't noticed the screenshot shows the "issue" with larger boundsInParent. Bug or feature?

Note: I created a Jira / Kenai bug report for the slider issue. http://javafx-jira.kenai.com/secure/CantBrowseCreatedIssue.jspa?issueKey=RT-4969

For some reason, I can see the bug reports I make against the compiler (eg. JFXC-3283) but not those against the runtime (the above, a previous one...).

Posted by Philippe Lhoste on June 18, 2009 at 12:11 AM PDT #

Thanks for the comments. Actually I had submitted 3 issues while I was writing this blog.
1) http://javafx-jira.kenai.com/browse/RT-4954 (Slider control slider knob issue when value is between - min value and + max value)

2) http://javafx-jira.kenai.com/browse/RT-4953 (boundsInParent calculation issue when a clip/effect is set.)

3) http://javafx-jira.kenai.com/browse/RT-4951 (Node class description is incorrect on the layoutBounds.)

Posted by Baechul on June 18, 2009 at 11:20 AM PDT #

I should have guessed you filled the bugs yourself... :-)
A nice think with this demo, beside the immediate usefulness, is that it is simple enough to hack yet it shows a non-trivial, real-world usage of controls.
I see you used absolute (and relative) pixel layout... I am used to such placement too, but I wanted to try a bit the new layout capabilities of JavaFX 1.2, so I hacked your code to use such layout.
I found out some issues, like not being able to provide layoutInfo to Group or Text (the latter being then replaced by Label) as they are not resizable, and the global binding to the scene content causing warnings about putting a node twice in a HBox (which I wasn't). I solved the latter by grouping the rectangles to their own group with (thus reduced) binding.
I though you might be interested to see the changes, so you can find my version at http://autohotkey.net/~PhiLho/PhiLhoSoft/JavaFX/NodeBoundsTest.fx
I don't pretend it is "better", just a different take on the problem... :-)

Posted by Philippe Lhoste on June 28, 2009 at 10:37 PM PDT #

Thanks for example, it is mmuch easier to understand then description on eblogs.java.net.

Posted by Aleksandr on September 13, 2009 at 04:19 PM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Hello,
I am Baechul and live in Santa Clara, U.S.A. This is my blog that will talk about Java and JavaFX technologies.

Search

Top Tags
Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today