Monday Jun 15, 2009

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.


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