Crónica y retrospectiva de Abredatos 2011

Abredatos 2011 ya ha pasado a la historia y también el glorioso equipo #t27. @jmbeas, @eamodeorubio y yo, @mgryszko estabamos desarrollando una aplicación de gestión de tracks GPS sobre mapas de IGN (como fuente de datos) – TrikTrack. La construimos sobre una librería de integración IGN – Gooogle Maps que desarrollé en marzo.

Disclaimer

Al final se parí un churro de post, a pesar de mantenerlo corto. Aquí puedes ver nuestro producto:

TrikTrack

Si no te gusta mi versión de hechos, echa un vistazo a la retro de @jmbeas: Abredatos 2011: TrikTrack.

Viernes, 6 de mayo

@jmbeas me recoge del metro de Oporto sobre las 20:30. Vamos a casa de @eamodeorubio. Empezamos sin el; el pobre todavía estaba atrapado por la fuerza de gravedad del agujero negro de su curro. Recibimos la bienvenida de @mcberros, la señora esposa de Enrique. Nos instalamos en el salón con portátiles y pizarra (nos ayudará mucho en los siguientes días). Empiezan los tweets de @jmbeas sobre mi presunto fervor religioso que supera incluso los talibanes de ultraderecha. Como XaV1uzz, aprovecho este post para desmentir todo escrito sobre mi.

Empezamos despotricando el backlog, haciendo una micro-incepción. Hago de product owner, @jmbeas se mete en el papel del equipo de desarrollo. Mi visión del producto y prioridades cambian. Quería empezar por pintar el mapa de IGN sobre el ‘lienzo’ de Google Maps y editar el track. Después de la conversación no salen cuatro historias para la primera iteración, cuya finalidad es validar la solución técnica coast to coast – desde la transferencia de un track del GPS, pasando por pintar el track en el mapa de IGN y terminando con el envío del track al servidor y vice versa (servidor – navegador – GPS).

Definimos dos personas: Pepe y María del Carmen, dando honores a la anfitriona que nos cuidará durante el fin de semana. Pepe es un usuario con pocos conocimientos técnicos. Quiere pasar el track del GPS al servidor sin muchas complicaciones. Carmen es una usuaria avanzada – quiere adicionamente editar los tracks – añadir puntos adicionales, borrarlos y moverlos sobre el mapa.

El la primera versión del backlog hubo más historias sobre rutas y waypoints, pero las descartamos por falta de tiempo.

Después de cenar, empezamos a desarrollar la primera funcionalidad – primero pruebas con Jasmine, después el código que las cumple. Conocía ya el framework, pero aprendí como hacer pruebas asíncronas, cuando hay que esperar hasta que se termine alguna ejecución externa (en mi caso transferencia desde el GPS que se hace con Garmin Communicator Plugin API).

Para guardar los tracks en el servidor, vamos a utilizar Grails, para arrancar de manera muy rápida. Gracias a mi nuevo trabajo en Osoco, lo conozco suficientemente para empezar un pequeño proyecto.

Terminamos el día (o la noche) a las tres; por lo menos yo bastante cansado, ya que más allá de las 12 de la noche no soy persona.

Sábado, 7 de mayo

Cuando me levanto, @jmbeas ya está dando a la tecla. Desayunamos y hasta la hora de comer seguimos con las historias coast-to-coast. Terminamos tres antes de chuparnos los dedos con filetones de ternera preparados por @mcberros y @eamodeorubio.

Por la tarde decidimos refactorizar el código – todos tenemos la certeza que la implementación de la última historia será mucho más sencilla si definimos objetos y sus responsabilidades. El código de UI dividimos entre la vista y el controlador. Decidimos mantener el modelo (Track) independiente del modelo de Garmin (que también ofrece la misma clase) y ‘traducirlo’ al Bounded Context de Garmin. La obtención y envío de tracks de/al servidor/GPS encapsulamos en dos Repositories. No sale una estupenda práctica de Domain Driven Design.

A la hora de cenar tenemos todas las historias acabadas más una de bonus, que hizo @eamodeorubio de estrangis – pintar el perfil altimétrico de la ruta con Google Charts API. ¡El gráfico es alucinante!

Al final la parte servidora queda muy restringida – solamente se puede descargar un track colgado y de subir nada. Tenemos Grails ‘por si acaso’, pero de momento es un servidor web ‘on steroids’.

Ahora toca poner todo en producción. @jmbeas prepara la página de inicio que explica el proyecto. A las tres queda todo preparado para el estreno. Ya que me estaba durmiendo sobre el teclado, ya se me escapa el hecho si lanzamos la página por la noche o después de dormir.

Domingo, 8 de mayo

Nos levantamos todavía más tarde. En una mini-reunión de planificación, decidimos poner nuestros esfuerzos en las historias de la parte del cliente. No establecimos una iteración con historias cerradas; cada uno escoge una que más le gusta y ¡manos a la obra!

