Una línea se dibuja eligiendo píxeles
Dibujar una línea en píxeles es elegir, para cada columna, la fila que queda más cerca de la recta ideal. Con ese cálculo sencillo puedes unir dos puntos cualesquiera de una pantalla.
Así se pinta el trazo de una aplicación de dibujo o la ruta de un plano del metro.
Al final de esta lección
Nota
Puedo colocar píxeles en una cuadrícula y dibujar una línea entre dos puntos.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Coordenadas | el par (x, y) que da la columna y la fila de un píxel | (3, 1) |
| Origen | el punto (0, 0), arriba a la izquierda | |
| Pendiente | cuánto baja la línea por cada paso a la derecha | |
| Redondear | elegir el número entero más cercano | |
| Rasterizar | convertir una forma en píxeles encendidos |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Cada píxel tiene dos coordenadas
Un píxel se nombra con dos números: la columna x y la fila y. Se empieza a contar en 0 desde la esquina de arriba a la izquierda.
La x crece hacia la derecha y la y crece hacia abajo. Un segmento de (0, 0) a (10, 4) baja cuatro filas mientras avanza diez columnas.
Ejemplo resuelto: una línea de 11 píxeles
| Columna x | Línea ideal: 0,4 por x | Se suma 0,5 | Fila elegida y |
|---|---|---|---|
| 0 | 0 | 0,5 | 0 |
| 1 | 0,4 | 0,9 | 0 |
| 2 | 0,8 | 1,3 | 1 |
| 3 | 1,2 | 1,7 | 1 |
| 4 | 1,6 | 2,1 | 2 |
| 5 | 2 | 2,5 | 2 |
| 6 | 2,4 | 2,9 | 2 |
| 7 | 2,8 | 3,3 | 3 |
| 8 | 3,2 | 3,7 | 3 |
| 9 | 3,6 | 4,1 | 4 |
| 10 | 4 | 4,5 | 4 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Una línea se dibuja avanzando columna a columna
El método es corto. Recorres cada columna x desde el primer punto hasta el último. Para cada una calculas la fila que corresponde a la recta y la redondeas.
Cada pareja (x, y) es un píxel que hay que encender. Este método sirve cuando la línea es más ancha que alta.
Calcula los píxeles de la línea
docker exec jupyter python3 -c "print([(x, (8 * x + 10) // 20) for x in range(11)])"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Qué imprime la lista de píxeles
Imprime once parejas, de (0, 0) a (10, 4). La fila 2 se repite tres veces, en las columnas 4, 5 y 6, y la fila 0 solo dos.
Es la tabla de arriba, calculada por Python. Una línea dibujada en píxeles tiene escalones, y los escalones se ven más cuanto más grande es cada píxel.
Mira la línea como un dibujo de texto
docker exec jupyter python3 -c "print('\n'.join(''.join('#' if (8 * x + 10) // 20 == y else '.' for x in range(11)) for y in range(5)))"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Cómo se lee el dibujo de texto
Imprime cinco filas de once signos. Cada # es un píxel encendido y cada punto uno apagado. Las filas salen así:
##........., ..##......., ....###...., .......##.. y .........##.
Se ve una escalera que baja hacia la derecha, con tres píxeles seguidos en la fila del medio.
Cambia la pendiente de la línea
# Una línea de (2, 1) a (12, 6): 10 pasos a la derecha y 5 hacia abajo.
x0 = 2
y0 = 1
dx = 10
dy = 5
for i in range(dx + 1):
x = x0 + i
y = y0 + (2 * dy * i + dx) // (2 * dx)
print(x, y)
# Cambia dy a 10 y mira cómo la línea baja un píxel por paso.
Con números enteros no hay dudas al redondear
En el código no se suma 0,5 y se corta. Se usan enteros: y0 + (2 * dy * i + dx) // (2 * dx). Es la misma cuenta, multiplicada por 2 · dx.
Así no aparecen decimales como 0,49999999 que cambiarían un píxel. Los gráficos por computador usan enteros siempre que pueden.
Un error muy común
Advertencia
Mucha gente cree que la y crece hacia arriba, como en una gráfica de clase. En una pantalla el origen está arriba a la izquierda y la y crece hacia abajo. Por eso una línea que «sube» en tu cuaderno baja en la pantalla.
Guarda la línea como imagen
docker exec jupyter python3 -c "from PIL import Image; im = Image.new('L', (11, 5), 255); [im.putpixel((x, (8 * x + 10) // 20), 0) for x in range(11)]; im.resize((220, 100), Image.NEAREST).save('linea.png'); print(im.getpixel((5, 2)), im.getpixel((5, 3)))"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Para ir más lejos: abre tu propia línea
El tercer comando del laboratorio guarda un archivo linea.png con la línea de (0, 0) a (10, 4). Ábrelo en JupyterLab desde la carpeta de trabajo.
Verás una escalera de cuadros negros sobre blanco, de arriba a la izquierda a abajo a la derecha. ¿Qué pasaría con una línea casi vertical? Piensa qué eje recorrerías.