Complete.Org: Mailing Lists: Archives: freeciv-dev: January 2002:
[Freeciv-Dev] Re: Native Coordinates [Was:[PATCH] Map cleanups (PR#1208
Home

[Freeciv-Dev] Re: Native Coordinates [Was:[PATCH] Map cleanups (PR#1208

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Cc: freeciv-dev <freeciv-dev@xxxxxxxxxxx>
Subject: [Freeciv-Dev] Re: Native Coordinates [Was:[PATCH] Map cleanups (PR#1208)
From: Jason Short <vze2zq63@xxxxxxxxxxx>
Date: Thu, 10 Jan 2002 05:49:21 -0500
Reply-to: jdorje@xxxxxxxxxxxx

Ross W. Wetmore wrote:

At 03:43 AM 02/01/09 -0500, Jason Short wrote:

Ross W. Wetmore wrote:


I've taken this to a fresh debate forum.

As a quick backgrounder so we can start from a common set of
(mis)understood terms  ...

I am using "standard" or "map" or "game" coordinates to mean the internal coordinate system used in most of the current code. The standard set is 2-D rectangular (x,y) based, and is typified by the trident tileset on the usual world map.

I use "native" coordinates to mean a coordinate system which is
generally rectangular in shape, but whose coordinates are not necessarily spaced or organized in a standard rectangular grid.
An example is a true isometric map which occupies only even or
odd points (i.e. x+y is even or odd) and is thus diagonal in
spacing. Native isometric coordinates can be mapped to standard
coordinates to give a pi/4 rotated rectangular array.

Compressed native isometric recognizes that every other position
is unoccupied in each row and indexes the row value as x' = x/2.
There is also a shift of 1/2 position in a zigzag pattern that
gets lost when doing this, but the even or oddness of the y or
row value can be used to fix this up in any reverse conversion.

For standard maps, standard and native coordinates are equivalent.

A key property of native coordinates is that no real coordinate position appears more than once.
Another property that must be built in to any native coordinate
system is that wrapping axes are aligned with the rectangular
coordinate axes.

I am of several minds about native coordinates.

1. Native iso coordinates are great to do topological calculations in if you have an iso-rectangular topology. But this can be done entirely internally to the topology code (i.e. without "native coordinates" as a global concept).


It is always nice to have a concept to guide your programming. It is like
a plan before you build. Understanding before you speak.

It simplifies the internal calculations immensely to switch when this
is beneficial instead of slogging through complex mistake prone standard
calculations, or heuristic algorithms that try to mimic them.

Probably, but it depends on the implementation. But this can be done entirely within map.c (or map_topology.c), and need not be introduced until we're ready for a topology that needs it.


3. Native iso coordinates do allow some game tasks, such as whole_map_iterate, to be done more cleanly _and_ efficiently. This can also be achieved by index positions just as effectively, though.


No. They do not handle savegames or debug output well. They do not
deal with normalization or border computations. All these are 2-D,
while linear coordinates are just good for listing things efficiently.

I was not speaking of savegames or debug output, although I can see I was unclear.

Debug output is IMO handled much better in flat coordinates because it is always drawn flat. savegames are slightly easier with native positions than with index positions, just because they are more human-readable.


4. Native coordinates for anything other than iso-rectangular and flat-rectangular topologies have not been proposed, or even considered.

These are part of the "global concept" that you threw out above. There is also discussion below of how to handle all wrapping cases, and the
rest are filter cases. This covers, your elliptical, hexagonal, "magic"
and others.

Filter cases I understand. This does not cover the hexagonal case (unless one considers it as a filter and gives up on having native coordinates for it, in which case one must loosen the definition of native coordinates - which is my point).


Is it possible for a "native coordinate" set meeting the above specifications to be created for, say, a wrapping hexagonal map?

To help you along. Wrapping hexagonal maps in 2-D still have the same
orthogonal wrapping axes as all wrapping topologies. The native set is
thus bounded by the wrapping dimensions (map.xsize,map.ysize) and the
coordinates are stored as in the article referenced previously. Standard coordinates won't be too useful though, as there are 6 and
not 8 directions with a lot of different local algorithms to fix up.

You are being lead astray by the article, which does not talk about topologies at all, either isometric or hexagonal. It only talks about tiles, and does a pretty mediocre job at that.

An isometric map has nothing to do with using isometric tiles, nor does a hexagonal map mean using hexagonal tiles. The map is shaped hexagonally, and the vectors of wrapping are most definitely not orthogonal in any standard coordinate system.


What about a flat-rectangular map that has unreal positions within the regular set (for instance, an ellipse)?


Your ellipse example is unwrapped. So it is just bounded by a rectangular
(map.xsize,map.ysize) grid with a filter condition to determine realness.
The native and your regular coordinates would be the same (no need to rotate the axes unless the ellipse is also rotated).

Yes, the filtered case has been covered. Here we give up on achieving a native coordinate set for the topology, and instead use a native coordinate set for the surrounding (unfiltered) topology. We thus have the concept of "regular" native positions, but (1) the bounding set is a lot more efficient and (2) we still don't have more than one equivalent real position within the regular set.

However, I don't see how (2) can be achieved for the hexagonal case, much less the general case.


What about in the general case?

What about it. Since native coordinates can as a first approximation be taken as your regular bounding box, except one chosen to minimize the
number of unreal tiles by appropriate rotation of the coordinates axes
(to align with the true-iso rectangle wrap axes for instence), they
should be somewhat more flexible and general than your more limited
case that forces a standard to regular constraint.

Yes, but this is just an increase in efficiency, so there is no need to add them until later.

To put it another way: you have stated that a big advantage of native coordinates is that no two regular native positions will ever be equivalent. If this cannot be guaranteed in the general case (AFAICT it cannot), then a big advantage of native coordinates has gone away. The most immediate effect of this is that your is_normal_map_pos->normalize_map_pos change in rand_map_pos is no longer correct even if we switch to using native coordinates.

Does this mean native coordinates are bad? No. But it means they are less of a priority, since they can never be a perfect solution.


If we introduce native iso coordinates and then have to fall back on using a "native regular" bounding box for them, then we haven't gained much.


Except to eliminate all the inefficiencies from unreal tiles which I
know is the backwards way to think about this. Or the simplification
of all the wrapping operations, the savegame bloat, the debug print
understanability. I know this isn't much  ...

We all agree that native coordinates work great for the iso case. But in the hexagonal case they will gain us nothing.


If you wrap, then the wrap dimension size determines the normal set to guarantee real coordinates appear only once in the native space. Once
you are guaranteed of this, filtering removes any unreal tiles within
these bounds.
The "regular" part of regular native, is the real+unreal native space
that is left when you reduce to a unique normal set. The real subset
of this is what you actually call normal, but I am happy to leave this
regular set as normal, and just worry about real/unreal. The regular
set is what is defined in memory, printed out, put in save games, etc
with some positions marked as unreal.

You've done all this and we can build on it, but you don't really need to add any "regular" functions or odd flavours of tests, or inefficiencies
to do all this if you do it right.

Well, I think we both agree that all native positions are "regular", that is, we don't even consider the positions outside of the regular set.

The question is, is this native regular set more useful than the flat regular set? In the iso case it is, but the general case still has not been addressed.


normalize_map_pos() and is_real_tile() are all one needs. No is_normal
condition is required for instance.

The difference between your regular and native results from relaxing
the linkage to standard, and making sure that native has some global
concept like "real" or "normal" that is reflected in the topology
functions.

The problem with "making sure" is that you run into problems when it's not possible.


A standard-regular set is some random collection of points that have
little global significance. It is just a bounding box hack.

>

5. Native coordinates are not a necessity but a convenience. Everything that has been discussed can be accomplished without them. In many cases, it can be done just as cleanly and efficiently using index positions.


For listing or vector operations, yes. For 2-D operations no. Most
topology functions involve 2-D relationships. Generic filters are the big class that index coordinates are most useful for and we should probably use them for all of this. But filter algorithms are likely
still best done in native coordinates for special cases.

But the difference is only incremental, and the changes are localized.


6. Finally, I see little reason why native coordinates can't be introduced later (after several different topologies are working), and used as necessary.


You mean do all the complicated general operations in regular or map coordinates, then figure out how to simplify them into native operations?

Why not just use native coordinates now for the things where they are useful?

Because it requires many more changes to the code, as the regular system is already in place.


You have split regular == map into two sets when you went to true iso
topologies. But a more efficient (rinse my mouth out) split for this
is standard and a (rotated regular == native).

You're confusing types of coordinate with coordinate sets. A regular native set is often more useful than a regular flat/map set, but the as I've explained above the difference is only in efficiency.


normalize_map_pos() doesn't change if you do it in native coordinates
so what you need to add is a map_to_native() at the start and a native_to_map_pos() as you return to have a standard coordinate normalize_map_pos().

I'm not saying it's impossible to do with a hexagonal map, but it certainly hasn't been explained yet. Nor has it been proven that all vector-preserving maps must be either hexagonal or rectangular (though I believe it is so). Nor have non-vector-preserving maps even been considered, for the most part.


whole_map_iterate() doesn't change, except if this is iterating over
native coordinates and they are no longer synonymous with standard or
map then you need to add a native_to_map_pos() transformation.

Note, you could use an index_to_map_pos() and use the linear form of
whole_map_iterate() in the corecleanups.

In fact, if you only access normalized coordinates, then all elements
like map.tiles should be be stored in linear coordinates and you need
to do a map_to_index() transform everytime you access them. But wait,
this is what Freeciv does already, why did it need to convert to regular :-?.

Freeciv uses map_inx to index into it, but all of the storage structures are hard-coded. map.tiles is hard-coded as a map.xsize x map.ysize array, and all local storage is either done that way or uses a double array. Eventually all of this should be converted to entirely use index positions, but this is also just a difference in efficiency.


There is nothing magic about native, standard, regular, linear. They
are all just ways of looking at similar things. Some ways have useful
properties when doing some things, so one should take advantage of this.

The problem is that while standard and linear are well-defined, native has not yet been. You have incorrectly assumed that all wrapping vectors must be orthogonal, and narrowly defined native positions to work with rectangular topologies.


Regular as you have used it just doesn't take the best advantage of things that others do, and certainly a lot of the original standard
operations didn't take much advantage of anything in the iso case.
These are the places where things are changing.


Most of their uses are local, and so once issue #4 has been resolved it should just be a matter of introducing the conversion functions and then using the native coordinates on a case-by-case basis.


That is pretty much what I have done. I used native operations where
I figured out they made sense. There may be some places that I've
missed, of others where standard -> linear or some such can also be done the same way.

OK.  Now implement a hexagonal map :-).



It might be nice one day to convert everything to native in a savegame, rather than just the global parts. This would mean you could save a game as an isometric world, hack the maptype in the savegame and read
it back in as a standard map. All the tile relationships would be
totally wacky, but everything would be in the right spots and it would probably play without trouble - sanity_checks of continental
integrity and such tile rearrangements excepted :-).

Yes.


For me, point #4 is the overriding concern. While Gaute and Ross have proposed systems to hack in the 8 "standard" topologies (Ross's recent corecleanups have taken a somewhat more general approach), most of my changes have been geared toward first separating all topology code. This then allows any topology within a rather loose set of restrictions.


These are the "critical" or must do cases. And fixing up isometric is
I think probably the most important part.

I think that in doing this we have figured out a lot of the complexity
and experimentally verified the resulting changes.

Not if you don't think ahead.

So long as native coordinates are defined in a sufficiently loose manner, everything should be fine. But if you make the definition too restricted (as I think you have), then it may make it impossible to impelement native coordinates at all for certain topologies.


Your separation work keeps us honest, and is very useful in pinpointing
the interfaces and structure that local fixing misses.
The combination of topdown and bottom up can result in more rapid change
and correct change after the initial stages of either are petering out.
So doing things in parallel or differently is not bad.

Hey, we have found another point of agreement.


The trick is to be able to merge and join the two when the time comes.

Yes. In this case, we are largely arguing about the _order_ of implementation. This is probably not the best use of time. We really should go back to arguing about unnormalize_map_pos/find_representative_map_pos.


In fact, almost all global game and topology operations are easiest
to handle in this representational form, is_border_tile() for
instance is only slightly more tricky because of the zizag in
native isometric.

Topology operations certainly.

For game operations, it depends on what you mean by "global". whole_map_iterate could certainly benefit from using native or index positions, but I'd call this local rather than global.


Global is iterating over the whole map. Local is map_stepping to adjacent tiles.

Global parameters are border and wrap dimensions, local are directional
tile relationships and distance computations.

OK. These are global in terms of the world, but local in terms of the code. Most stuff that is global in terms of the code is local in terms of the world and best done in map positions (although there are exceptions).


Conversely, standard map representations are best used for local
game and directional operations like adjacent iteration.

Making sure one has designed the native representation appropriately
and that there is a reasonably efficient coordinate transformation
process allows one to convert to the representation best suited for given operations on the fly in local codepaths. It means one does not have to decide up front which is the one-true-representation that has to do it all, no matter how cumbersome or complicated things get.


There is a competing term "flat" for standard coordinates. Personally
I think all 2-D coordinates are flat, and "Flat-Earth" is a general
term for a non-wrapping topology, so this is confusing and overloaded.
But we should add "flat" to "standard" or "map" or "game" as an alternate
designation until it's use dies out :-).

Well, my interpretation is like this:

* native: whatever system is most convenient for the current topology
* iso: a native iso-rectangular system
* flat: the opposite of iso, i.e. a native flat-rectangular system
* standard / game / map: whatever the game uses as its main coordinate system. I much prefer "map" to game or standard, since that's what all the functions call it. * index: a single integer identifier in the range [0..n]. This is much easier to implement if we allow values within this range to be invalid, i.e. not identified with a unique map position.


I will resist quibbling here ... basically we agree.

Yes.


I'm willing to give up flat in favor of map, but not in favor of standard or game. Currently flat == map == native. In the foreseeable future we will have map == flat, but this will not necessarily always be the case.


map is the internal standard game coordinates, I'm fine with that.

It should be described as the "standard" that all others need to be
able to convert to and from, but we don't need to label it "standard".

This means we have native iso and native map coordinates as the two
core coordinates systems used in most global operations. They have
4 wrapping flavours each to give 8 topologically distinct maps. The
GUI has two views, isometric and (map) to give 16 unique ways to play
the game.

Native generally deals with a particular topology. So we have native iso-rectangular and native flat-rectangular (==map) positions. Hopefully we can also have native hexagonal and (of dubious use) native iso-hexagonal positions. Some day we may come up with native circular positions, just to make that topology more efficient.


Regular is a term that is used to describe a rectangular bounding box
in standard coordinates that encloses a complete normal set such as a
pi/4 rotated true isometric rectangle.
While we're on the topic, just to rehash:

- normal: a representative set chosen by us. It has no significance other than what we give it, but using it makes calculations and debugging much easier.


Normal has some concept of uniqueness associated with the set. There
are never two equivalent positions in a normal set.

Yes.


- real.  Duh.


Let me help. Real coordinates are the necessary part of the game. Unreal coordinates are an unrecoverable error condition, except to void_tile adherents.

Yes. Unreal coordinates are an unrecoverable error condition, except to those willing to accept a void_tile-ish solution :-).


- regular: a convenient bounding box for the normal set.

Currently we talk about "normal map positions" and "regular map positions", but if we introduce native positions and can't figure out how to work different topologies we may end up with regular native positions, and that would IMO suck.


I think (regular == normal) in native coordinates if you are willing
to relax the realness constraint on normal to include filtered unreal
positions. Thus linear coordinates are also always normal even when
they have extra positions to make calculation easier.

OK, although I don't think the semantics on the linear/index positions are really important.


The only important condition for map coordinates is realness. It is
the native/regular/index ones that need something like normal to make storage and the like work.

You're still confusing coordinate types with coordinate sets. Regular is not a "type" of coordinate; there's no map_to_regular_pos function. It's a set of coordinates, chosen by us just as the normal set is chosen. When we say "regular" coordinates, we mean "regular map" coordinates. Of course, this is mostly just quibbling over semantics.


For standard maps, standard and regular coordinates are equivalent.
For a 100 x 2 isometric map, this would be a 102 x 102 square.
Yep. Anyone who wants to use a 100x2 isometric map is doomed to a 98% waste of memory if we use regular positions for storing map data. This was deemed acceptable (Tony, Raimar, and I all agreed IIRC), mostly because nobody would play with a 100x2 map.


Except those that are trying to argue candycaning is necessary :-)

Hey, good point :-).


Typically one iterates over all values of the regular map and selects the ones that are normal for global operations (<2% in the above case, but never better than 50%).

Yes. This leads to an inefficient loop, although in most/all cases it will be unnoticable..


All these unnoticeables, especially when they are all in the same
direction, do add up you know :-)

