I have a hierarchy of Components which are scaled with a simple
AffineTransform. The inner Components are frequently very small. I want to use
localAreaToGlobal() to find the absolute area of each Component, but this function fails when the inner Components shrink beyond the integer resolution.
Here is a simple example:
Component outer, middle, inner; addAndMakeVisible(outer); outer.addAndMakeVisible(middle); middle.addAndMakeVisible(inner); outer. setSize(10, 10); middle.setSize(10, 10); inner. setSize(10, 10); auto scaleUp = AffineTransform().scale(8.0f); auto scaleDown = AffineTransform().scale(0.125f); outer. setTransform(scaleUp); // So outer's side should be 10 * 8 = 80 middle.setTransform(scaleDown); // middle should be 10 * 8 / 8 = 10 inner. setTransform(scaleDown); // inner should be 10 * 8 / 8 / 8 = 1.25 auto outerArea = outer. localAreaToGlobal(outer. getLocalBounds()); auto middleArea = middle.localAreaToGlobal(middle.getLocalBounds()); auto innerArea = inner. localAreaToGlobal(inner. getLocalBounds()); DBG(String("outer area: ") + outerArea. toString()); // prints 80 DBG(String("middle area: ") + middleArea.toString()); // prints 10 DBG(String("inner area: ") + innerArea. toString()); // prints 8 -- oh no!
In this example, the “outer” Component is scaled up by 8 times. I did this to illustrate how small rounding errors can be amplified, so that
localAreaToGlobal() becomes completely inaccurate, rather than just a little bit.
It is quite obvious why this happens when you look at the source code for the Component class, but for a casual user it might not be. The Affine Transformations might have been set it completely different areas of the code, making the error difficult to track down.
As a temporary solution, I’m multiplying the area up before applying the function, and then dividing it back afterwards:
auto correctInnerArea = inner.localAreaToGlobal(inner.getLocalBounds() * 128) / 128; DBG(String("correct inner area: ") + correctInnerArea.toString()); // prints 1 -- close enough!
This works in my case, but it is hardly a general solution.
1: Fix the existing
localAreaToGlobal() function so that it works internally with float precision. I’m not exactly sure how to do this, but it doesn’t look like it would be too complicated.
or 2: Add a new method in Component for
Rectangle< float> localAreaToGlobal (Rectangle<float>). The existing
Rectangle< int> localAreaToGlobal (Rectangle<int>) method is just accessing a template function
ComponentHelpers::convertCoordinate() anyway, so I think this addition would be very trivial.
or 3: At the very least, add a disclaimer to the documentation, warning users that the function may not produce accurate results if the Component has been transformed below integer resolution.