timhutton / geofun

Exploring location-based fun
2 stars 0 forks source link

Tile painting #2

Closed timhutton closed 7 years ago

timhutton commented 7 years ago

The world is divided into squares e.g. 30m x 30m, or other shapes. Users can set the color of the tile they are in, making a picture.

A bit like /r/place but on a large physical scale.

rawles commented 7 years ago

This is a good example of a game we could easily make.

We can do it with the current interface. The map gains a paintbrush or paintpot icon, showing the state of the grid square they're in (black, white or unassigned). By clicking it, their current 0.1x0.1 degree centicule flips colour. We can then plot the pixel art on a webpage, ideally in a nice animation to show how the design evolved over time. At zoom levels which cover a lot of area, we can also plot it as a map overlay. Graticules (1x1) or decicules (0.01x0.01) might work better.

The information going to the server (the 'put') is an approximate latitude and longitude (the server decided the assigned colour). The state of the game is a rectangular grid of pixels (though hex pixels would be cooler!), either black or white or unassigned. The information coming from the server (the 'get') would be both (a) the current colour of the user's square given their approximate location and (b) a set of grid squares, optionally limited by bounding box. The information that is logged is the colour of the grid squares. No user identity is needed for this game.

Is this 'fun and private'?

timhutton commented 7 years ago

"plot the pixel art on a webpage" - Leaflet supports drawing semi-transparent polygons from lat,lng coords, so all the drawing stays in the same interface, and is rendered over the map. Of course we could render the data separately too if we wanted.

User chooses the color, surely? No need to limit to black/white, other than coding simplicity.

Otherwise, sounds great! It's pretty private and certainly non-zero fun.

rawles commented 7 years ago

Leaflet is really cool. I guess for plotting it on a webpage I had the idea of have an animated globe, but we wouldn't need to do that for a while.

My idea for black and white was because it would be just one button on the map, and pressing it once might mean 'change colour'. Are you thinking of having a set of buttons each of a different colour? Black and white pixel art often looks nice because of its simplicity, but there's no need at all to limit it to that, as you say.

rawles commented 7 years ago

Thinking about it, your suggestion is much simpler and therefore better. The reason is that the client doesn't need to know the current state of the grid cell before making the flip, and updates to the state of the game can be atomic.

timhutton commented 7 years ago

What are the packets? Something like the below? Send to server: [lat,lng,color] when the user wants to change the color of a pixel. Send to server: [lat,lng,lat,lng] bounding box when the user wants to be able to draw the pixels. Get from server: [[lat,lng,color],..] showing the colors in the requested bounding box. Where lat,lng are decimal coords abbreviated to the size of the graticule we decide on.

rawles commented 7 years ago

Precisely this. It should be available in an hour or two.

timhutton commented 7 years ago

How are you thinking of storing the data?

rawles commented 7 years ago

It's going into a database table with four fields, the timestamp, the latcell, the longcell, and the colour. latcell is floor(10*latitude), and longcell similarly. We do this because it's not good to have a float as a primary key in a database table. The colour is an integer, any integer. These are converted on-the-fly to latitude and longitude for use by the client. Particularly, the get-call returns bounding boxes, because we might want to change the size of the boxes later.

Does this sound sensible to you?

timhutton commented 7 years ago

So the tiles are decicules? 0.1°x0.1°? How big is that around here?

rawles commented 7 years ago

They are 0.1x0.1 degree boxes. Go to http://wiki.xkcd.com/geohashing/Cambridge,_United_Kingdom and imagine the graticule divided into 10x10 boxes.

timhutton commented 7 years ago

Thanks! That's too big I think. I think we need centicules or smaller.

rawles commented 7 years ago

Yeah, I wasn't sure if the 'canvas' was, for example, the whole UK, or a city, or whatever. If we enforce the use of bounding boxes on queries to the paint endpoint, we can have it pretty fine-grained. Is that easy from your end?

To be more concrete, the box defined by (52.185 < lat < 52.215) and ( 0.1 < long < 0.15 ) is a good 'playground' for playtesting. If we wanted to draw a 10x10 picture on this box we could do it by having 0.003 x 0.005 cells, for example. If the game were to collaboratively draw pixel art over the whole of the UK, with people only able to change their own cell or neighbouring ones, then 0.1x0.1 is a better choice.

Perhaps for testing we should have it pretty fine grained.

If it is too fine-grained, it begins to get less private.

rawles commented 7 years ago

Proposal: for this test, each graticle is a 500x500 grid, that is, 0.002x0.002 cells. We can then review for the 'public game'.

timhutton commented 7 years ago

How big are those, roughly?

Does the data structure require the limits? Surely the table only stores those entries that have been given a color?

rawles commented 7 years ago

The lawn of the Fitzwilliam Museum is at latitude 52.20 and longitude 0.12.

In[3]:= GeoDistance[{52.20 - 0.001, 0.12}, {52.20 + 0.001, 0.12}, UnitSystem -> "Metric"] Out[3]= Quantity[222.542, "Meters"] In[4]:= GeoDistance[{52.20, 0.12 - 0.001}, {52.20, 0.12 + 0.001}, UnitSystem -> "Metric"] Out[4]= Quantity[136.743, "Meters"]

So, a box of 223m north-south, and 137m east-west.

The data structure works as you describe and doesn't require these limits.

rawles commented 7 years ago

The API is now ready for testing, with 1/500 tiles.