Once they do we can fix them. Fixing them before they are inefficient seems unnecessary.


Unfortunately, in wrapping scenarios, there may be a lot of equivalent coordinate positions in the regular set that map into the normal subset (over a 50 in a torus world for the given example, but never less than 2).

So? Just skip those positions. The fact that they're equivalent is only a problem if you insist on calling normalize_map_pos instead of is_normal_map_pos, which unfortunately you (Ross) do.


Actually, it is the number of times that I FAIL and just spend CPU cycles
spinning that bothers me when I do this.

Usually this is no greater than 50%, which is comparable to the time waste you'd have in converting to native coordinates and back.


Storing savegames, debug printing etc. are all typically done in the
regular coordinate system because of the rectangular axes. Typically
"unreal" or "duplicate" markers are stored for the extra positions.
For the above isometric world, one would see a diagonal band or rectangle
on printout of 102 lines of 102 elements, and a 5200% increase in savegame
size.

That's a gross exageration. It will result in a 5200% increase in the map part of the savegame size. In a savegame I just looked at, the map data accounted for 12% of the savegame. So we'd end up with a 52*12/100=500% increase in savegame size in this pathological case. In the median case it will account for about a 15% increase.


In a Savegame of ~4200 lines, ~700 are the initial map, and all but
100 of 500 for each of the 7 players are map-sized objects. These lines
are always 80 columns or better while the residual is typically 20 characters or less.

