wx.Rect.Setx - Which .Set()s change other Rect attributes ?

The wx.Rect Set_() methods seems unintuitive to me. What are the effects on all the other attributes if, for example, Rect.SetTop() is called ? What Set() calls cause Rect.Size to be recalculated ?

For example, I’m calling Rect.SetTopLeft() which intuitively moves the Rect, but Rect.SetBottomRight() grows or shrinks the Size ! (The TopLeft coordinate remains fixed.) Why does SetTopLeft() have a different effect on the Size and Position than SetBottomRight() ? What are the undocumented rules ?

Did wx.Rect originate from the MSW Rect routines, and so, inherit MS’s, um…, “unique” way of thinking ?

Ray Pasco

Ray Pasco wrote:

The wx.Rect Set_() methods seems unintuitive to me. What are the
effects on all the other attributes if, for example, Rect.SetTop() is
called ? What Set() calls cause Rect.Size to be recalculated ?

For example, I'm calling Rect.SetTopLeft() which intuitively moves the
Rect,...

...and adjusts the size...

but Rect.SetBottomRight() grows or shrinks the Size ! (The TopLeft
coordinate remains fixed.) Why does SetTopLeft() have a different
effect on the Size and Position than SetBottomRight() ? What are the
undocumented rules ?

I'm not sure what surprises you. SetTopLeft changes top and left, and
leaves bottom and right unchanged, which means the size changes.
SetBottomRight changes bottom and right, and leaves top and left
unchanged. The behavior seems perfectly rational to me, with one
possible exception:

C:\tmp>python
Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit
(Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx
>>> z = wx.Rect(10,20,60,70)
>>> z
wx.Rect(10, 20, 60, 70)
>>> z.SetTopLeft((1,2))
>>> z
wx.Rect(1, 2, 60, 70)
>>> z.SetBottomRight((100,200))
>>> z
wx.Rect(1, 2, 100, 199)
>>>

I don't know why that last resulted in 199 instead of 200, but the rest
of it is only natural.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Tim Roberts wrote:

Ray Pasco wrote:

The wx.Rect Set_() methods seems unintuitive to me. What are the
effects on all the other attributes if, for example, Rect.SetTop() is
called ? What Set() calls cause Rect.Size to be recalculated ?

For example, I'm calling Rect.SetTopLeft() which intuitively moves the
Rect, but Rect.SetBottomRight() grows or shrinks the Size !

I'm not sure what surprises you.

It occurs to me that you might be accustomed to thinking of rectangles
as having top, left, height and width. In that case, I can see where
you might be surprised. Rectangles in Windows have left, top, right,
and bottom. Width and height are merely attributes of the rectangle
that are computed by subtracting right-left and bottom-top.

So, either corner can be moved independently. The width and height
change whenever any point is changed, because they are computed. To set
the width of a rect, you end up doing
    rect.right = rect.left + newWidth

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Internally wx.Rects are (x,y width,height) too, but methods and properties are provided for dealing with it as (left, top, bottom, right) as well for people and code that prefer that mode of thinking.

···

On 7/29/11 3:42 PM, Tim Roberts wrote:

Tim Roberts wrote:

Ray Pasco wrote:

The wx.Rect Set_() methods seems unintuitive to me. What are the
effects on all the other attributes if, for example, Rect.SetTop() is
called ? What Set() calls cause Rect.Size to be recalculated ?

For example, I'm calling Rect.SetTopLeft() which intuitively moves the
Rect, but Rect.SetBottomRight() grows or shrinks the Size !

I'm not sure what surprises you.

It occurs to me that you might be accustomed to thinking of rectangles
as having top, left, height and width. In that case, I can see where
you might be surprised. Rectangles in Windows have left, top, right,
and bottom. Width and height are merely attributes of the rectangle
that are computed by subtracting right-left and bottom-top.

So, either corner can be moved independently. The width and height
change whenever any point is changed, because they are computed. To set
the width of a rect, you end up doing
     rect.right = rect.left + newWidth

--
Robin Dunn
Software Craftsman

Internally wx.Rects are (x,y width,height) too, but methods and
properties are provided for dealing with it as (left, top, bottom,
right) as well for people and code that prefer that mode of thinking.

which may explain:

···

On 7/29/11 4:40 PM, Robin Dunn wrote:

On 7/29/11 3:27 PM, Tim Roberts wrote:

  >>> z.SetBottomRight((100,200))
  >>> z
  wx.Rect(1, 2, 100, 199)
  >>>

I don't know why that last resulted in 199 instead of 200,

it's actually being calculated, so there may have been some rounding error in there.

-Chris

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Christopher Barker wrote:

···

On 7/29/11 3:27 PM, Tim Roberts wrote:

  >>> z.SetBottomRight((100,200))
  >>> z
  wx.Rect(1, 2, 100, 199)
  >>>

I don't know why that last resulted in 199 instead of 200,

it's actually being calculated, so there may have been some rounding
error in there.

Since those are all integers, I'm pretty sure you didn't mean what you
just said.

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

I’ll repeat:
Calling Rect.SetTopLeft() moves the Rect [size is unchanged],
but Rect.SetBottomRight() grows or shrinks the Size."

I don’t understand what you all are saying.

Ray

I'll repeat:

Calling Rect.SetTopLeft() moves the Rect [size is unchanged],
but Rect.SetBottomRight() grows or shrinks the Size."

I don't understand what you all are saying.

I am afraid Ray is right. Not only that, but the numbers themselves do
not make any sense as they are always out by one pixel:

import wx

rect = wx.Rect(100, 50, 200, 200)
rectTL = wx.Rect(*rect)
rectBR = wx.Rect(*rect)

rectTL.SetTopLeft((0, 0))
rectTL
wx.Rect(0, 0, 200, 200) # width=200, height=200: unchanged

rectBR.SetBottomRight((500, 500))
rectBR
wx.Rect(100, 50, 401, 451) # width=401, height=451: way changed

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

==> Never *EVER* use RemovalGroup for your house removal. You'll
regret it forever.
The Doomed City: Removal Group: the nightmare <==

···

On 30 July 2011 20:04, Ray Pasco wrote:

in gdicmn.h:

void SetBottomRight(const wxPoint &p) { SetRight(p.x); SetBottom(p.y); }
...
void SetRight(int right) { width = right - x + 1; }
...
void SetBottom(int bottom) { height = bottom - y + 1; }

Why the "+1"? And, for God's sake, please stop putting method
implementations inside *.h files. These are just files for method
declarations. Jeez, every time I need to find something in the
wxWidgets source code I get lost. Sorry for the rant.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

==> Never *EVER* use RemovalGroup for your house removal. You'll
regret it forever.
The Doomed City: Removal Group: the nightmare <==

···

On 30 July 2011 20:57, Andrea Gavana wrote:

On 30 July 2011 20:04, Ray Pasco wrote:

I'll repeat:

Calling Rect.SetTopLeft() moves the Rect [size is unchanged],
but Rect.SetBottomRight() grows or shrinks the Size."

I don't understand what you all are saying.

I am afraid Ray is right. Not only that, but the numbers themselves do
not make any sense as they are always out by one pixel:

import wx

rect = wx.Rect(100, 50, 200, 200)
rectTL = wx.Rect(*rect)
rectBR = wx.Rect(*rect)

rectTL.SetTopLeft((0, 0))
rectTL
wx.Rect(0, 0, 200, 200) # width=200, height=200: unchanged

rectBR.SetBottomRight((500, 500))
rectBR
wx.Rect(100, 50, 401, 451) # width=401, height=451: way changed

I'll repeat:

Calling Rect.SetTopLeft() moves the Rect [size is unchanged],
but Rect.SetBottomRight() grows or shrinks the Size."

I don't understand what you all are saying.

I am afraid Ray is right. Not only that, but the numbers themselves do
not make any sense as they are always out by one pixel:

import wx

rect = wx.Rect(100, 50, 200, 200)
rectTL = wx.Rect(*rect)
rectBR = wx.Rect(*rect)

rectTL.SetTopLeft((0, 0))
rectTL
wx.Rect(0, 0, 200, 200) # width=200, height=200: unchanged

rectBR.SetBottomRight((500, 500))
rectBR
wx.Rect(100, 50, 401, 451) # width=401, height=451: way changed

in gdicmn.h:

void SetBottomRight(const wxPoint&p) { SetRight(p.x); SetBottom(p.y); }
...
void SetRight(int right) { width = right - x + 1; }
...
void SetBottom(int bottom) { height = bottom - y + 1; }

Why the "+1"?

Because you count the zero as one. IOW, a rectangle at 0,0 with width 10 and height 20 has a right side at position 9 (0 to 9 is ten pixels) and a bottom at position 19.

And, for God's sake, please stop putting method
implementations inside *.h files. These are just files for method
declarations. Jeez, every time I need to find something in the
wxWidgets source code I get lost. Sorry for the rant.

Unfortunately that's what you have to do to allow the C++ compiler to perform inline optimizations. The compiler has to see the implementation when it is included in other source modules. And I don't like it either, even after about 20 years of writing C++ code.

···

On 7/30/11 11:17 AM, Andrea Gavana wrote:

On 30 July 2011 20:57, Andrea Gavana wrote:

On 30 July 2011 20:04, Ray Pasco wrote:

--
Robin Dunn
Software Craftsman

Did wx.Rect originate from the MSW Rect routines, and so, inherit MS's,
um..., "unique" way of thinking ?

from PySide.QtCore import *
a = QRect(10, 20, 100, 200)
a.topLeft()

PySide.QtCore.QPoint(10, 20)

a.bottomRight()

PySide.QtCore.QPoint(109, 219)

a.contains(109, 219)

True

a.contains(110, 220)

False

a.right()

109

# ...

import wx
a = wx.Rect(10, 20, 100, 200)
a.GetTopLeft()

(10, 20)

a.GetBottomRight()

(109, 219)

a.Contains((109, 219))

True

a.Contains((110, 220))

False

a.GetRight()

109

# ...

To complete Robin's explanation. The "pixel arithmetic"
is working like a Python "string arithmetic" (number of
chars, index of a char).

It should be noted, the bottom-right [*] point *does not
belong* to the exposed rectangle.

Not really practical for drawing data, it is a least
a generalized accepted convention. However, in some
"plotter languages/API" (HP), the bottom-right point
is logically includes in the rectangle.

[*] Strange convention to put the y-coordinate prior
the x-coordinate!

jmf

The perverse logic to all this is that when changing Right and/or Bottom, the TopLeft (the origin/Position) is maintained and the Rect’s Size changes accordingly. Changing Top and/or Left moves the Rect and Size is maintained.

Why on Earth would anyone choose to design it this way ?

Is there an alternative to Rect that behaves in a more intuitive way ? For example:

  • Changing any edge or corner always adjusts the position, meaning that all the other unrelated edges and corners do not change. Size is always recalculated.

  • Moving the Rect has its own method using either TopLeft as the default reference or by alternatively specifying 1 of the other 3 corners to be the movement reference/origin.

Ray

I tend to agree with you. Fact is, the things are like
this.
I do not know why you have to use a Rectangle gui core
"widget". Such a component is probably deeply used by a lot
if not all widgets.

For plotting/drawing data, I'm used to create my own lib
based on the "primitive" API of the gui. This has also
the advantage, I can create my own scaling engine, which
is more "solid", that the usual proposed solution.
Eg. displaying a Dirac "fct" (FFT of a constant), with
values 0, 0, 0, 0, 1e30, 0, 0, 0, ...

jmf

···

On 31 juil, 19:47, Ray Pasco <pascor22...@gmail.com> wrote:

The perverse logic to all this is that when changing Right and/or Bottom,
the TopLeft (the origin/Position) is maintained and the Rect's Size changes
accordingly. Changing Top and/or Left *moves* the Rect and Size is
maintained.

The perverse logic to all this is that when changing Right and/or
Bottom, the TopLeft (the origin/Position) is maintained and the Rect's
Size changes accordingly. Changing Top and/or Left *moves* the Rect and
Size is maintained.

Why on Earth would anyone choose to design it this way ?

Probably because at its heart a wx.Rect is a point and a size. Being able to access and set its sides is a convenience for folks that prefer to look at it that way, but even so it is still preferable to follow the point/size conventions and behaviors for consistency.

Is there an alternative to Rect that behaves in a more intuitive way ?

You could always write your own class. As long as it has the magic Python methods implemented that make it look like a sequence of 4 integers (x,y,w,h) then you should be able to pass it directly to any of the wrapped wx methods expecting a wxRect. With appropriate properties you could probably also use it in 3rd-party Python code expecting a wx.Rect. Just be sure to not publicly publish any examples using such a class where newbies might be going to learn about wxPython, so we can avoid the inevitable confusion that would result.

···

On 7/31/11 10:47 AM, Ray Pasco wrote:

--
Robin Dunn
Software Craftsman

I’ve done just that, after a lot of head scratching untangling this bit of insanity wxWidgets created.

What’s sad is that there’s absolutely no documentation from wxWidgets about which attributes do and don’t make Size and Position be recalculated…

Ray

···

On Sun, Jul 31, 2011 at 4:38 PM, Robin Dunn robin@alldunn.com wrote:

You
could always write your own class. As long as it has the magic Python methods implemented that make it look like a sequence of 4 integers (x,y,w,h) then you should be able to pass it directly to any of the wrapped wx methods expecting a wxRect. With appropriate properties you could probably also use it in 3rd-party Python code expecting a wx.Rect.
Just be sure to not publicly publish any examples using such a class where newbies might be going to learn about wxPython, so we can avoid the inevitable confusion that would result.

Robin Dunn

See the attachment.

RectR.py (4.02 KB)

···

On Sun, Jul 31, 2011 at 11:40 PM, Ray Pasco pascor22234@gmail.com wrote:

On Sun, Jul 31, 2011 at 4:38 PM, Robin Dunn robin@alldunn.com wrote:

You
could always write your own class. As long as it has the magic Python methods implemented that make it look like a sequence of 4 integers (x,y,w,h) then you should be able to pass it directly to any of the wrapped wx methods expecting a wxRect. With appropriate properties you could probably also use it in 3rd-party Python code expecting a wx.Rect.
Just be sure to not publicly publish any examples using such a class where newbies might be going to learn about wxPython, so we can avoid the inevitable confusion that would result.

Robin Dunn

I’ve done just that, after a lot of head scratching untangling this bit of insanity wxWidgets created.

What’s sad is that there’s absolutely no documentation from wxWidgets about which attributes do and don’t make Size and Position be recalculated…

Ray


Ray Pasco

I've done just that, after a lot of head scratching untangling this bit of
insanity wxWidgets created.

I have shown this is not specific to wxWidgets.

What's sad is that there's absolutely no documentation from wxWidgets about
which attributes do and don't make Size and Position be recalculated..

http://docs.wxwidgets.org/trunk/classwx_rect.html

You may argue this is more an enumeration of
attributes and methods than an explanation.
However, it should not be to complicate to
undestand if you modify a vertex of a
rectangle, the width/height may change accordingly.

jmf

···

On 1 août, 05:40, Ray Pasco <pascor22...@gmail.com> wrote:

Andrea Gavana wrote

in gdicmn.h:

void SetBottomRight(const wxPoint &p) { SetRight(p.x); SetBottom(p.y); }
...
void SetRight(int right) { width = right - x + 1; }
...
void SetBottom(int bottom) { height = bottom - y + 1; }

Why the "+1"?

There is a philosophical difference between Windows and X in the
interpretation of "bottom" and "right", and perhaps the confusion
derives from that. In Windows, the "bottom right" point is not inside
the rectangle. A rectangle starting at (0,0) with a size of (400,300)
includes the point (399,299), and not the point (400,300), but the
rectangle structure will say (0, 0, 400, 300). This makes it easier to
do surface tiling.

In X, the "bottom" and "right" coordinates are inside the rectangle.
So, X would store that rectangle as (0, 0, 399, 299). The SetRight and
SetBottom methods from above seem to be assuming the X interpretation.
I would call SetRight(399) if I wanted the rectangle to be 400 points wide.

Please note that both of these interpretations are "right". You merely
have to know what your toolset assumes. In this case, SetBottomRight is
setting the bottommost right point that is INSIDE the rectangle.

However, I don't think this agrees with the philosophy in the rest of
wxWidgets, and is probably worth a bug report.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Robin Dunn wrote:

···

On 7/30/11 11:17 AM, Andrea Gavana wrote:

in gdicmn.h:

void SetBottomRight(const wxPoint&p) { SetRight(p.x); SetBottom(p.y); }
...
void SetRight(int right) { width = right - x + 1; }
...
void SetBottom(int bottom) { height = bottom - y + 1; }

Why the "+1"?

Because you count the zero as one. IOW, a rectangle at 0,0 with width
10 and height 20 has a right side at position 9 (0 to 9 is ten pixels)
and a bottom at position 19.

That's true in X. It's not true in Windows. In Windows, a rectangle at
0,0 with width 10 and height 20 has its right coordinate set to 10 and
its bottom coordinate set to 20. If you fill that rectangle, it only
touches (0,0) through (9,19).

Has wxWidgets actually adopted the X philosophy here?

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

jmfauth wrote:

Did wx.Rect originate from the MSW Rect routines, and so, inherit MS's,
um..., "unique" way of thinking ?

To complete Robin's explanation. The "pixel arithmetic"
is working like a Python "string arithmetic" (number of
chars, index of a char).

It should be noted, the bottom-right [*] point *does not
belong* to the exposed rectangle.

Your note is exactly backwards from what is actually happening here.
The wx SetBottomRight point DOES belong to the exposed rectangle.
That's why they add 1 to get the width. Again, that's the X interpretation.

In Windows, the bottom right does NOT belong to the exposed rectangle,
and you would not add 1 to get the width.

Not really practical for drawing data, it is a least
a generalized accepted convention. However, in some
"plotter languages/API" (HP), the bottom-right point
is logically includes in the rectangle.

Yes, as does X. Postscript deals with the problem somewhat differently,
by defining coordinates as infinitely small points that drawing is done
between. That effectively gives you the Windows interpretation; a
rectangle defining a single point in X would be (0,0,0,0), whereas in
Windows and Postscript it would be (0,0,1,1).

[*] Strange convention to put the y-coordinate prior
the x-coordinate!

Agreed, but this is kind of an English language quirk. We talk about
the "upper left" of a sheet of paper, not the "left top". Perhaps the
APIs should have been "SetPosition" and "SetSize"...

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.