Me pongo con el borrado de puntos de la ruta. Al principio todo va bien – pinto puntos de la ruta. Después me atasco – resulta que no soy capaz de abrir un bocadillo al pinchar sobre un marcador de Google Maps. Después de un par de horas de intentos llegamos a la conclusión que se trata de un bug en la API de Google Maps. El mismo código funciona con el mapa de carreteras de Google, pero no con la de IGN.

Mientras me peleo con Google, los viejetes hacen posible que se pueda elegir que track descargado del GPS/servidor se puede visualizar.

Después de comer, @eamodeorubio me saca de mi bloqueo – encontramos un workaround y finalmente podemos marcar los puntos del track y borrarlos. Mientras tanto el anfitrión optimiza la generación del perfíl altimétrico que se genera ahora bajo demanda.

@jmbeas afina la página principal y mueve algunos botones al mapa. Ya es bastante tarde; decidimos poner todo en producción y grabamos un video explicatorio (para la gente que no tiene el GPS de Garmin y quiere ver como funciona con el cacharro). Terminamos el concurso con cava y varias copas de vino. Pasada media noche ya estoy en casa, gracias al super-cochecito y el maestro al volante @jmbeas.

Retrospectiva

Agradezco estupenda compañía de Jose y Enrique y la hospitalidad de nuestros anfitriones, Enrique y Carmen. Por primera vez pasé dos días encerrado con dos tíos programando (@eamodeorubio solicitó dos tías el año que viene). Desde el viernes hasta casi el lunes hubo un ambiente de mútuo respeto, trabajo codo a codo y una buena sensación de un avance constante, ya que las historias se cristalizaban.

Lo bueno

  • retrospectivas varias veces al día y pair programming nos salvaban de la pérdida total de foco
  • adaptación
    • el sábado nos inspiramos en Scrum y cerramos la iteración, porque creíamos que era el mejor modo para sacar la primera funcionalidad. Con el scrum backlog cerrado, no concentramos solamente en las cuatro historias y no nos desvíamos (mucho) por las otras.
    • el domingo, ya que la fecha definitiva se acercaba cada vez más, no hubo una lista fija de historias. Entre los tres decidíamos que hacer lo siguiente.
  • puesta a punto común muy a menudo, pero sin frequencia fija – cuando notabamos que habia una necesitad de alinearnos
  • trabajo de comunicación de @jmbeas en Twitter, incluyendo todas las tonterías sobre mi supuesto fanatismo religioso 🙂

Para mejorar

  • más programación en pareja por mi parte. @eamodeorubio y @jmbeas lo hicieron bastante tiempo, pero yo solamente un rato con los dos
  • hacer una incepción más larga y algunos días antes del inicio del concurso, ya que cambia mucho la perspectiva con la que uno ve el producto
  • pintar después algunos bocetos de la interfaz de usuario
  • no quedarnos hasta las tantas de la noche. Para mi las horas nocturnas son de baja productividad (rindes poco y además no te recuperas). Mejor irnos a dormir antes y levantarnos antes
  • apuntar a @mcberros a un curso extendido de costumbres polacas para que nos diese la bienvenida con pan y sal. Puntos adicionales por ofrecer una copa de vodka :))

Y a partir de ahora – buscar las fuentes de datos para el año que viene e ir sacando ideas como las podemos sacar a la luz pública!

Advertisements

How IGN tile servers work?

In my previous blog article I introduced an IGN – Google Maps integration library. In this post I want to explain how IGN map server interface.

IGN ‘chops’ the world into small square tiles 256 x 256 pixel each. The size is equal to Google map tiles. Image format is JPG (Google uses PNG images).

There are 5 tile servers (as for 2011.04.11) – tsN.iberpix.ign.es, where 0 <= N <= 4. The tile URL is composed in the following manner:
http://ts|tile server index|.iberpix.ign.es/tileserver/n=|map type|;z=|UTM zone|;r=|map scale|;i=|tile x coordinate|;j=|tile y coordinate|.jpg

where:

  • tile server index – as commented before
  • map type – topo map identifiers useful for outdoor activities:
    • 1:1,000,000 – mapa_millon
    • 1:200,000 – mapa_mtn200
    • 1:50,000 – mapa_mtn50
    • 1:25,000 – mapa_mtn25
  • UTM zone – just the number, without hemishere designator and latitude band. Mainland Spain range: 29-31, Canary Islands: 27-28
  • map scale – Map scale pixels per meter multiplied by 1000. Must be a power of 2. The highest value that works (according to my checks) is 2048000 (2,048 m/px), the lowest is 1000 (1 m/px)
  • tile x-y coordinates – cartesian coordinates of a tile (in a propietary IGN coordinate system). More on this later in this article

An example of a tile: http://ts0.iberpix.ign.es/tileserver/n=mapa_millon;z=30;r=256000;i=5;j=68.jpg

