Bug? B4XRect .height changes when .top changes

MrKim

Well-Known Member
Licensed User
Longtime User
I try to set the height once, but setting the top changes the height.
If this is by design I would love to know why?
1665947980073.png

1665948026545.png

1665948095162.png
 

William Lancee

Well-Known Member
Licensed User
Longtime User
B4XRectangles are defined by boundaries: left, top, right, bottom.
This is different from views which are defined by shape: left, top, width, height.

The benefit of this difference is that when drawing on canvas, one typically goes from left to right, top to bottom or vice versa.
When you change the boundaries of a rectangle, the width and height are automatically adjusted.

It tripped me up a few times, but I have come to appreciate this design.
 

Markus Winter

Member
Licensed User
The benefit of this difference is that when drawing on canvas, one typically goes from left to right, top to bottom or vice versa.
When you change the boundaries of a rectangle, the width and height are automatically adjusted.
Why would that design be a benefit?

For one thing: should you really have TWO different definitions of a rectangle? Consistency is a virtue in programming after all.

Secondly, how do you usually define a rectangle?

Top and Left define the location of a rectangle.
Width and Height define the size of a rectangle.

That is easy to understand because it is intuitive (if you ever build a shelf then you know that you need width and height to define if it fits), and it is easy to automatically adjust left and bottom when width or height are changed.

The given design would only be a benefit if the rectangle is and remains static - but what if the rectangle can move or change (size or position)?

Imagine a drawing or gaming application and you need to move and resize a rectangle - then this design is counter-intuitive and makes for example moving a rectangle more cumbersome than it should be. In the current design you need something like:

B4X:
var oldHeight = rect.height
var oldWidth= rect.width

rect.top = newTop
rect.left = newLeft

rect.height = oldHeight
rect.width = oldWidth

instead of

B4X:
rect.top = newTop
rect.left = newLeft

Of course one could wrap it in a function like setTop and setLeft … but that induces overhead which might not be desirable.

But a better design might be:
  • if you change the right or bottom then automatically adjust width or height
  • if you change the width or height then automatically adjust right or bottom
Then the rule would be

Top and Left define the location of a rectangle.
Width & Height and Right & Bottom define the size of a rectangle.

Best of both Worlds?
 
Last edited:

William Lancee

Well-Known Member
Licensed User
Longtime User
I am a woodworker and shelves are real objects, and indeed that is how I measure my shelves.
I am also a mathematician and rectangles are abstract objects.
They are different only in how you approach the dimensions,
As a mathematician, I would see a rectangle as two points, (x0, y0) and (x1, y1).

But a better design might be:
  • if you change the right or bottom then automatically adjust width or height
  • if you change the width or height then automatically adjust right or bottom

I agree.
 
Last edited:

MrKim

Well-Known Member
Licensed User
Longtime User
At 74, one thing I have learned. When something seems intuitively obvious, to ME, there are others for whom the the intuitively obvious thing is the exact opposite.
 

William Lancee

Well-Known Member
Licensed User
Longtime User
At the risk of extending this discussion beyond its usefulness, I would like to add this.

We will all agree that the position and shape of an object should be independent parameters.
A change in position should not influence shape and a change in shape should not influence position.
(Once I finish making my shelf, I can put it anywhere without changing its shape)

Position can be defined by any point in the shape. Often, I find it very useful to specify position of an object by its centroid.
And if I specify its shape relative to the centroid, the centroid will be at (0, 0). This makes my computations much simpler.

By convention, the positions of views are specified by their left/top point, and texts are specified by their bottom left point.
Rectangles are different. They are geometric shapes set in a Cartesian co-ordinate system. In general, a n-sided polygons requires n points to specify its
shape and position. Rectangles require four points, but if the sides are parallel to the axis of the co-ordinate system, only 2 points are needed.
The other 2 points can be derived from these two. That is how a B4XRect is specified. Note that a nice feature of this structure is that the
the centerX and centerY values are accessed as read-only.

Also note:
1. changing the width/height changes the right/bottom values
2. changing the right/bottom changes the width/height values

B4X:
    Dim r As B4XRect
    r.Initialize(100, 0, 900, 1000)
    Log(r.Left & TAB & r.Right & TAB & r.CenterX & TAB & r.Width)    '    100    900    500    800
    r.Width = 200
    Log(r.Left & TAB & r.Right & TAB & r.CenterX & TAB & r.Width)    '    100    300    200    200
    r.Right = 900
    Log(r.Left & TAB & r.Right & TAB & r.CenterX & TAB & r.Width)    '    100    900    500    800

This too is a convention. There is really no other reason to pick the left/top as the unchanging position anchor.
If you were to make the right/bottom the anchor, changing the width should change the left.
If you define structures with the centroid as the anchor, and use standard units [I use min(screen.width, screen.height) / 1000] then
a simple transform will adapt your geometric shapes to any size screen. It makes them screen-independent.
They also can be scaled easily.
 
Top