Transforming text – Geomerative

General Information

As I was working on this, I realized that I haven’t understood the Geomerative library as much as I thought I did, as I struggled a lot while using it.
Therefore, I wanted to make this week’s assignment, an opportunity for me to get a better grasp of most things that have to do with Geomerative and implement something quite basic.

I got the idea to make a program that displays words from a string one at a time, with a transition transforming each word into the one following it. (When we reach the final word of the string, it starts again from the first word.)
It turns out that this has been done a lot before, and to be honest, since I was still trying to learn about the Geomerative library, I ended up needing a lot of help and inspiration from the pre-existing codes I found online.
(PS: I didn’t copy any code. I used what I found to understand some of the main concepts of the program, but I made sure to code everything myself.)

The process

The first thing I did was use the geomerative_basic example, that Professor has provided us with, as my base. (It’s on GitHub if anyone was wondering.)
This program displays one string using ellipses.
In order to make it more suitable for what I wanted to create, I made a bunch of changes:

      • I turned everything into arrays (or array of arrays) so that it can be used on multiple strings instead of one.
      • Instead of using RGroup, I used RShape. This is because I needed access to each point individually so I needed to use getPoint() instead of getPoints(), which doesn’t work on RGroup.
      • Instead of drawing ellipses, I drew points. I made the number of points quite big so that it appears as a line which makes the transition effect look a bit cooler.
      • I added another array of arrays of RPoint called “changing_pnts” such that for every word, there are multiple elements:  changing_pnts[…], each containing the positions of all the points making up that word but at a different stage of the transition.
      • I added a function that populates changing_pnts. It has a role in changing each word into the next one and the last word back into the first one.

This is the code in the tab containing the function:

float temp1,temp2;

void populate_changing_pnts()
{
  //for each word
  for (int i=0; i<myStringArr.length; i++) 
  {
      //for the number of positions taken during the transition
      for (int j=0; j<num; j++) 
      {
          //for the number of points in this word (word of index i)
          for (int k=0; k<pnts[i].length; k++) 
          {
              //if we're at the last word, make the transition back to the first word
              if (i == myStringArr.length -1){
                temp1 = lerp( pnts[i][k].x, pnts[0][k].x, j*(1.0/num));
                temp2 = lerp( pnts[i][k].y, pnts[0][k].y, j*(1.0/num));
                changing_pnts[index][k] = new RPoint(temp1, temp2);
              }
              //if we're not at the last word, make the transition to the next word
              else {
                temp1 = lerp( pnts[i][k].x, pnts[i+1][k].x, j*(1.0/num));
                temp2 = lerp( pnts[i][k].y, pnts[i+1][k].y, j*(1.0/num));
                changing_pnts[index][k] = new RPoint(temp1, temp2);
              }  
          }
          index += 1; /*this is here because when the counter j goes back to 0, we want index to keep 
                      incrementing to reach the size of changing_pnts*/
      }
  }
  index = 0; //setting back index to 0
}

 

And this is the code in the main tab:

import geomerative.*;

RFont font;
int diameter = 15;
int pointNum = 2500; //this how many points we want the words to be made up of

String myString = "this wasn't as easy as it seemed in my head"; 
String[] myStringArr; //this is a string of strings that will contain all words from myString 
RPoint[][] pnts; //an array of arrays of points. For each word i, pnts[i] contains all points that form that word

RShape[] words; //an array of groups
float xOffset[]; //an array of xOffsets

int num = 60; //This is the number of positions that each point will go through while it's transitioning
              //This means it will move through 60 positions to get from its start to its destination

RPoint[][] changing_pnts; //an array of arrays of points.
                          //its size will be num * the size of the array of arrays pnts.
                          /*because for each word, there exist many elements changing_pnts[] 
                          each containing the positions of the points at a different stage of the transition*/

int index = 0; //this variable will be the one used to iterate through changing_pnts without a for loop


void setup() {
  size(640, 640);
  stroke(0);
  strokeWeight(4);
  
  RG.init(this);
  font = new RFont("Franklin Goth Ext Condensed.ttf", 200, RFont.CENTER);
  
  myStringArr = split(myString, ' ');
  
  //initializing all of the arrays according to the size of myStringArr
  pnts = new RPoint[myStringArr.length][pointNum];
  words = new RShape[myStringArr.length];
  xOffset = new float[myStringArr.length];
  changing_pnts = new RPoint[(myStringArr.length)*num][pointNum]; //size of this is = nums * size of pnts

  
  // load all strings from the myStringArr into geomerative
  for(int i=0; i<myStringArr.length; i++){
    words[i] = font.toShape(myStringArr[i]);
    //create the same number of points for each word
    for (int j=0; j<pointNum; j++){
      pnts[i][j]= words[i].getPoint(j*(1.0/pointNum));
    }

     //to set each word in the middle of the screen
     //get the size of the string from myStringArr susbtracted from the width of the screen
     //this is the amount left over
    xOffset[i] = width - words[i].getBottomRight().x - words[i].getBottomLeft().x;
    // divide that by two to center it
    xOffset[i] /= 2;
  }
  
  //this function fills changing_pnts with all the required points
  populate_changing_pnts(); 
}

void draw() {
  background(255);
  for (int j = 0; j< pointNum; j++) {
    float x = changing_pnts[index][j].x + xOffset[0];
    float y = changing_pnts[index][j].y + height/2;
    point(x, y);
  }
  index+= 1;
  if (index == (myStringArr.length)*num){
    index=0;
  }
  
}

final outcome

Leave a Reply