So, 16% + 80% * 84% ~= 83% of the save game is of map-sized data in lines
not even data units.

Touche.  I had, of course, forgotten the player maps.


I think you underestimate the effect this is going to have on Renier and
Paul's server hardware budget.

Only if people play on 100x2 maps!


Note it is always possible to choose a native or a regular system for
any given 2-D topology, and a coordinate system that maps it to the
standard internal game coordinates and back.
It is certainly always possible to choose a regular system. A native system has more restrictions and may not always be possible.


I laugh ... native has more restrictions :-).

Restrictions are a good thing - they allow you to do things simply and cleanly.


At its worst, native == regular.

Yes, but with an extra conversion required.


It must be my backwards English, and genetic heritage again.


Choosing a regular system means identifying the extremum points in the topology in the axial directions. Choosing a native system means choosing a regular system in a rotated coordinate frame that is aligned with the topological wrapping axes, or in one that minimizes the number of unreal tiles if there is no axial constraint.

As I understand native coordinates, they have normal==regular. How can this be guaranteed for unusual topologies?


Good ... (normal == regular) == agreement

normal==regular is a restriction, and a good one since it allows a lot of tasks to be done much more easily.

Unfortunately, it's not possible because of filtered cases. Here we will (in the iso-rectangular case, at least) have a much lower miss rate, but we won't be able to take advantage of this with simpler code constructs - we'll still have to check each time. So certainly some _regular_ native positions will not be _normal_.

