floats passed to DC methods expecting longs

Sorry to come back to the discussion, but one another point
came to my mind. It is related to the floats arguments passed to
the dc.Methods(). I think that point is not negligible.

A computer (and its OS) has a video card and an underlying
library to drive that video card. The graphic functions of these
libraries are generally using graphic functions with integers or
longs as arguments. This argument shows that sticking on
integers in dc.Methods() will avoid bad suprises.

Surprisingly, some video libraries (or os libraries) are accepting
floats (understand large numbers) as graphic functions arguments.
What happens in such cases? I am not sure about the answer. I would
say this depends on the graphic card/driver and/or of the OS.
Sometimes, the drivers converts a large float value into a wrong
"integer representation". The application is working without any crush
or compiling complaints, but the end result is just wrong.

Once again, let see this with an example. I can draw an horizontal
line from the centre of the screen (mx, my) to the right with a
statement like this

object.DrawLineXY(mx, my, mx + 100, my).

Now look at what is happening on my screen with the following
statement

object.DrawLineXY(mx, my, mx + 10.0e10, my)

The line is drawn from the centre of the screen to the left! And without
any compiling complaints.
I can repeat the exercise with varying the x-coordinate of the second
point. I get the issue when"x2" > 65535 (2**16-1).

I had the opportunity to test this behaviour on some others
win platforms, same issue. (I just wonder if this is not an
gdi.dll bug???)

Anyway the message behind this example, is that you do not
meet bad suprises if your are forced to use integers as
dc.Methods() arguments. In the present example, you
would have had at least a warning.
This example is obvious, I have done enough "scientific plotting",
I know this type of logical error is sometimes difficult to see
(real curve or display artefact)

I am not a guru in computer science (beeing an hobbyist),
how does the other languages/toolkits respond to this
problem?
JAVA and win32 API fcts are forcing the use of integers.
I know the case in Visual Basic. This is even worth, the
graphic function arguments are of type single, neither integer
of double !). My experience, a lot of problems.
wxWidgets requires integers.

My philosophy. If a library is forcing the programer to use
the right type, the best it is. After all, a pixel is an "atomic
entity".

As an analogy, I can mention the AltGr problem in wxPython
applications. It is amazing to see the number of wxPy apllications
that are not working on my non US platform, just because people
are not progamming the event.KeyDown() correclty.

As you say in your coutry, just my 2 cents

jmf

ka

<snip>

object.DrawLineXY(mx, my, mx + 100, my).

Now look at what is happening on my screen with the following
statement

object.DrawLineXY(mx, my, mx + 10.0e10, my)

The line is drawn from the centre of the screen to the left! And without
any compiling complaints.
I can repeat the exercise with varying the x-coordinate of the second
point. I get the issue when"x2" > 65535 (2**16-1).

I had the opportunity to test this behaviour on some others
win platforms, same issue. (I just wonder if this is not an
gdi.dll bug???)

If you try and use a float that is too large then you'll get an error like

OverflowError: long int too large to convert to int

Anyway the message behind this example, is that you do not
meet bad suprises if your are forced to use integers as
dc.Methods() arguments. In the present example, you
would have had at least a warning.
This example is obvious, I have done enough "scientific plotting",
I know this type of logical error is sometimes difficult to see
(real curve or display artefact)

I am not a guru in computer science (beeing an hobbyist),
how does the other languages/toolkits respond to this
problem?
JAVA and win32 API fcts are forcing the use of integers.
I know the case in Visual Basic. This is even worth, the
graphic function arguments are of type single, neither integer
of double !). My experience, a lot of problems.
wxWidgets requires integers.

My philosophy. If a library is forcing the programer to use
the right type, the best it is. After all, a pixel is an "atomic
entity".

In Python, it is not really the type that is important, rather the interface. If an object walks like a duck and quacks like a duck then you can treat it like a duck even if isn't. Insert obligatory Holy Grail joke here about wood, floating, witches, etc.

