1 pontos por GN⁺ 2024-05-20 | Ainda não há comentários. | Compartilhar no WhatsApp

Escrita em bloco

  • O artigo anterior era sobre uma versão em letras de forma do alfabeto.
  • Em resumo, foi feito por meio do seguinte processo:
    • Escrever código que define os pontos principais do caminho de cada letra (~10 pontos por letra).
    • Usar o algoritmo de curvas de Chaikin para suavizar o caminho.
    • Converter o caminho em uma forma com espessura variável.
    • Desenhar o caminho da forma usando p5js.
  • Ficava assim:
  • Em breve haverá um artigo sobre como gerar frases com esse sistema. Assine a newsletter para receber novidades.
  • Definir os caminhos das letras originais era um trabalho muito manual, escrevendo posições no código e ajustando os pontos até que a letra ficasse com a aparência correta.
  • Ao codificar uma escrita cursiva, esse processo foi simplificado.

Design das letras

  • Foi criada uma ferramenta para definir e exportar os pontos principais dos caminhos, com acesso fácil no editor do p5js.
  • Ela oferece uma letra de exemplo e uma área para projetar novas letras.
  • Próximos passos:
    • Clicar para posicionar os pontos principais do caminho — o caminho resultante com curva de Chaikin é exibido.
    • Pressionar p para alternar para o modo de edição.
    • Selecionar um ponto e arrastá-lo para uma posição.
    • Pressionar enter para imprimir o caminho no console.
  • Foram criadas de 2 a 3 opções para cada letra.
  • O caminho resultante é assim:
    [{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}]
    
  • Como queria usar a própria letra como guia, foram escritos exemplos em minúsculas e maiúsculas, e as imagens foram carregadas diretamente na ferramenta para serem traçadas.
  • As teclas w/a/s/d são usadas para posicionar a imagem no lugar correto, e r/e para aumentar ou diminuir o zoom da imagem.
  • Os números são as coordenadas x y para posicionar a área correspondente na janela de geração de letras.
  • Depois de criar todos os caminhos, desenhar as curvas e convertê-los em formas com largura variável, cada letra individualmente ficava assim.

Tornando cursiva

  • Às vezes, conectar letras é fácil. Basta ir diretamente do caminho dos pontos principais de uma para o próximo caminho e então aplicar a curva de Chaikin de uma vez.
  • Mas alguns pares de letras não se encaixam bem.
  • Por exemplo, no par na, o último ponto de n é baixo e o primeiro ponto de a é alto, criando um caminho que cruza a em diagonal e faz parecer um e.
  • No par ti, t termina acima da linha de base e i começa na linha de base, criando uma elevação artificial.
  • Para resolver esses problemas, é possível adicionar um ponto extra no início de a e remover os dois últimos pontos de t.
  • Mas não dá para modificar as letras assim em todos os cenários.
  • Por exemplo, se a estiver no começo da palavra, o ponto adicional fica no lugar errado, e se vier depois de uma letra como w, surge uma linha cruzando a de outra forma.
  • Se t formar par com k, ele fica deformado.
  • Os pontos inicial e final do caminho de uma letra precisam variar conforme a posição em relação às outras letras.
  • No começo, a ideia era identificar pares "problemáticos" específicos e escrever regras para eles, mas no fim foram adicionados números ao início e ao fim de cada caminho para indicar o seguinte:
    • Não se conecta a outra letra (0)
    • Conecta-se a outra letra perto da linha de base (1)
    • Conecta-se a outra letra logo acima da linha de base (2)
    • Conecta-se a outra letra perto da altura-x (3)
  • Exemplo:
  • Agora o caminho de cada letra fica assim. Repare nos números de um dígito no início e no fim:
    [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]
    
  • Todos os pares de letras foram testados:
  • Aqui é possível ver que há várias opções de caminho para cada letra, além das mudanças causadas quando a letra é editada conforme as letras vizinhas.
  • Idealmente, seria bom ter pelo menos 5 a 6 opções de caminho para cada letra, mas é preciso equilibrar isso com o tamanho do arquivo.