Unless we can solve the hexagonal case and are willing to take our chances in the future, we will also have to abandon the other restriction: that each real position is represented only once within the regular native set. Then we will still have an efficiency gain, but will miss out on some more simpler code constructs. This is what I think we should do, but I think we should think about it some more.


It is explained above. For 2-D wrapping topologies which have many equivalent positions, but two orthogonal rectangular wrap axes with given wrap dimensions, it is the rectangle formed by these dimensions. If you have no wrapping it is the smallest bounding box that encloses all the points (note that not being restricted to alignment with map coordinates means you can often find a rotated rectangle that is smaller than your regular case). This set guarantees that no two positions in it are ever equivalent, unless you are doing really funky warp space stuff (if so it will probably need to be special cased up the ying-yang anyway). On top of this set you can
apply shape filters to produce ellipses, etc.

Now how about the non-orthogonal case? If you warp it a little bit, you could perhaps represent the hexagonal case with two coordinates in two different, non-orthogonal directions. But I haven't given much thought to the math.

Or, to put it another way: in flat-rectangular coordinates, our u and v axes are x and y, and our unit vector has distance 1.

In iso-rectangular coordinates, our u and v axes are at pi/4 and 3/4 * pi, and our unit vector has distance 1/sqrt(2). Some positions are excluded, according to simple well-defined rules.

