1 points par GN⁺ 2024-05-20 | Aucun commentaire pour le moment. | Partager sur WhatsApp

Écriture bâton

  • L’article précédent portait sur une version alphabet en lettres bâton.
  • En résumé, cela a été réalisé avec le processus suivant :
    • Écrire du code qui définit les points clés du tracé de chaque lettre (environ 10 points par lettre).
    • Lisser les tracés avec l’algorithme de courbe de Chaikin.
    • Convertir les tracés en formes à épaisseur variable.
    • Dessiner les contours de forme avec p5js.
  • Voici à quoi cela ressemblait :
  • Un article expliquant comment générer des phrases avec ce système sera bientôt publié. Inscrivez-vous à la newsletter pour être tenu au courant.
  • À l’origine, définir le tracé des lettres consistait en un travail très manuel : écrire les positions dans le code puis ajuster les points jusqu’à ce que la lettre ait le bon rendu.
  • Pour coder une écriture cursive, ce processus a été simplifié.

Conception des lettres

  • Un outil a été créé pour définir et afficher les points clés des tracés, afin qu’ils soient facilement accessibles dans l’éditeur p5js.
  • Il affiche une lettre d’exemple et fournit une zone pour concevoir une nouvelle lettre.
  • Étapes suivantes :
    • Cliquer pour placer les points clés du tracé — le tracé résultant avec la courbe de Chaikin s’affiche.
    • Appuyer sur p pour passer en mode édition.
    • Sélectionner un point et le faire glisser à l’emplacement voulu.
    • Appuyer sur enter pour afficher le tracé dans la console.
  • 2 à 3 variantes ont été créées pour chaque lettre.
  • Le tracé obtenu ressemble à ceci :
    [{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}]
    
  • Comme l’objectif était d’utiliser sa propre écriture comme guide, des exemples en minuscules et en majuscules ont été écrits, puis l’image a été chargée directement dans l’outil pour être retracée.
  • Les touches w/a/s/d servent à placer l’image correctement, et r/e à l’agrandir ou la réduire.
  • Les nombres correspondent aux coordonnées x y pour positionner cette zone dans la fenêtre de génération des lettres.
  • Une fois tous les tracés créés, les courbes dessinées puis converties en formes à largeur variable, chaque lettre prise individuellement ressemblait à ceci.

Mise en cursive

  • Parfois, relier les lettres est simple. Il suffit de passer directement du tracé des points clés d’une lettre au suivant, puis d’appliquer la courbe de Chaikin sur l’ensemble.
  • Mais certaines paires de lettres s’assemblent mal.
  • Par exemple, dans la paire na, le dernier point de n est bas et le premier point de a est haut, ce qui crée un tracé qui traverse a en diagonale et le fait ressembler à un e.
  • Dans la paire ti, t se termine au-dessus de la ligne de base et i commence sur la ligne de base, ce qui produit une arête peu naturelle.
  • Pour résoudre ce type de problème, il est possible d’ajouter un point supplémentaire au début de a et de supprimer les deux derniers points de t.
  • Mais on ne peut pas modifier les lettres de cette façon dans tous les cas.
  • Par exemple, si a est au début d’un mot, ce point supplémentaire se retrouve au mauvais endroit, et si a suit une lettre comme w, cela crée une ligne qui traverse a autrement.
  • Si t est associé à k, il se déforme.
  • Les points de début et de fin du tracé d’une lettre doivent varier selon la position des lettres voisines.
  • Au départ, l’idée était de repérer certaines paires « problématiques » et d’écrire des règles pour elles, mais finalement des nombres ont été ajoutés au début et à la fin de chaque tracé pour indiquer :
    • aucune liaison avec une autre lettre (0)
    • liaison avec une autre lettre autour de la ligne de base (1)
    • liaison avec une autre lettre juste au-dessus de la ligne de base (2)
    • liaison avec une autre lettre autour de la hauteur d’x (3)
  • Exemple :
  • Chaque tracé de lettre ressemble désormais à ceci. Notez les chiffres à un seul caractère au début et à la fin :
    [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]
    
  • Toutes les paires de lettres ont été testées :
  • On voit ici plusieurs variantes de tracé pour chaque lettre, ainsi que les modifications provoquées par les lettres adjacentes.
  • Idéalement, il y aurait au moins 5 à 6 variantes de tracé par lettre, mais il faut trouver un équilibre avec la taille du fichier.