How to calculate tile (cartesian) coordinates?

IGN uses UTM (Universal Transverse Mercator) coordinate system indirectly to calculate tile (x, y) references.

Flash introduction to UTM – it “flattens” the earth surface into zones (where we assume that the surface is not spherical but flat). To reference an earth point with an UTM coordinate, you need three numbers: UTM zone (reference to the grid rectangle), x and y. x gives you the distance from the central meridian of each zone (“false easting”) in meters. The zone meridian has a fixed (artificial) value of 500,000 (to avoid negative coordinates). y gives you the distance from earth’s equator (in meters too). As you see, using UTM is useful to get a grasp of distances (if point A’s UTM coordinates are (500,000, 2,000,000) and B’s (500,000, 2,001,000) they are 1000 m = 1 km away).

The IGN tile coordinate is based on the UTM coordinate of the lower left pixel and map scale (in meters per pixel). Lower left pixel of the (0, 0) IGN tile corresponds to (0, 0) UTM point. Since each tile has 256 pixels, it represents the world fragment in a scale and UTM coordinate unit is meter, (1, 1) tile’s lower left pixel corresponds to:

(1 * 256 [px] * scale [m/px], 1 * 256 [px] * scale [m/px]) UTM point.

e.g. for 128 m/px scale, (1, 1) tile’s lower left pixel UTM is (32768, 32768).

generalizing, for given a (i, j) tile and scale, lower left pixel UTM is:

(i * 256 [px] * scale [m/px], j * 256 [px] * scale [m/px])

To calculate tile IGN coordinates (given a tile scale) that cover a point with given UTM coordinates:
(floor(x / (256 [px] * scale [m/px])), floor(y / (256 [px] * scale [m/px])))

Notice that x UTM coordinates can be negative and thus tile coordinates. UTM (-1, 4000000) point (lat-lng: 36.01619ºN, 8.54615ºW) in the 30N zone is legal, although it lies outside of the zone (which spans from 6ºW to 0º). It’s supported by the IGN tile server – it can return tiles covering areas outside of an UTM zone, although with higher projection errors.

IGN – Google Maps integration library

What is IGN?

IGN stands for Instituto Geográfico Nacional (National Institute of Geography), a public institution in Spain. Its functions include maintaining spatial data and to producing topographical maps of the country.

What maps does the IGN offer (that are interesting for outdoor activities)?

  • topo maps in 1:1,000,000, 1:200,000 y 1:50,000 and 1:25,000 scales
  • satellite imagery from Landsat 7 and SPOT 5 satellites
  • PNOA aerial imagery (PNOA – Plan Nacional de Ortofotografía Aérea, National Plan of Aerial Orthophotography)

How can I get the maps?

You can see rendering differences between SigPac and Iberpix on the picture below:

Why another viewer?

My idea was to display IGN map tiles on Google Maps canvas by implementing a custom (Google Maps) map type. In this way I can use Google Maps API to draw waypoints, paths, etc. If you mix it with Garmin Communicator Plugin API, you get a full-blown outdoor trip planning tool like Garmin MapSource, written entirely in JavaScript. Ok, there are maps of Spain for Garmin devices (Garmin’s Topo Spain, free Topo Hispania), but they IGN maps are more vivid and differentiate better between paths, tracks and forest roads.

What is IGN-Google Maps integration library?

Currently, it is not a full-feature viewer. The library offers a custom google.maps.ImageMapType, consisting of a google.maps.Projection and google.maps.ImageMapTypeOptions

I took a different approach than taken e.g. by Wikiloc. I didn’t want to make the IGN tile layer interchangeable with maps offered by Google. It means that for a given zoom or scale, you cannot switch between a Google map and IGN map and get the same view. This is possible in Wikiloc, but at expense of correct visualization and smooth zooming. I wanted just to have an independent IGN map viewer implemented in Javascript (ok, you depend now on Google Maps API that is closed source).

The source code has a comprehensive test suite implemented with Jasmine. Doing BDD on a broader scale and in Javascript was a completely new experience for me. With Jasmin it makes fun – the library is intuitive to use and well documented. As a bonus you get a mocking framework – no extra libraries required.

There are some TODOs in the project (they are described in README.md). On the next days I’ll try to fix them, depending on my spare time.

Where can I get the library?

I just published the very first version on the Github: https://github.com/mgryszko/ign-gmaps. The API is not stable yet and may change in the future.

How is it licenced?

MIT licence. You are free “to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software” = fork it and hack on it.

What are next steps?

I’d like to use it in Abredatos 2011 contest. Abredatos is a 48-hour programming challenge. You are supposed to developed a working application making use of at least one Spanish public datasource. It will be held on May 7th-8th 2011.

My idea is to develop the previously mentioned track & route manager with IGN maps and Garmin integration. If you want to participate, drop me an email/tweet.