In flat-hexagonal coordinates, our u and v axes would have to be at 0 and pi/3, with a third dependent axis at 2/3 pi. I have not worked it out any further, but this should get you started :-).
   X
  XXX
  XXX
   X
Wrapping is possible along any of the three axes, but they are not independent (any two implies the third). There are therefore 5 possible choices for wrapping (although the unwrapped and horizontally wrapped cases are indistinguishable from a filtered flat-rectangular topology).

Then we have the pi/4 rotated hexagon:
  XXX
 XXXXX
  XXX
which we're probably not really interested in. Plus we have isometric versions of both, which are only of use to make isometric-view clients _slightly_ better looking.

-------------------------------------------------------------------

After we've considered that, we should consider cases that don't obey the vector-addition rule. Mobius strips, klein bottles, and wrapped triangles may be of little interest to most players, but they're certainly very cool. These don't really have vectors of wrapping at all, and so native coordinates may not be achievable at all in the general case.


I tend to think of the unique set as a normal set, and the real coordinates
as those that are both normal and survive filtering.

For me realness is the condition that guarantees game utility, and normalcy the one that allows utility for topology, storage, etc. or
conversely avoids assert hazards.

Yes.


I suspect that it is a property of wrapping axes in 2-D that they must
be orthogonal. Certainly limiting ones topologies by this constraint will
do much to reduce stress on both game designers and players.
A hexagon does not have orthogonal axes. A hexagon would be a good shape to play on.


