This problem seems harder to address than Issue 135.
I fixed it on my machine with some quick and dirty workarounds.  I am
not hurrying to fix this issue in this post.

Labyrinth 0.4 have rudimentary zooming capability and the SVN trunk
version made some improvement, but still buggy.

As for the SVN version, when mouse wheel is scrolled, what actually
happened is as follows:

1. The cursor point (I mean the point where the mouse cursor is
pointing at) moves to the center of the window.
2. The view zooms, with the center of the window as an fixed point(the
point that doesn't move when zooming).

A good zooming expects the "cursor point" to be the "fixed point".
This point should not move while other points move towards this point
when zooming out, and move away from this point when zooming in.

Look at how "zooming" is currently implemented:

in MMapArea.py:

def scroll (self, widget, event):
    scale = self.scale_fac  # Backup the old scale factor
    if event.direction == gtk.gdk.SCROLL_UP:
        self.scale_fac*=1.2  # update to new scale factor

        coords = self.transform_coords(event.x, event.y)  # get the
"user" coordinates of mouse-pointer
        geom = self.window.get_geometry()  # get the window size ( in
"device" coords )
        middle = self.transform_coords(geom[2]/2.0, geom[3]/2.0)  #
get window center and transform into "user" coords

        self.translation[0] -= coords[0] - middle[0]  # move the
"cursor point" to the center of the window
        self.translation[1] -= coords[1] - middle[1]  # and y coordinate
    elif event.direction == gtk.gdk.SCROLL_DOWN:
        self.scale_fac/=1.2
    self.undo.add_undo (UndoManager.UndoAction (self,
UndoManager.TRANSFORM_CANVAS, \
                                                self.undo_transform_cb,
                                                scale, self.scale_fac,
self.translation,
                                                self.translation))
    self.invalidate()

See the problem?  After zooming, the "cursor point" is moved to the
center of the window.  That is not expected to happen.
And another problem is that zooming-in and zooming-out are also
assymetric. Zooming-out does not move self.translation.  This is also
incorrect.
But I will not go for a quick workaround here.
Instead, let's look at the draw() function:

In MMapArea.py:

def draw (self, event, context):
    '''Draw the map and all the associated thoughts'''
    area = event.area

    ... # some initializations

    alloc = self.get_allocation ()
    context.translate(alloc.width/2., alloc.height/2.)
    context.scale(self.scale_fac, self.scale_fac)
    context.translate(-alloc.width/2., -alloc.height/2.)
    context.translate(self.translation[0], self.translation[1]) #
attention here.

    ... # other drawings follows

There are four transformations: three translate()'s and one scale()'s.
 These can be interpreted as four operations done sequentially (in the
reversed order of the code).

I think the problem is in the self.translation.  What does
self.translation denotes?  According to the above operations,
self.translation is merely an "ACTION" that should be performed as the
first step of coordinates transformation.  Does self.translation have
other meanings?  I found that the point (-self.translation[0],
-self.translation[1]) lies in the top-left corner of the window when
self.scale_fac==1.  Though I have found "where" self.translation is, I
think it is a "weird" point that haunts around on the "user" canvas.

We can use other denotion instead of the currently used self.translation.

Let's introduce another attribute self.central_point_of_view.  It
satisfies the following condition:
1. self.central_point_of_view is a point on the "user" coordinates.
2. When translating from "user" coordinates to the "device"
coordinates self.central_point_of_view should always be translated to
the center of the window, and not affected by self.scale_fac and the
size of the window.

The effect of this change will be:
1. When panning the view-area (i.e. hold the middle mouse-button and
move), self.central_point_of_view should be moved in the opposite
direction of self.translation
2. The translation steps in the draw() method should become:

    context.translate(alloc.width/2., alloc.height/2.)
    context.scale(self.scale_fac, self.scale_fac)
    
context.translate(-self.central_point_of_view[0],-self.central_point_of_view[1])
# note the negative sign.

3. When scaling (move the mouse-wheel), the code would become:

    def scroll (self, widget, event):
        scale = self.scale_fac
        if event.direction == gtk.gdk.SCROLL_UP:
            self.scale_fac*=1.2
        elif event.direction == gtk.gdk.SCROLL_DOWN:
            self.scale_fac/=1.2

        coords = self.transform_coords(event.x, event.y)
        # geom = self.window.get_geometry()
        # middle = self.transform_coords(geom[2]/2.0, geom[3]/2.0)
        # These are not needed. middle is always self.central_point_of_view

        def move_position(mouse, middle):
            """ Since we are moving x-coord and y-coord in the same
way, I create a function """
            old_delta = middle - mouse
            new_delta = old_delta / 1.2    # suppose we zoom in.  Yes, zoom IN
            new_middle = mouse+new_delta
            return new_middle

        self.central_point_of_view[0] =
move_position(coords[0],self.central_point_of_view[0])
        self.central_point_of_view[1] =
move_position(coords[1],self.central_point_of_view[1])

How move_position() works?
If we zoom-in while keeping the current "mouse point" fixed, then the
self.central_point_of_view moves towards the "mouse point" in the
"user" coords, because zooming-in means that the same on-screen
distance worths less in the "user" coords.

And there is a side-effect when we use self.central_point_of_view
instead of self.translation.  When we resize the window, the result
becomes different.  Now the central point keeps fixed while in the
past the top-left point was fixed.

Currently self.translation is referenced all around the code.  It
should be taken seriously whether to introduce
self.central_point_of_view and remove self.translation.

Summary:

1. The current implementation of scroll() is obviously incorrect.
2. The self.translation is strange.  It is difficult to understand and
difficult to use.
3. Introducing self.central_point_of_view will simplify coordinate
handling, but will result in many code-changes.


Kunshan Wang

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Labyrinth Discussion" group.
To post to this group, send email to labyrinth-devel@googlegroups.com
To unsubscribe from this group, send email to 
labyrinth-devel+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/labyrinth-devel?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to