FloatCanvas

OOPS, I accidentally sent this to wxPython-dev, instead of
wxPython-users the first time.

Hi all,

This is a note in response to a personal note from Robert Irie about my
FloatCanvas. I decided to poat my reply here, as I'd like to get as much
feedback as I can. If you use FloatCanvas, or might use it, or just find
it interesting, please read on and make comments.

If you've never heard of FloatCanvas, it's component designe dto make it
easy to draw stuff in floating point coordinates (including lat-long for
maps), and provides zooming, scrolling, etc. See the enclosed code.

-thanks, Chris

Robert Irie wrote:

    Thanks for writing such a great wxpython component!

you're welcome.

I'm using floatcanvas' map features for my own work (I work at a navy research lab) in
place names. I was wondering if you have progressed any further on the
events for interactive map use that you mention in the comments. What I
would like is to have the user click on a point or polygon and have a pop-up
window displayed with any relevant information.

I've made some progress, but not much. I'm waiting for a project that I
need the interactive stuff for, that I have my supervisor's permission
to work on...otherwise, I can't afford much time.

    I have subclassed FloatCanvas to add some more toolbar buttons (like
refresh/clear) and was thinking to hack together some event handling, taking
care not to interfere with the handling you are already doing for
zooming/moving. But if you have already implemented something I'ld really
appreciate getting the latest version of your code.

You probably want the latest version anyway. Here is what I have done:

I adapted it to use the new "wx" namespace. I havn't tried it under the
version 2.5 beta yet, but I do plan to before 2.5 is officially
released.

I've not got it to generate mouse events that can be handled by user
code. The generated events are just like the regular mouse events, but
they have an additional method to get the "world coordinates" of the
mouse clicks. If you read wxPython-users, you'll know that I was trying
desperatley to just alter and pass on the regular mouse events, so they
could be caught by all the same EVT_* functions, etc. I almost got it to
work but not quite. The problem is that if I raised the same event in
the floatcanvas, It got caught again, and then got in an infinite
recursion. If I raised it in the parent window, the EVT* functions
caught both the floatcanvas ones and the regular ones, making a mess.
Anyway, the way it currently works is that there are a compete set of
floatcanvas.EVT_* functions for mouse events. The resulting events are
wrappers around the normal event, so I didn't have to write boiler-plate
code to create all of the usual mouse event methods.

So, at this point, you can catch mouse events, and impliment your own
hit-test, etc code, and do whatever you want.

The ultimate goal, however, is to have the hit-test code in the
FloatCanvas. I've done a lot of thinking about this, and some
experimenting, but don't have any working code yet. Essentially, I have
two approaches in mind, and I'm not sure which I want to go with yet:

1) Use an off-screen bitmap to hold a "hit-test image". Each object that
you want to capture mouse events draws itself to that bitmap in a
different color. When you get a mouse event, the color of the pixel at
the event location indicates the object that was clicked on. I have
written some test code to try this out, and it works very well, and is
very fast for the hit-test part.

Upsides:
- Once the code is written for the FloatCanvas, additional objects coudl
be added easily, and it would be faiirly easy to make them
hit-test-able. All you'd need to do is figure out how you wnat them
drawn on teh hit-test image.

- This approach would automatically take into account the line-width,
text size, etc of the objects.

- The hit-test could be customised by chaning the line widths, filling
or not filling the shapes, etc.

- It's very fast... Catching mouse-overs is no problem.

- hit-test performance is not a function of how many objects are drawn

Downsides:

- It will slow down drawing, as the "clickable" objects have to be drawn
twice. I'm inclined to think that it won't be neccessary to have all the
objects clickable, but this will be dependent on teh application.

- I'm not sure how to deal with "sets" of objects. FloatCanvas currently
has PointSet (and other set) classes. The idea is to take advantage of
the DC.DrawXXXList methods, and substantially speed up drawing for
thousands of points (the performace gain is less for more complex
objects). For hit-testing, however, it would be easy to determine that
one of the points was hit, but not so easy to know which one. Each one
could be drawn in a separate color, but that would slow things down.
Another option would be to have another step that does the "which dot"
test.

- Only one object could get hit at once. If two objects overlap, there
would be no way to know if there was one underneath that was also hit.
This would match what the user sees, but could be limiting in some
applications.

- There is the extra memeory overhead of the additional bitmap

- The number of hitable object is limited to the number of colors in the
display (wxBitmaps can only be the same color depth as the current
screen). On modern systems, this is unlikely to be a problem, but who
knows?

2) Have every draw_object have a hit-test method that takes a coordinate
pair and determine if the object was hit.

Upsides:

- hit tests could be very customized

- There would be no impact on drawing speed

- No memory impact (unless you need to cache pixel coords...)

Downsides:

- There could be some confusion between float coordinates that define
the objects, and pixel coordinates that the user sees. It may require
that the pixel coordinates be stored for the objects when they are
drawn. THis is particularly true for objects that don't scale with
zooming: Dots, Text, Line widths, etc.

- Custom computational geometry code would have to be written for every
object type. This is a lot of work, and it could be pretty slow. I have
some of this code around already, and would probably put some of it a C
extension (or Pyrex?), but would be a lot of work.

- It might be fairly slow to check for hits...in particular, I doubt it
could be fast enough to catch mouse-overs for lots of complex objects.

Other issue:

How should the event raising/binding work?

Once the FloatCanvas has determined one way or another that an object
has been clicked on, what happens then? The easy way would be for
FloatCanvas to raise a FC_OBJECT_HIT event that contained a reference to
the object. The user code could then determine what to do based on what
object was in the event. This doesn't seem very elegent, however.

An alternative would be to have the user pass in the function that they
want called when the object is hit to the object itself. Then when it
was hit, that callback would be called. This is more elegant, but
perhaps too differnent from the normal wxPython event handling.

Perhaps there are other options as well.

There's my thoughts. I've enclosed the latest version of FLoatCanvas.py
and FloatCanvasDemo.py. This version has only been tested on Linux, with
Python 2.3 and wxPython 2.4.2, but A fairly recent version worked fine
on Windows. Note also that there is now a version of floatcanvas in teh
wxPython lib. I've set up the demop to run that version by default. If
you want to run a local version, put a "-l" on the command line:

python2.3 FloatCanvasDemo.py -l

or, if you're on *nix and have chmod +x'd it:

./FloatCanvasDemo.py -l

The other option is to jsut put the new version in the wxPython lib
directory, removing the caps from the name: floatcanvas.py. Note to
Robin: Why did you remove the caps from the name? I imagine you had a
good reason...

Please send me any bugs, feedback, suggestions, *CODE*, etc.

Note that I think FloatCanvas could use a lot cleaning up in ways that
have nothing to do with interactivity, so please send other suggestions
as well.

-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

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-dev-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-dev-help@lists.wxwindows.org