Well it depends on what axes you want to grind, but a 2-D hexagonal world has wrapping axes that are. And symmetry operations in these two axial
directions.

For the purposes of doing a Torus world in hex coordinates, you would
choose the appropriate axes, rather than some inappropriate ones.

See above.  A hexagonal map is not the same thing as hexagonal tiles.


If we limit ourselves to axes of wrapping (which both general-topologies and corecleanups do, unfortunately, since otherwise we must normalize vectors just like we normalize map positions), then I can think of only two shapes that will be playable: a rectangle and a hexagon. With these two shapes we can do any one of (1) rotate them to make iso or some other form; (2) take a subset of them, i.e. make certain positions within them unreal; (3) have them wrap in any valid set of the available directions.


You can play quite usefully on a number of flat-earth (unwrapped) maps
of arbitrary shape using filtering techniques.

You can use rectangular wrapping with square, iso and hexagonal tilesets
without too much pain on rectangular maps, there are two flavours of
hex, one with E-W and one with N-S primary axis, while the secondary axis alternately bisects one and separates two tiles.

I don't think there is any useful non-rectangular wrapping shape in 2-D.

I remember someone explicitly requesting the hexagon; it is potentially a more "fair" world shape than a torus.


It might be interesting to see what you could do by limiting oneself to
a local representation of a hexagonal tiled spherical surface. As one
moves out the 2-D projection gets to be a bit funky, but locally one
would probably be fine.

Yes. Unfortunately, since everything is continuous there is no distinction between local and global in game coordinates. But it might be possible to use spherical coordinates or a connected graph of positions to represent a sphere in terms of game coordinates, and use an approximation for the GUI part of it.


