1 puntos por GN⁺ 2024-05-20 | Aún no hay comentarios. | Compartir por WhatsApp

Escritura de imprenta

  • El artículo anterior trataba sobre una versión en imprenta de las letras del alfabeto.
  • En resumen, se hizo mediante el siguiente proceso:
    • Escribir código que define los puntos clave de la ruta de cada letra (~10 puntos por letra).
    • Suavizar la ruta usando el algoritmo de curvas de Chaikin.
    • Convertir la ruta en una forma de grosor variable.
    • Dibujar la ruta de la forma usando p5js.
  • Se veía así:
  • Pronto habrá un artículo sobre cómo generar oraciones con este sistema. Suscríbete al boletín para enterarte.
  • Definir las rutas originales de las letras era un trabajo muy manual: había que escribir las posiciones en el código y ajustar los puntos hasta que la letra se viera bien.
  • Al programar la cursiva, simplifiqué este proceso.

Diseño de letras

  • Creé una herramienta para definir y exportar los puntos clave de una ruta, de forma que fuera fácil acceder a ella desde el editor de p5js.
  • Muestra una letra de ejemplo y ofrece un área para diseñar letras nuevas.
  • Los pasos son los siguientes:
    • Hacer clic para colocar los puntos clave de la ruta; se muestra la ruta curva resultante con Chaikin.
    • Presionar p para cambiar al modo de edición.
    • Seleccionar puntos y arrastrarlos hasta su posición.
    • Presionar enter para imprimir la ruta en la consola.
  • Hice de 2 a 3 opciones para cada letra.
  • La ruta resultante se ve así:
    [{x:0.7,y:22.5},{x:8.2,y:18.1},{x:8.9,y:11.2},{x:3.7,y:11.4},{x:1.7,y:18.9},{x:8.4,y:22.4},{x:17.7,y:22.0}]
    
  • Quería usar mi propia letra como guía, así que escribí ejemplos en minúsculas y mayúsculas, cargué la imagen directamente en la herramienta y la calcé.
  • Usé las teclas w/a/s/d para colocar la imagen en la posición correcta, y r/e para ampliar o reducir la imagen.
  • Los números son las coordenadas x y para colocar esa área en la ventana de generación de letras.
  • Después de crear todas las rutas, dibujar las curvas y convertirlas en formas de ancho variable, cada letra se veía así de manera individual.

Convertirlo en cursiva

  • A veces conectar letras es fácil. Basta con pasar directamente de la ruta de puntos clave de una letra a la siguiente y luego aplicar la curva de Chaikin de una sola vez.
  • Pero algunos pares de letras no encajan bien.
  • Por ejemplo, en el par na, el último punto de n está abajo y el primero de a está arriba, así que aparece una ruta que cruza a en diagonal y hace que parezca una e.
  • En el par ti, t termina por encima de la línea base e i empieza en la línea base, lo que crea una cresta poco natural.
  • Para resolver estos problemas, se pueden agregar puntos extra al inicio de a y eliminar los dos últimos puntos de t.
  • Sin embargo, no es posible modificar las letras así en todos los escenarios.
  • Por ejemplo, si a está al principio de una palabra, el punto extra queda en el lugar equivocado, y si va después de una letra como w, aparece una línea que cruza a de otra manera.
  • Si t forma pareja con k, también se deforma.
  • Los puntos de inicio y fin de la ruta de una letra deben variar según su posición respecto de las otras letras.
  • Al principio intenté detectar pares “problemáticos” específicos y escribir reglas para ellos, pero al final opté por agregar números al inicio y al final de cada ruta para indicar lo siguiente:
    • No se conecta con otra letra (0)
    • Se conecta con otra letra alrededor de la línea base (1)
    • Se conecta con otra letra justo por encima de la línea base (2)
    • Se conecta con otra letra alrededor de la altura x (3)
  • Ejemplo:
  • Ahora cada ruta de letra se ve así. Fíjate en los números de un dígito al inicio y al final:
    [0,{x:12.2,y:13.2},{x:13.5,y:11.0},{x:6.2,y:8.4},{x:1.1,y:13.0},{x:1.8,y:19.0},{x:7.0,y:23.4},{x:15.2,y:23.6},{x:18.4,y:22.1},1]
    
  • Probé todos los pares de letras:
  • Aquí se puede ver que tengo varias opciones de ruta para cada letra, y también los cambios que se producen cuando una letra se edita según las letras vecinas.
  • Idealmente me gustaría tener al menos de 5 a 6 opciones de ruta por letra, pero hay que equilibrarlo con el tamaño del archivo.