/paint/get: returns the tiles within (and which overlap) a specified bounding box. Required parameters: latitude_min, latitude_max, longitude_min, longitude_max. The response will be latitude_min, latitude_max, longitude_min, longitude_max, colour, one per line, describing the boxes which make up the current design. There is no limit to the size of the bounding box.

/paint/put: sets a tile with a colour. Required parameters: latitude, longitude, accuracy, colour. Accuracy is ignored for now. Simply reponds 'done.'

timhutton commented 7 years ago

Can we make them a bit more square? Vertically-elongated pixels won't generate enough love.

Why send a box in the response? Could be just the center, to save bandwidth.

Is color a 6-character hex string?

rawles commented 7 years ago

Do you want them to be square anywhere in the world or just in Cambridge? If anywhere in the world, we'd need to either (a) write some code on the server to compute the size (in metres) of a square box at the user's latitude and longitude or (b) to made a dependency on the client to do the same and directly send the cell number. If we want them to be square only in Cambridge, we can easily do that by making them, for example 200m square boxes using the meters-per-degree ratio in Cambridge.

Making it square everywhere is tricky - how do you tile a sphere with a set of square tiles such that they don't overlap and that there's a simple function to identify each tile from the latitude and longitude?

The response has a box because we might want to change the resolution of the game later and I didn't want to have an unnecessary dependency on that in the client.

Colour is an integer.

timhutton commented 7 years ago

Yes, OK, let's try it with the box size you have implemented.

The client already needs to know the grid resolution for deciding which tile the user is currently in, to be able to send reduced-accuracy coordinates. So best to save bandwidth and not send a box for every tile I would suggest.

For color, can we use a six character hex string please? It is standard on the web and saves having to think about mapping integers to colors.

rawles commented 7 years ago

I can change it so the boxes look square in Cambridge easily, so I'll do that.

At the moment, the client doesn't decide which tile the user is currently in - it just sends a latitude and longitude to the server and the server decides. The tile grid is abstracted away in case we want to change its properties.

We can reverse that by having the client decide the tile and tell the server, but then the server won't know the location of the tiles, so we won't be able to log the colour changes in a plottable way unless we coordinate the properties between the client and server, which is unnecessary work for us. However, we can just send the tile numbers and colours, and save bandwidth, though I think the bandwidth saving isn't worth it. Furthermore, imagine we change the resolution of the game, and choose a different tile size. Since the tile identifiers have changed, we'd have to delete the original design, whereas before we wouldn't.

I'll change the colour to a six character hex string.

rawles commented 7 years ago

I'm adapting it to be 'square in Cambridge', with a square size of 200m, so that's approximately 1/556 degrees north-south and 1/342 degrees east-west.

timhutton commented 7 years ago

In the packets thought above the client decides which tile the user is currently in, by abbreviating their location coordinates to N decimal places. This is fantastic for privacy because we're not even sending high-accuracy location data.

The idea was that the server can just use that abbreviated form (multiplied by 10^N to make into an integer) for the table entries.

This scheme doesn't let us choose the shape of the tile but maybe that's fine. Both server and client know the value of N (probably N=4 or N=3).

rawles commented 7 years ago

Ah okay, sorry, I misunderstood. So, this is already totally compatible with what we have on the server! Any approximate position will be in the same tile as the accurate position.

Since we want to make the tiles square, I suggest the best reduced-accuracy location the client can send is in the centre of the tile as the server understands it. So:

sent latitude = (floor(556 latitude) + 0.5)/556 sent longitude = (floor(342 longitude) + 0.5)/342

Note that you should use floor and not just truncate the fractional part, because either the latitude or longitude might be negative.

timhutton commented 7 years ago

Sounds good. So now the server can send on request the tile center exactly as stored, together with a color, as a triple? I'm thinking bandwidth is important here because if the user zooms out they might get sent a lot of tiles. (We'll likely have to limit the amount that can be sent, in any case.)

rawles commented 7 years ago

No problem. I'll change things now so that /paint/get is called /paint/get/boxes and there'll be a new endpoint called /paint/get/centres which works as you describe.

rawles commented 7 years ago

Okay, that's ready. You specify the bounding box in the same way. Where you define the interface above, I assume you don't mean by '[lat,lng,color]' that you're sending a square brackets delimited string to the server. This data is sent in the same way as for /insert.

timhutton commented 7 years ago

I get the feeling you want /paint/get/boxes for something?

Square brackets not needed. Only a delimiter for when sending a list of tiles.

rawles commented 7 years ago

Only that I had already written it, and didn't see any reason to delete it immediately.

I thought you'd only be sending a request to change the colour of one tile at a time, if for no other reason that you can't be in more than one tile at once.

timhutton commented 7 years ago

Sorry, I meant for when the server sends the list of tiles.

Communication is hard.

rawles commented 7 years ago

It's a CSV file, like you get when you call /data.

Yes, using GitHub to communicate during a hacking session is excruciatingly slow and prone to misunderstanding.

rawles commented 7 years ago

It seems to work. I added a lime-green tile at the corner of our home graticule:

52.000899,0.001462,D2F135

timhutton commented 7 years ago

https://geofun.org.uk/paint/get/centres ? Seems empty at the moment.

rawles commented 7 years ago

Did you specify a bounding box (parameters latitude_min, latitude_max, longitude_min, longitude_max)?

https://geofun.org.uk/paint/get/centres?latitude_min=51&latitude_max=53&longitude_min=-1&longitude_max=1

timhutton commented 7 years ago

Still lots of work to do but a basic version of this is now implemented.