If one thinks of this as two hemispherical/hexagon grids touching at the
equator or day/night halves it is probably conceivable without requiring
too much therapy. It would be a strain to think about how a centered
view would move tiles around as you stepped along, but it probably
peels off an edge in one of the six directions of motion and adds it
to the otherside of the hexagon across the axis orthogonal to the motion.

The border (along the equator) isn't clean.


Native coordinates would of course be the rectangle bounding two joined
hexagons with a filter to cut out the non-real positions.

There are an infinity of Great Circles or wrapping coordinates on a sphere, but this is probably limited to the number of hexagons around the equatorial edge with some interesting paths being traced in the process. Wrapping operations would be interesting.

Sounds fun, but it's still a long ways off.


This makes it relatively easy to guarantee a single normal set in native coordinates. With no wrap possibility, unreal conditions are detected by a filter operation, which is also not surprisingly the key test condition for the regular case.


There is another pre-existing format to which we will give the name "linear" or "vector". It is typically only used in a one-way

transformation
handled by map_inx(), though index_to_map_pos() is its reverse.


In standard maps, "standard", "regular", "native" and "linear" usually map to the same memory locations, and linear is just the vector form of the array storage system. Linear coordinates are optimal for storage, and can always be designed to hold exactly one normal set. Printing, wrapping and other global topology operations are not usually optimal in linear coordinates.

Nit: regular isn't a different coordinate system; i.e. opposing native or standard, it's just a different classification of a position.


Nit on nit ... it really is, but it is heavily constrained so it isn't
really that obvious.

Nit on nit on nit: the same definition can be applied to normal and real, but isn't. The point here is that we apply a filter rather than a conversion to determine whether the points are real/regular/normal. You're right that it's all semantics.


The only thing bad about it is that it typically leads to an inefficiency in storage and execution. For an iso-rectangular map this would be about 60%, for a flat-hexagonal map it would be about 30%. The advantage is that it required minimal changes from the current code to implement; we just fixed certain constructs that thought they were operating on normal positions to instead be operating on regular coordinates.


There aren't a lot of changes for either system. Native has close to
zero conceptual change in the basic global elements, and only requires
inserting transformations when you switch coordinates from global to local operations. This is equivalent to looking for places to linearize array
lookups using map_inx() - not rocket science.

Yes. Once the above issues are addressed, I certainly won't be opposed to the introduction of native coordinates. I just think other things have higher priority.


Finally, the corecleanups use native coordinates extensively where they
simplify life. There is no trace of any interfaces with "regular" in them,
but map_std_xsize() and map_std_ysize() return regular dimensions where
the native and standard coordinate axes are not aligned, and various
standard objects are regular sized. There are a number of places where a native_to_map_pos() transformation has been inserted into code, usually where a global iteration is handled in native coordinates, but access is needed to standard map operations. Otherwise code and data structures
outside of the topology functions are relatively untouched.

The generalized-topology alternative uses regular coordinates extensively
rather than native. There is a key data structure that are added to hold standard coordinates, and a number of changes in code to switch from the
map dimensions that are now subsumed by regular to the topology ones.
Global operations are typically unchanged apart from the is_normal
condition test for the spin checks.

Yes. The changes from normal->regular are already in CVS, and what remains is just the tough changes: mapgen, GUI, communication, internals.


To bad you couldn't have finished the topology work, then switched things
to regular coordinates as you suggested above for native, and which in
fact is pretty much the way the corecleanups went except for the last
push.

The topology changes wouldn't have worked without one of the two. The regular system is much simpler, and probably required in the native case as well, so from a code point of view it's a no-brainer. The only issue is the efficiency, but that's not an issue until the work is completed.


That would mean less of the useless grunge would need to be removed from CVS now, or the corecleanups when I had to tidy them up.


There are considerable performance and general game flow differences between the two because of slightly different ways of traversing the global coordinate space.

Optimizations aside, I seriously doubt there is a considerable performance in the general case. This is difficult to measure because of all the optimizations, of course.


Yup, when it is not going to improve efficiency there is no need for
numbers or serious analysis. I'm sure the spin loops are almost noise
even at 2% hit rates :-).