The conversion of the float to an int is both for convenience and an optimization, since doing all the conversions in Python code leads to slow performance. In general, people will use ints or longs and it won't matter, but when you need to use a virtual coordinate space, support scaling without loss of precision, etc. the auto-convert is a really important. Even with normal drawing you end up with float results simply because Python is going to use a float for a calculation and result if you have a float in the expression, the simple case being the use of sin, cos, and tan, especially if your drawing involves any rotation or calculation of angles. Having to wrap everything with int() just makes the code harder to read, slows it down, and doesn't give you any real protection from logic or bounding errors.

The solution Robin came up with is actually quite slick because it means that if you want a very rigid object for your drawing operations you can create your own class that handles the __int__ conversion and that also allows you to use rigid bound testing, all hidden in one class.

Now here is the kicker. Newer drawing APIs like Cocoa use floats not ints because it is a virtual canvas. I'm guessing that wxCocoa should use floats instead of int/longs. My understanding is that the new drawing API for Longhorn, the next version of Windows has something similar. So at some point we'll be supporting floats anyway.

Finally, this is just the first 2.5.x release, there will be more and we have more releases to reverse issues like this if needed before 2.6 is released.

ka

···

On Mar 31, 2004, at 6:21 AM, Jean-Michel Fauth wrote:

Jean-Michel Fauth wrote:

Once again, let see this with an example. I can draw an horizontal
line from the centre of the screen (mx, my) to the right with a statement like this

object.DrawLineXY(mx, my, mx + 100, my).

Now look at what is happening on my screen with the following
statement

object.DrawLineXY(mx, my, mx + 10.0e10, my)

The line is drawn from the centre of the screen to the left! And without
any compiling complaints.
I can repeat the exercise with varying the x-coordinate of the second
point. I get the issue when"x2" > 65535 (2**16-1).

I had the opportunity to test this behaviour on some others
win platforms, same issue. (I just wonder if this is not an
gdi.dll bug???)

It has nothing to do with allowing floating point and everything to do with the fact that drawing coordinates on win98 are limited to 2**16, but integers are 2**32. You would have the same integer overflow issue in C++ with these functions. In fact, IIRC, some compilers wouldn't even complain if you passed floating point values.

Anyway, the bottom line is that Python is still the one doing the conversion just like wx 2.4.x in Python < 2.3, not my code. I'm just calling PyInt_AsLong or raising a custom exception if a number was not passed in. It would in fact be more work to exclude floats.

This change was motivated by the fact that SWIG stopped using PyArg_ParseTuple to do the parameter conversion for ints and other basic types, and the code they used instead raised a meaningless exception if there was a bad type passed in. I found that the most efficient test and convert also happened to allow floats, (or any type that can convert itself to an integer) which I knew would make a lot of people happy, so it seemed to be the best option to choose for more than just efficiency reasons.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Now look at what is happening on my screen with the following
statement

object.DrawLineXY(mx, my, mx + 10.0e10, my)

The line is drawn from the centre of the screen to the left! And without
any compiling complaints.
I can repeat the exercise with varying the x-coordinate of the second
point. I get the issue when"x2" > 65535 (2**16-1).

This is not an issue with floats, in fact, quite the opposite, it is an issue with integers overflowing, which doesn't happen in Python anymore, as they are cast to a python long int when they would overflow. In C however, it's standard behavior. I think integers overflow in Numeric without warning as well.

If you try and use a float that is too large then you'll get an error like

OverflowError: long int too large to convert to int

Presumably the same thing with a Python long int. I have mixed feeling about his, however. In the past, if you zoom in too far with my FloatCanvas, the drawing gets screwy as the coordinates overflow, but you don't get any exceptions. I kind of like this, as it still works, without me having to detect and trap the too big values. However, it's probably better to set zoom limits anyway, so I guess this will force me to do it.

This example is obvious, I have done enough "scientific plotting",
I know this type of logical error is sometimes difficult to see
(real curve or display artefact)

