Complete.Org: Mailing Lists: Archives: freeciv-dev: March 2004:
[Freeciv-Dev] Re: (PR#8299) wrapping GUI coordinates
Home

[Freeciv-Dev] Re: (PR#8299) wrapping GUI coordinates

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] Re: (PR#8299) wrapping GUI coordinates
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 25 Mar 2004 08:54:15 -0800
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=8299 >

rwetmore@xxxxxxxxxxxx wrote:

>>There are two possible ways to do this: the easy way, and the hard way.
> 
> And *always* the third way not yet considered ...

I'm listening.

>>In the easy way we convert the GUI position to a map position, wrap that 
>>map position, then convert it back to a GUI position.  We have to 
>>remember the GUI position's offset from the map position's tile so that 
>>we end up with the proper result.  Attached patch "A" does this.  The 
>>advantage is that it is easy.  The disadvantage is that it's a hack and 
>>won't be very extensible to other problems.
> 
> It is correct.
> It leaves wrapping in the native space.

Yes.

> It separates the intrinsically tile granular wrapping from any weird
> and wonderful GUI backing store to window mappings that might involve
> varying scaling and/or pixel resolutions.

This isn't a problem, since those transformations will be a part of 
map_to_gui_pos and can easily be reproduced.

> It is likely to be the most extensible for doing odd GUI stuff, and
> the most robust (single source wrapping code never touched).

It may be the most robust but it is not the most extensible.

>>In the hard way we convert the GUI position to a "native" gui position. 
> 
> Converts a 1xn problem set to an nxn one. But may have value in some
> hard to handle special cases.

Currently an n+2 one.

>>NORMAL_TILE_WIDHT*NORMAL_TILE_HEIGHT.  We can then wrap this position 
>>directly before converting it back to a gui position.  Attached patch 
>>"B" does this.  The disadvantage is that this is hard: it takes more 
>>code than the above method, the math is hard to follow, and the very 
>>concept of "gui-native" coordinates is a bit bizarre.  
> 
> GUI-native is not bizarre, but may be unneeded and more complicated than
> is worth the trouble. Prototyping and experimenting is *good* (TM) way
> to explore issues, though.

Yes.

>>The advantage is 
>>that it is a more flexible design: gui-native coordinates can be used to 
>>do just about any topological operation needed on GUI coordinates while 
>>preserving pixel resolution (for instance a gui_distance_vector() 
>>function would be just a few lines).
> 
> It is a wide open/not-yet-thought-through design/hack that has not been
> consolidated to the point where it obeys rules like the current native
> wrapping that all use. Using a backing store and GUI shifted window as
> above is probably so simple to get the scrolling right in two steps that
> a one shot hack is probably not worth it.

Perhaps.

>>I'm not sure which method is better.
> 
> 
> I'd like to understand a bit more about what the goal actually is and
> the hard technical problems this causes before trying to answer that.

There are at least two other GUI topology problems.

1.  The overview viewrect is inaccurate.  If you play an iso-map with 
iso-view and scroll to the left, the viewrect will zig-zag.  Pretty 
mediocre.  However we can preserve pixel granularity with the following 
operation:

   int gui_to_overview_pos(*ovr_x, *ovr_y, gui_x, gui_y)
   {
     int guinat_x, guinat_y;
     const int size = NORMAL_TILE_WIDTH * NORMAL_TILE_HEIGHT;

     gui_to_guinat_x(&guinat_x, &guinat_y, gui_x, gui_y);
     *ovr_x = guinat_x * OVERVIEW_TILE_WIDTH / size;
     *ovr_y = guinat_y * OVERVIEW_TILE_HEIGHT / size;
   }

AFAICT there is no way to achieve a similar result without the use of 
gui-native position.  This is the reason I said in my second e-mail that 
I prefered the gui-native solution.

2.  With a sliding mapview (see PR#8210) we need a gui_distance_vector 
function.  This can be implemented via gui-native coordinates or via a 
conversion to map coordinates.  The former is nearly identical to 
map_distance_vector:

   int gui_distance_vector(*dx, *dy, gui_x0, gui_y0, gui_x1, gui_y1)
   {
     const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
     const int xsize = map.xsize * W * H, ysize = map.ysize * W * H;

     gui_to_guinat_pos(&gui_x0, &gui_y0, gui_x0, gui_y0);
     gui_to_guinat_pos(&gui_x1, &gui_y1, gui_x1, gui_y1);

     /* Find the native distance vector. */
     *dx = gui_x1 - gui_x0;
     *dy = gui_y1 - gui_y0;
     if (topo_has_flag(TF_WRAPX)) {
       *dx = FC_WRAP(*dx + xsize / 2, xsize) - xsize / 2;
     }
     if (topo_has_flag(TF_WRAPY)) {
       *dy = FC_WRAP(*dy + ysize / 2, ysize) - ysize / 2;
     }

     gui_x1 = gui_x0 + *dx;
     gui_y1 = gui_y0 + *dy;
     guinat_to_gui_pos(&gui_x0, &gui_y0, gui_x0, gui_y0);
     guinat_to_gui_pos(&gui_x1, &gui_y1, gui_x1, gui_y1);

     *dx = gui_x1 - gui_x0;
     *dy = gui_y1 - gui_y0;
   }

while the latter is uglier on its own but doesn't require gui-native 
positions.  It may also be inaccurate by very small (half-tile) amounts:

   /* Similar to conversion in map_to_gui_pos.  This function has other
    * users; see move_unit_map_canvas. */
   int map_to_gui_vector(*gui_dx, *gui_dy, map_dx, map_dy)
   {
     if (is_isometric) {
       *gui_dx = (map_dx - map_dy) * NORMAL_TILE_WIDTH / 2;
       *gui_dy = (map_dx + map_dy) * NORMAL_TILE_HEIGHT / 2;
     } else {
       *gui_dx = map_dx * NORMAL_TILE_HEIGHT;
       *gui_dy = map_dy * NORMAL_TILE_WIDTH;
     }
   }

   int gui_distance_vector(*dx, *dy, gui_x0, gui_y0, gui_x1, gui_y1)
   {
     int map_x0, map_y0, map_dx0, map_dy0;
     int map_x1, map_y1, map_dx1, map_dy1;
     int gui_x, gui_y, map_dx, map_dy;

     gui_to_map_pos(&map_x0, &map_y0, gui_x0, gui_y0);
     map_to_gui_pos(&gui_x, &gui_y, map_x0, map_y0);
     map_dx0 = gui_x0 - gui_x;
     map_dy0 = gui_y0 - gui_y;

     gui_to_map_pos(&map_x1, &map_y1, gui_x1, gui_y1);
     map_to_gui_pos(&gui_x, &gui_y, map_x1, map_y1);
     map_dx1 = gui_x1 - gui_x;
     map_dy1 = gui_y1 - gui_y;

     map_distance_vector(&map_dx, &map_dy,
                         map_x0, map_y0, map_x1, map_y1);
     map_to_gui_vector(dx, dy, map_dx, map_dy);
     *dx += (map_dx1 - map_dx0);
     *dy += (map_dy1 - map_dy0);
   }

jason




[Prev in Thread] Current Thread [Next in Thread]