Geração de palavras

  • Quando uma palavra é gerada:
    • Um caminho base é escolhido para cada letra entre 2 a 3 opções diferentes.
    • As informações sobre o fim do caminho são passadas para as letras adjacentes (como diferentes opções de caminho da mesma letra podem ter diferentes pontos finais, todos os caminhos das letras precisam ser escolhidos primeiro).
    • O caminho base é ajustado em resposta às letras vizinhas. Por exemplo, se a altura final da letra anterior for 2, remove-se 1 ponto do início deste caminho; ou, se a altura inicial da próxima letra for 1, adiciona-se um ponto extra em uma posição específica.
  • A função de ajuste pode ser um pouco complexa. Por exemplo, a função da letra q é a seguinte:
    // ip = caminho
    // pc = informação do fim da letra anterior
    // nc = informação do início da próxima letra
    // n = índice do caminho escolhido para esta letra
    adjust: (ip, pc, nc, n) => {
      // adiciona uma interrupção no fim desta letra com 70% de chance
      if (rand() < 0.7 ) ip.splice(-1, 1, 0);
      // se [2] foi escolhido para este caminho entre 4 opções
      if (n < 2) {
        // se a letra anterior terminar em 3, substitui os dois primeiros pontos por outro ponto
        if (pc == 3) ip.splice(1, 2, {x:10,y:12});
        // caso contrário, se não for 0, adiciona um ponto no início
        else if (pc > 0) ip.splice(1, 0, {x:10,y:20});
      }
      // se não houver interrupção entre esta letra e a próxima (0)
      if (nc > 0 && ip[ip.length-1] != 0){
        // substitui os dois últimos pontos por outro ponto
        ip.splice(-3, 2, {x:16,y:34});
      }
    }
    
  • Mas muitas vezes ela é curta. Por exemplo, a função da letra n é a seguinte:
    adjust: (ip, pc, nc) => {
      // se a próxima letra começar em 3, gera aleatoriamente uma interrupção ou move o último ponto
      if (nc == 3) rand() < 0.3 ? ip.splice(-1, 1, 0) : ip.splice(-2, 1, {x:17,y:23.8});
    }
    
  • Em seguida, todos os caminhos base das letras são conectados entre si. Nesse processo, 1, 2 e 3 do caminho são ignorados, mas sempre que aparece um 0, um novo caminho é iniciado para criar uma interrupção.
  • Depois, o caminho é transformado em curva, convertido em uma forma de largura variável e recebe um leve tremor com ruído de Perlin; a escrita cursiva fica assim.
  • Em breve haverá um artigo sobre como gerar esta frase. Assine a newsletter para receber novidades.
  • Por diversão, aqui está uma comparação lado a lado entre a caligrafia codificada executada em um plotter e a caligrafia real.

Quanto pesa?

  • A classe de letras para escrita em bloco tinha 9.7kb.
  • A classe de letras cursivas atualmente tem 26.1kb (após compressão).
  • Essa classe é maior porque inclui vários caminhos para cada letra e funções que ajustam os pontos. Mas também há algumas outras formas de economizar.
  • Parece que ainda dá para economizar mais. Eu não sou um mago do code golf, mas tenho algumas ideias.
  • Por exemplo, atualmente as letras são projetadas com base em um tamanho de fonte padrão 20 e depois redimensionadas. Isso significa que muitos pontos são definidos como x: 14.5, mas se o tamanho base fosse alterado para 200, os pontos poderiam ser definidos como 145, removendo as casas decimais. Essa mudança exigiria cuidado, então ficou para a lista de tarefas futuras.

Como usar

  • O principal objetivo desta caligrafia é servir para títulos, rótulos e anotações rabiscadas em diagramas nos quais estou trabalhando.
  • Mas também é muito divertido brincar com o próprio texto.
  • Como os caminhos foram codificados, em vez de usar uma fonte pronta é possível brincar com os próprios caminhos. Mudar a posição das letras, alterar a espessura de letras individuais e assim por diante.
  • O próximo passo é integrar essa caligrafia aos diagramas, mas também há planos de criar algo focado no próprio texto. É muito bonito e tem muitas possibilidades.

Opinião do GN⁺

  • Este artigo oferece um exemplo interessante do processo de digitalizar a própria caligrafia usando JavaScript e p5.js. Isso pode ser uma boa oportunidade para engenheiros de software praticarem habilidades de programação por meio de um projeto criativo.
  • É possível aprender como aplicar algoritmos matemáticos como o de curvas de Chaikin em projetos reais. Isso ajuda a aprofundar a compreensão de programação gráfica.
  • Também dá para aprender a lidar com lógica complexa, como funções de ajuste de caminhos. Essa é uma habilidade importante para aumentar a flexibilidade e a extensibilidade do código.
  • O projeto trata de questões práticas como otimização de tamanho de arquivo. Isso é uma consideração importante no desenvolvimento de software real.
  • Ao adotar essa técnica, pode ser necessário investir bastante tempo na definição dos caminhos e na escrita das funções de ajuste. Em compensação, o resultado oferece uma representação de texto muito personalizada e única.

Ainda não há comentários.

Ainda não há comentários.