Now that you mention it, yes. Without candy-caning the spin loops will be the least of your worries for such a pathological topology :-).

But to be clear, I mean "average" rather than "general".  My bad.


And from what I've seen, there is very little game flow difference. All of the changes corecleanups introduces with native coordinates are localized; i.e. one section of code converting to native coordinates, doing some work, and (if necessary) converting back.


Except for the global loop order though.

Yes. These changes are localized; i.e. within whole_map_iterate or some other place. Map storage, unfortunately, is not - but I haven't changed that at all; if I did it would be to use index positions.


[...]

It is certainly unsafe in my implementation of general-topologies.


That might be a thought on which to ponder ...

It should go without saying that until native coordinates are implemented they should not be used. This is true of both general-topologies and of current CVS.


And Raimar always says that until used, they cannot be implemented.

How did regular slip through this catch-22 situation to foul up CVS so badly :-)

Partly it all goes away in the compilation; i.e.
# define regular_map_pos_is_normal(x, y) (1)

Also because it was put forth as necessary, rather than just an optimization.


General-topologies is also 70k instead of 800k, and consequently has a good (well, better) chance of being realized in the foreseeable future.

Corecleanups has a lot of stuff besides topology. It has also been
diverging from a lot of the ongoing experimentation hacks.

Yes, I know.  This has both advantages as well as problems.


If we remove the ?? K of regular changes from the topology diffs of
the corecleanup stuff you might be surprised to see what the ratios
are.

Probably about the same.


But corecleanups was touted as a mega-patch when it was the current
size of general-topologies.

So is general-topologies.  I just don't want it to become any more mega :-).


I have taken the opposite approach from that of corecleanups; i.e. making the minimum number of changes necessary to implement a more general system. My opinion is that once the more general system is in place, it will be much easier to justify optimizations like native and/or index positions to make calculations easier. This is why I have implemented neither of them, although at least index positions are necessary to make the code cleaner and more efficient.

Once it is in place there will be a lot of breakage and an incredibly
unwieldy system to ever unscramble. The effort required to do core
cleanups of similar grunge tells me this is not a good way to go. This usually happens with piecemeal development and no concern for global concepts, and no opportunity for real review of what is being done
or where it is leading.

I think the "it" that you're talking about is already in place, and is no worse than the code that preceeded it.

If native coordinates had been implemented before the regular system was developed, things might have gone differently (or maybe not). But since you implemented native coordinates as a reaction to the "regular" system, this was impossible :-).


But I agree, it will open the door to lots of fixup patching :-).

Only a little, I think. And it will be easier to justify the fixups then because they will actually gain something (efficiency).


Ok, I think the squabbling has gone on long enough. Here is what I propose. As I see it, there are just a few pieces of cleanup necessary to implement iso-rectangular maps:

1. find_representative_map_pos/unnormalize_map_pos. We have to agree to something on this. 2. mapgen changes. You had wanted to do this; now is the time IMO. My only request is that there is at least one map generator that is topology-independent, and that the code fall back upon this one if necessary (rather than segfaulting as it will do with no changes). 3. miscellaneous changes. There are just a few of these (like the vnotify_conn_ex thing), and they should (but generally aren't) straightforward. 4. the map overview. This depends on #1, and will probably require extensive discussion. 5. the topology system; i.e. a global topology struct or ID, plus code to transfer it server->client and store it in the savegame, plus capabilities and other necessary backwards-compatibility, plus code for specifying it as pre-game server options. This doesn't depend on any of the above, although it doesn't make sense to introduce it much before we're ready for #6. 6. the iso-rectangular topology itself, implemented as changes to the backend topology functions plus necessary additions to the topology system (i.e. new values for the topology struct/id). This depends on all of the above.

Only #4 has any chance of introducing further regular map coordinates, and I'm sure there will be extensive discussion about that. In the meantime, we can introduce any other desirable changes as well - as I said, I will support a patch that (correctly) provides native coordinates, although there is no use for them yet (it makes more sense IMO to focus on index/linear positions first).

jason



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