Generación de palabras

  • Cuando se genera una palabra:
    • Para cada letra se elige una ruta base entre 2 o 3 opciones diferentes.
    • La información sobre el final de la ruta se pasa a las letras vecinas (como distintas opciones de ruta para una misma letra pueden tener diferentes puntos finales, primero hay que elegir todas las rutas de letras).
    • La ruta base se ajusta en respuesta a las letras vecinas. Por ejemplo, si la altura final de la letra anterior es 2, se elimina 1 punto al inicio de esta ruta; o si la altura inicial de la siguiente letra es 1, se agrega un punto extra en una posición específica.
  • La función de ajuste puede ser algo compleja. Por ejemplo, la función para la letra q es la siguiente:
    // ip = ruta
    // pc = información del final de la letra anterior
    // nc = información del inicio de la siguiente letra
    // n = índice de la ruta elegida para esta letra
    adjust: (ip, pc, nc, n) => {
      // agregar una interrupción al final de esta letra con 70% de probabilidad
      if (rand() < 0.7 ) ip.splice(-1, 1, 0);
      // si se eligió [2] para esta ruta entre las 4 opciones
      if (n < 2) {
        // si la letra anterior termina en 3, reemplazar los dos primeros puntos por otro punto
        if (pc == 3) ip.splice(1, 2, {x:10,y:12});
        // de lo contrario, si no es 0, agregar un punto al inicio
        else if (pc > 0) ip.splice(1, 0, {x:10,y:20});
      }
      // si no hay interrupción entre esta letra y la siguiente (0)
      if (nc > 0 && ip[ip.length-1] != 0){
        // reemplazar los dos últimos puntos por otro punto
        ip.splice(-3, 2, {x:16,y:34});
      }
    }
    
  • Pero muchas veces es corta. Por ejemplo, la función para la letra n es la siguiente:
    adjust: (ip, pc, nc) => {
      // si la siguiente letra empieza en 3, generar una interrupción aleatoria o mover el último punto
      if (nc == 3) rand() < 0.3 ? ip.splice(-1, 1, 0) : ip.splice(-2, 1, {x:17,y:23.8});
    }
    
  • Luego se conectan todas las rutas base de las letras. En este proceso se ignoran los 1, 2 y 3 de las rutas, pero cada vez que aparece un 0 se inicia una ruta nueva para generar una interrupción.
  • Después, las rutas se convierten en curvas, luego en formas de ancho variable, y se agrega un poco de vibración usando ruido Perlin; así se ve la escritura cursiva.
  • Pronto habrá un artículo sobre cómo generar esta oración. Suscríbete al boletín para enterarte.
  • Y por diversión, aquí hay una comparación lado a lado entre la letra programada ejecutada con un plóter y la letra real.

¿Cuánto pesa?

  • La clase de letras para imprenta pesaba 9.7kb.
  • La clase de letras cursivas ahora pesa 26.1kb (comprimida).
  • Esta clase es más grande porque incluye varias rutas por letra y funciones para ajustar los puntos. Pero también hay algunas otras formas de ahorro.
  • Creo que todavía se puede reducir más. No soy un mago del code golf, pero tengo algunas ideas.
  • Por ejemplo, actualmente las letras están diseñadas con un tamaño base de fuente de 20 y luego se escalan. Eso significa que muchos puntos están definidos como x: 14.5, pero si cambio el tamaño base a 200 podría definirlos como 145 y eliminar los decimales. Como ese cambio hay que hacerlo con cuidado, lo dejé para mi lista de pendientes.

Cómo usarlo

  • El objetivo principal de esta letra es usarla en los títulos, etiquetas y notas tipo garabato de los diagramas en los que estoy trabajando.
  • Pero también es muy divertido jugar con el texto en sí.
  • Como las rutas están codificadas, en vez de usar una fuente se puede jugar directamente con las rutas. Por ejemplo, mover la posición de las letras o cambiar el grosor de letras individuales.
  • Lo próximo será integrar esta letra en mis diagramas, pero también planeo crear algo centrado en el texto mismo. Es muy bonito y tiene muchísimas posibilidades.

Opinión de GN⁺

  • Este artículo ofrece un ejemplo interesante del proceso de digitalizar la escritura a mano usando JavaScript y p5.js. Puede ser una buena oportunidad para que los ingenieros de software practiquen sus habilidades de programación mediante un proyecto creativo.
  • Se puede aprender cómo aplicar algoritmos matemáticos como el de curvas de Chaikin en proyectos reales. Esto ayuda a profundizar la comprensión de la programación gráfica.
  • También se puede aprender a manejar lógica compleja, como las funciones de ajuste de rutas. Esta es una habilidad importante para mejorar la flexibilidad y escalabilidad del código.
  • El proyecto aborda problemas prácticos como la optimización del tamaño de archivo. Eso es una consideración importante en el desarrollo de software real.
  • Al adoptar esta técnica, hay que tener en cuenta que definir rutas y escribir funciones de ajuste puede tomar mucho tiempo. Sin embargo, el resultado ofrece una forma de expresión de texto muy personalizada y única.

Aún no hay comentarios.

Aún no hay comentarios.