lunes, octubre 22, 2012

La Confusión de la Tortuga

Quiero compartir una muy buena noticia, la traducción al español del libro “Turtle Confusion” de Barry Newell. Este libro plantea en el diálogo entre una tortuga y un docente, una colección de problemas a resolver, pero tambien comentarios acerca de como plantear estos problemas para que sean de utilidad a los alumnos. La versión original fué puesta por el autor bajo dominio público y autorizó su traduccion, que fué hecha por Melina Lucía Coronel y revisada y editada por Manuel Kaufmann, la imagen de la tapa es de Manuel Quiñones.
Esto no termina aqui, alentado por la repercusión, Barry ha decidido escribir una guia para docentes, con pistas acerca de los acertijos que en forma de poemas se incluyen en cada capítulo. Además Melina ya ha comenzado la traducción de otro libre del mismo autor: "Turtles Speak Mathematics".
Es interesante mencionar que Barry Newell es astrónomo y docente y vive en Australia, y Melina Lucía Coronel es Profesora de Inglés, y vive en Entre Ríos, Argentina, por lo que se trata de una colaboración intercontinental.... La magia de internet. También es interesante ver el desarrollo del proyecto, ya que se llevó a cabo completamente en github.
Pueden leer el libro on line o descargarlo, y también usar la actividad TurtleConfusion en Sugar


Me gusta mucho uno de los comentarios del autor acerca de como usar el cuadernillo:
"Se intenta que el material en éste cuadernillo sea de alguna manera confuso a primera vista. En la vida real, no podemos evitar sentirnos confundidos de vez en cuando. Éste sentimiento de confusión nos indica que nuestro entendimiento de una situación en particular es inadecuada... En otras palabras, la confusión representa una oportunidad para aprender.
Los adultos deberían reconocer el peligro que existe en proteger a los jóvenes de los sentimientos de confusión. La vida no nos ofrece sus problemas en una secuencia de paquetitos cuidadosamente graduada, cada una de los cuales se puede resolver por el ‘alumno promedio’ en una hora de clase. Se lo debemos a nuestros alumnos, a la posibilidad de sentirse confundidos a veces; a permitirles aprender de lidiar con, y hasta beneficiarse de, la confusión; a permitirles desarrollar respuestas, en lugar de entrar en pánico, frente a situaciones en las que pueden sentirse inicialmente sobrepasados."

Pequeñas lecciones aprendidas usando Cairo (1)

Portando actividades de gtk2 a gtk3 aprendimos algunos trucos relacionados con Cairo.
Voy a compartir algunos básicos en este post, y luego algunas cosas que hemos aprendido con respecto a la pérformance, que no son del todo obvias o no son muy sencillas de encontrar.

En primer lugar un ejemplo bien sencillo de la mínima aplicacion para mostrar algo usando cairo en gtk2 y gtk3:

#!/usr/bin/python

import gtk

class MinimalCairoTest(gtk.Window):

    def __init__(self):
        super(MinimalCairoTest, self).__init__()
        self.set_size_request(400, 400)
        self.connect("destroy", gtk.main_quit)
        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.__expose_cb)
        self.add(darea)
        self.show_all()

    def __expose_cb(self, widget, event):
        cr = widget.window.cairo_create()
        cr.set_source_rgb(1.0, 0.0, 0.0)
        cr.rectangle(20, 20, 120, 80)
        cr.fill()


MinimalCairoTest()
gtk.main()


El mismo código usando Gtk3:

#!/usr/bin/python

from gi.repository import Gtk

class MinimalCairoTest(Gtk.Window):

    def __init__(self):
        super(MinimalCairoTest, self).__init__()
        self.set_size_request(400, 400)
        self.connect("destroy", Gtk.main_quit)
        darea = Gtk.DrawingArea()
        darea.connect("draw", self.__draw_cb)
        self.add(darea)
        self.show_all()

    def __draw_cb(self, widget, cr):
        cr.set_source_rgb(1.0, 0.0, 0.0)
        cr.rectangle(20, 20, 120, 80)
        cr.fill()


MinimalCairoTest()
Gtk.main()

Como podemos ver, el cambio más importante es que el "expose-event" es reemplazado por un evento "draw" que ya nos provee un contexto de cairo, en este caso, es el parámetro cr.

Lo que veremos en pantalla es simplemente:

No muy interesante, pero nos sirve de base para seguir avanzando.

Si queremos mostrar una imagen centrada en la pantalla podemos hacer:

#!/usr/bin/python

from gi.repository import Gtk
import cairo

png_test_file = '/usr/share/icons/gnome/256x256/emotes/face-cool.png'

class MinimalCairoTest(Gtk.Window):

    def __init__(self):
        super(MinimalCairoTest, self).__init__()
        self.set_size_request(400, 400)
        self.connect("destroy", Gtk.main_quit)
        # read the png file and create a surface
        self._im_surface = cairo.ImageSurface.create_from_png(png_test_file)
        
        darea = Gtk.DrawingArea()
        darea.connect("draw", self.__draw_cb)
        self.add(darea)
        self.show_all()

    def __draw_cb(self, widget, cr):
        # get window width & heigth
        win_width = self.get_allocation().width
        win_height = self.get_allocation().height
        # show the image centered
        cr.translate((win_width - self._im_surface.get_width()) / 2,
                (win_height - self._im_surface.get_height()) / 2)
        cr.set_source_surface(self._im_surface)
        cr.paint()


MinimalCairoTest()
Gtk.main()

Y veremos:


Lo primero a tener en cuenta, es que aun usando los bindings dinámicos para Gtk3, los bindings dinámicos para Cairo no estan listos por eso hacemos "import cairo" y no "from gi.repository import Cairo"

En el último ejemplo de este post, vamos a aplicar una transformación simple, para mostrar la imagen a la mitad de su tamaño (copio solo el metodo __draw_cb, ya que el resto es igual)

     def __draw_cb(self, widget, cr):
        # get window width & heigth
        win_width = self.get_allocation().width
        win_height = self.get_allocation().height
        # show the image centered
        scale = 0.5
        image_width = self._im_surface.get_width() * scale
        image_height = self._im_surface.get_height() * scale
        cr.translate((win_width - image_width) / 2,
                (win_height - image_height) / 2)
        cr.scale(scale, scale)
        cr.set_source_surface(self._im_surface)
        cr.paint()

En este caso veremos:

Lo interesante es ver que pasa si cambiamos el orden en las operaciones de cairo efectuadas (translate, scale, set_surface, paint).

Si hacemos el scale despues del set_surface:

        cr.translate((win_width - image_width) / 2,
                (win_height - image_height) / 2)
        cr.set_source_surface(self._im_surface)
        cr.scale(scale, scale)
        cr.paint()

La imagen es transladada correctamente, pero no se escala:

Y si hacemos el scale antes del translate:

        cr.scale(scale, scale)
        cr.translate((win_width - image_width) / 2,
                (win_height - image_height) / 2)
        cr.set_source_surface(self._im_surface)
        cr.paint()

La escala afecta al translate, por lo que se translada menos de lo que debería:

Este caso es sencillo, porque hay una sola transformación efectuada, pero por ejemplo cuando hay escalados y rotaciones, se complica un poco más, y hay que tener bien en cuenta el orden en el que se aplican las transformaciones.
En un próximo post voy a escribir acerca de algunos puntos para lograr buena performance usando Cairo.