Yes, it can be tricky. but Robin's new method does not preclude you from using all integers if you want to, and preventing surprises. I think the rule of thumb with this kind of thing, and Floating Point in particular, is that most of the time, for most people, it "just works". When it doesn't you'd better know what you are doing. I don't think this is changed by the auto-casting, except now people will only have to think about if it causes a problem for them, and not if it doesn't. the downside is that it might take them a while to realize why they are having the problem, but I suspect anyone who just carelessly throws int() around everything could still have problems.

wxWidgets requires integers.

Which is an unfortunate limitation. the PostscriptDC is problematic, because Postscript is supposed to be scalable. Limiting resolution to 1 pt is horrid. i think the solution was to have the PotscriptDC use 1/10 (or 1/100) of a pt as the unit, but floating point would make much more sense. In fact, printing as a whole is a pain, because you have to deal with the resolution of the printer, so you know what units to deal with. Furthermore, with scalable fonts and anti-aliasing, drawing calls shouldn't be limited to integers even on the screen. (Check out the Antigrain graphics library.. very nice job with line widths less than one pixel)

My philosophy. If a library is forcing the programer to use
the right type, the best it is. After all, a pixel is an "atomic
entity".

not with anti-aliasing.

The conversion of the float to an int is both for convenience and an optimization, since doing all the conversions in Python code leads to slow performance.

Are you sure about that? the conversion is happening in either case, with pretty much the same code. In fact, a couple versions ago, when we could pass Floating point numbers in, it was faster to use Numeric to convert an array of points to Int than to pass in an array of floats and the wxPython code convert it. That may have been unique to the DrawXXXList code, but I'm not at all sure we're getting a useful optimization out of this.

In general, people will use ints or longs and it won't matter, but when you need to use a virtual coordinate space, support scaling without loss of precision, etc. the auto-convert is a really important.

Well, not really important, but handy. If you want to be able to reverse the process, you need to store your scaled coords in FP, and then convert on every DC call, which is uglier. In my FloatCanvas, I just converted on each calculation (using Numeric), and it works fine. in wxPyPlot, there was a need (at least Gordon thought there was) to keep the scaled coords around in FP, so he has to convert to int() on every DC call. He wrote a DC wrapper to do that, but it would have been cleaner to have it built in to the DC.

The solution Robin came up with is actually quite slick because it means that if you want a very rigid object for your drawing operations you can create your own class that handles the __int__ conversion and that also allows you to use rigid bound testing, all hidden in one class.

Yes, I agree, very nice.

Now here is the kicker. Newer drawing APIs like Cocoa use floats not ints because it is a virtual canvas. I'm guessing that wxCocoa should use floats instead of int/longs. My understanding is that the new drawing API for Longhorn, the next version of Windows has something similar. So at some point we'll be supporting floats anyway.

More fuel for my point above. However, this really isn't that relevant. In the near term wxDCs will take only integers. If in the future, there is a FP implementation of wxDC, wxPython will wrap that, and will surely allow ints to be used as well. I suppose if we allow floats now, some folks might suddenly get better resolution for free with their old code, but it will be a new may of thinking anyway.

I think the trade off is thus:

If we allow floats, folks code can be cleaner and easier to write, and most people won't have to think about it.

If we don't allow floats, folks will be forced to think about the coercion issues up front, and thus are less likely to get mysterious behavior.

I think the auto casting is a bit more Pythonic. In general, you don't have to think about types much in Python, but when it's critical, you have control if you need it.

-Chris

Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

···

On Mar 31, 2004, at 8:29 AM, Kevin Altis wrote:

On Mar 31, 2004, at 6:21 AM, Jean-Michel Fauth wrote:

Kevin Altis:

My understanding is that the new
drawing API for Longhorn, the next version of Windows has something
similar. So at some point we'll be supporting floats anyway.

   GDI+, the graphics layer beneath .NET currently uses floating point
coordinates.

   Neil