Génération des mots

  • Lorsqu’un mot est généré :
    • un tracé de base est choisi pour chaque lettre parmi 2 à 3 variantes ;
    • les informations sur l’extrémité du tracé sont transmises aux lettres adjacentes (comme les autres variantes d’une même lettre peuvent avoir des extrémités différentes, tous les tracés doivent d’abord être sélectionnés) ;
    • le tracé de base est ensuite ajusté en réaction aux lettres voisines. Par exemple, si la hauteur de fin de la lettre précédente vaut 2, on retire 1 point au début de ce tracé, ou si la hauteur de départ de la lettre suivante vaut 1, on ajoute un point supplémentaire à un emplacement précis.
  • La fonction d’ajustement peut être un peu complexe. Par exemple, celle de la lettre q ressemble à ceci :
    // ip = tracé
    // pc = information de fin de la lettre précédente
    // nc = information de début de la lettre suivante
    // n = index du tracé sélectionné pour cette lettre
    adjust: (ip, pc, nc, n) => {
      // ajouter une interruption à la fin de cette lettre avec une probabilité de 70 %
      if (rand() < 0.7 ) ip.splice(-1, 1, 0);
      // si [2] parmi les 4 options a été sélectionnée pour ce tracé
      if (n < 2) {
        // si la lettre précédente se termine à 3, remplacer les deux premiers points par un autre point
        if (pc == 3) ip.splice(1, 2, {x:10,y:12});
        // sinon, si ce n’est pas 0, ajouter un point au début
        else if (pc > 0) ip.splice(1, 0, {x:10,y:20});
      }
      // s’il n’y a pas d’interruption entre cette lettre et la suivante (0)
      if (nc > 0 && ip[ip.length-1] != 0){
        // remplacer les deux derniers points par un autre point
        ip.splice(-3, 2, {x:16,y:34});
      }
    }
    
  • Mais elle est souvent plus courte. Par exemple, celle de la lettre n est la suivante :
    adjust: (ip, pc, nc) => {
      // si la lettre suivante commence à 3, créer aléatoirement une interruption ou déplacer le dernier point
      if (nc == 3) rand() < 0.3 ? ip.splice(-1, 1, 0) : ip.splice(-2, 1, {x:17,y:23.8});
    }
    
  • Ensuite, tous les tracés de base des lettres sont reliés entre eux. Lors de cette étape, les 1, 2 et 3 du tracé sont ignorés, mais chaque fois qu’un 0 apparaît, un nouveau tracé commence afin de créer une interruption.
  • Le tracé est ensuite courbé, converti en forme à largeur variable, puis un léger tremblement est ajouté avec du bruit de Perlin ; l’écriture cursive obtenue ressemble alors à ceci.
  • Un article expliquant comment générer cette phrase sera bientôt publié. Inscrivez-vous à la newsletter pour être tenu au courant.
  • Pour le plaisir, voici une comparaison côte à côte entre l’écriture codée exécutée via un traceur et l’écriture manuscrite réelle.

Quel poids ?

  • La classe de lettres pour l’écriture bâton pesait 9,7 kb.
  • La classe de lettres cursives pèse actuellement 26,1 kb (après compression).
  • Cette classe est plus volumineuse, car elle contient plusieurs tracés par lettre ainsi que des fonctions qui ajustent les points. Mais d’autres pistes d’optimisation existent aussi.
  • Il semble possible de réduire encore davantage. Je ne suis pas un magicien du code golf, mais j’ai quelques idées.
  • Par exemple, les lettres sont actuellement conçues sur la base d’une taille de police par défaut de 20, puis redimensionnées. Cela signifie que beaucoup de points sont définis comme x: 14.5, mais si la taille de base passait à 200, les points pourraient être définis comme 145 et les décimales supprimées. Comme ce changement doit être fait avec soin, il reste sur la liste pour plus tard.

Utilisation

  • Le but principal de cette écriture est de servir pour les titres, les étiquettes et les notes griffonnées dans les diagrammes sur lesquels je travaille.
  • Mais il est aussi très amusant de jouer avec le texte lui-même.
  • Comme les tracés sont encodés, il est possible de jouer directement avec eux au lieu d’utiliser une police. Par exemple, déplacer la position des lettres ou modifier l’épaisseur de lettres individuelles.
  • La prochaine étape consiste à intégrer cette écriture dans des diagrammes, mais il est aussi prévu de créer quelque chose centré uniquement sur le texte. C’est très beau et plein de possibilités.

L’avis de GN⁺

  • Cet article offre un exemple intéressant du processus de numérisation d’une écriture manuscrite à l’aide de JavaScript et de p5.js. Pour les ingénieurs logiciel, cela peut être une bonne occasion de pratiquer leurs compétences en code à travers un projet créatif.
  • Il permet de voir comment appliquer des algorithmes mathématiques, comme l’algorithme de courbe de Chaikin, à un projet concret. Cela aide à mieux comprendre la programmation graphique.
  • Il montre aussi comment gérer une logique complexe, comme les fonctions d’ajustement de tracé. C’est une compétence importante pour améliorer la flexibilité et l’extensibilité du code.
  • Le projet aborde également des questions pratiques, comme l’optimisation de la taille des fichiers. C’est un point important dans le développement logiciel réel.
  • Lorsqu’on adopte cette technique, il faut garder à l’esprit que définir les tracés et écrire les fonctions d’ajustement peut demander beaucoup de temps. En contrepartie, le résultat offre une représentation du texte très personnalisée et unique.

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.