How to change String order and position and keep char order of each String?!

Hello,
I got some amazing help from the great @jeremydouglass for my sketch, but I am stuck now.
Jeremy wrote me this below, but I don’t find the solution to write properly the function he suggested to me.

Blockquote

"It seems like you want to do word-level manipulations, then produce a mapping of the new positions.

So you want something like this:

“one for all”

designated as [0, 1, 2]

and then you want to give the input [2, 1, 0]

and produce “all for one” – is that correct?

So the function should accept two things – a String, and an int[] word order number sequence – and it should return an int[] of the letter id order

int[] order1 = new int[] {0, 1, 2};
int[] origins = targetPositions("one for all", order1); 
println(origins);

0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8

int[] order2 = new int[] {2, 1, 0};
int[] targets = targetPositions("one for all", order2);
println(targets);

6, 7, 8, -1, 3, 4, 5, -1, 0, 1, 2

now you can find a target for each id, get the position of that target, and lerp to it.

for (int i=0; i<targets.length; i++) {
  PVector targetPos = posFromID(targets[i]);
  PVector pos = PVector.lerp(originPos[i], targetPos, amt);
}
"

Blockquote

Here is my bad attempt below. I managed to get this :

println(origins);
> 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8 


(FULL CODE BELOW )
but don’t manage to change the words order… How should I procceed.
Thanks a lot for your help.
best wishes,

Laurent

String message;
PVector []originPos;
PVector[] targetsPos; 
PVector []posFromID;
int[]targets;
float arcLength;
PVector pos = new PVector(0, 0);
String []st ;
String [] wordsList;
int []origins;
float amt=0.02;
String m;
float rad =200;
String  s = "one for all";
char [] c;
int[] order;


void setup() {

  size(1000, 1000);
  textFont(createFont ("Lucida sans", 20));
  textSize(30);
  textAlign(CENTER, CENTER);
  st = split(s, ' ');
  message = join(st, ' ');
  targetsPos = chosenPos(message.length());
  originPos = chosenPos(message.length());

  for (int i=0; i<message.length(); i++) {
    char [] c = new char[message.length()]; 
    c[i] =message.charAt(i);
  }
  for (int i=0; i<message.length(); i++) {
    targets = new int [message.length()];
  }
}


void draw() {
  background(0);
  arcLength=0;

  translate(width/2, height/2);

  for (int i=0; i<message.length(); i++) {
    char [] c =message.toCharArray(); 
    char currentChar = message.charAt(i);
    float w = textWidth(currentChar);
    arcLength +=w/2+10;
    float theta = PI+arcLength/rad;
    targetsPos[i].x = cos(theta)*rad;
    targetsPos[i].y = sin(theta)*rad; 
    originPos[i].lerp(targetsPos[i], 0.02);
     // draw words + rect
    pushMatrix();
    translate(originPos[i].x, originPos[i].y); 
    rotate(theta+PI/2);
    noFill();
    stroke(255, 0, 0, 200);
    strokeWeight(3);
    rect(0, 0, 10, 10);
    fill(255, 200);

    text(c[i], 0, 0);
    popMatrix();
    arcLength+=w/2;
  }
}


/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/
void keyReleased() {
  if (key=='0') {
    int[] order1 = new int[] {0, 1, 2};
    int[] origins = targetPositions(s, order1); 
    println(order1);
    println(origins);
  } else if (key=='1') {
    int[] order2 = new int[] {2, 1, 0};
    int[] targets = targetPositions(s, order2);
    println(order2);
    println(targets);
  }
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/

PVector[] chosenPos(int count) {
  PVector[] originPos = new PVector[count];
  for (int i=0; i<message.length(); i++) {
    originPos[i] = new PVector(0, 0);
  }
  return originPos;
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/

int [] targetPositions (String s, int[]order) {

  String[]st = split(s, " ");
  
  String  [] ns = new String [st.length];
  ns[0] = st[order[0]];
  ns[1] = st[order[1]];
  ns[2] = st[order[2]];
  ns=st;

  s=join(st, ' ');

  int [] origins = new int[s.length()];
  PVector [] np = new PVector [s.length()];
  for (int i=0; i<st.length; i++) {
    for (int j=0; j<s.length(); j++) {

      if (order[i]==0) {

        st[0] = "one";
        st[0] = s.substring(0, 2);
        origins[0]=s.indexOf('o');
        origins[1]=s.indexOf('n');
        origins[2]=s.indexOf('e');

        np[0]=originPos[origins[0]];
        np[1]=originPos[origins[1]];
        np[2]=originPos[origins[2]];
      }
      origins[3]=s.indexOf('$');

      if (order[i]==1) {

        st[1] = "for";
        st[1] = s.substring(4, 6);
        origins[4]=s.indexOf('f')-1;
        origins[5]=s.indexOf(st[1], 1);
        origins[6]=s.indexOf('r')-1;

        np[4]=originPos[origins[4]];
        np[5]=originPos[origins[5]];
        np[6]=originPos[origins[6]];
      }
      origins[7]=s.indexOf('$');

      if (order[i]==2) {

        st[2] = "all";
        st[2]= s.substring(8, 10);
        origins[8]=s.indexOf('a')-1;
        origins[9]=s.indexOf('l')-1;
        origins[10]=s.indexOf('l');

        np[8]=originPos[origins[8]];
        np[9]=originPos[origins[9]];
        np[10]=originPos[origins[10]];
      }
    }
  }
  return origins;
}



/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/
2 Likes

Here what should be the result !! :


But wiith this solution I loose track of the initial positions of my chars… Please help!!

1 Like

I answer only this part with this Sketch.

The mentioned function is named arrange



String  s = "one for all"; // Start String 
String []st; // split String 

// -------------------------------------------------------------------------------------

void setup() {

  size(1000, 1000);

  // split 
  st = split(s, ' ');

  // make s again but without the ' '
  String message = "";
  for (int i=0; i<st.length; i++) {
    message += st[i];
  }

  // build an array newArrayWords to keep track of letter positions 
  OneWord[] newArrayWords;
  newArrayWords = new OneWord [st.length]; 

  int j=0; 
  for (int i=0; i<st.length; i++) {  // for-loop over st
    newArrayWords[i] = new OneWord(st[i], j);  // put this word into array newArrayWords
    j += st[i].length();
  }

  testPrintlnNewArrayWords(newArrayWords);

  // Now test the array using the function arrange (which is the core function) 
  int[] order1 = new int[] {0, 1, 2};
  int[] order2 = new int[] {2, 1, 0};
  int[] order3 = new int[] {2, 0, 1};

  int[] newOrder = arrange(newArrayWords, order1);
  printArrayMy(order1);
  printArrayMy(newOrder); 
  printWordMy(message, newOrder); 
  println("");

  newOrder = arrange(newArrayWords, order2);
  printArrayMy(order2);
  printArrayMy(newOrder);
  printWordMy(message, newOrder); 
  println("");

  newOrder = arrange(newArrayWords, order3);
  printArrayMy(order3);
  printArrayMy(newOrder);
  printWordMy(message, newOrder); 
  println("");
  //
} // setup

void draw() {
  background(0);
}//draw

// ------------------------------------------------------------------------------------------

void testPrintlnNewArrayWords(OneWord[] newArrayWords_) {
  for (OneWord ow : newArrayWords_) {
    println ( ow.s1, ow.arrayStart);
  }
  println("");
}//func 

void printArrayMy(int[] list_) {
  for (int i1 : list_) {
    print(i1+", ");
  }
  println("");
}//func 

void printWordMy(String s_, int[]newOrder_) {
  for (int i=0; i<newOrder_.length; i++) {
    if (newOrder_[i] != -1) {
      print(s_.charAt( newOrder_[i] ));
    } else {
      print(" ");
    }
  }//for
  println("");
}//func 

int[] arrange(OneWord[] list, int [] order) {

  int[] result; 
  int len1=0;

  if (list.length != order.length) 
    println("Error +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 

  // prepare empty array 
  for (OneWord ow : list) {
    len1+=ow.s1.length();
  }
  result = new int [  len1 + list.length  ]; 

  // fill array
  int i=0; 
  for (int i2=0; i2<st.length; i2++) {
    // for (OneWord ow : newArrayWords) {
    OneWord ow = list[order[i2]];
    int countChar=0; 
    for (char c : ow.s1.toCharArray()) {
      //
      result[ i ] = ow.arrayStart + countChar;
      countChar++;
      i++;
    }
    result[ i ] = -1;
    i++;
  }

  return result;
}// func 

// =================================================================================
// classes 

class OneWord {

  String s1; 
  int arrayStart;

  // constr 
  OneWord (String s1_, int pos_) {
    s1         = s1_;
    arrayStart = pos_;
  }// constr 
  //
}//class 
//
1 Like

new shorter form

pass a string and array now to function arrange()

String  s = "one for all"; // Start String 

int[] order1 = new int[] {0, 1, 2};
int[] order2 = new int[] {2, 1, 0};
int[] order3 = new int[] {2, 0, 1};

// -------------------------------------------------------------------------------------

void setup() {

  size(1000, 1000);

  // split String s
  String []st = split(s, ' ');
  // make s again but without the ' '
  String message = "";
  for (int i=0; i<st.length; i++) {
    message += st[i];
  }

  // Now test the function arrange (which is the core function) 
  testOutputOneOrder(message, order1);
  testOutputOneOrder(message, order2);
  testOutputOneOrder(message, order3);
  //
} // setup

void draw() {
  background(0);
}//draw

// ------------------------------------------------------------------------------------------

void testOutputOneOrder(String message_, int[] order1_) {
  // Now test the function arrange (which is the core function) 
  int[] newOrder = arrange(s, order1_);
  printArrayMy(order1_);
  printArrayMy(newOrder); 
  printWordMy(message_, newOrder); 
  println("");
}

int[] arrange(String s, int [] order) {

  int[] result; 
  int len1=0;

  // split
  String []st; // split String
  st = split(s, ' ');

  // build an array newArrayWords to keep track of letter positions 
  OneWord[] newArrayWords;
  newArrayWords = new OneWord [st.length]; 

  int j=0; 
  for (int i=0; i<st.length; i++) {// for-loop over st
    newArrayWords[i] = new OneWord(st[i], j); // put this word into array newArrayWords
    j += st[i].length();
  }

  testPrintlnNewArrayWords(newArrayWords);

  if (newArrayWords.length != order.length) 
    println("Error +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 

  // prepare empty array 
  for (OneWord ow : newArrayWords) {
    len1+=ow.s1.length();
  }
  result = new int [  len1 + newArrayWords.length  ]; 

  // fill array
  int i=0; 
  for (int i2=0; i2<st.length; i2++) {
    // for (OneWord ow : newArrayWords) {
    OneWord ow = newArrayWords[order[i2]];
    int countChar=0; 
    for (char c : ow.s1.toCharArray()) {
      //
      result[ i ] = ow.arrayStart + countChar;
      countChar++;
      i++;
    }
    result[ i ] = -1;
    i++;
  }

  return result;
}// func 

void testPrintlnNewArrayWords(OneWord[] newArrayWords_) {
  for (OneWord ow : newArrayWords_) {
    println ( ow.s1, ow.arrayStart);
  }
  //println("");
}//func 

void printArrayMy(int[] list_) {
  for (int i1 : list_) {
    print(i1+", ");
  }
  println("");
}//func 

void printWordMy(String s_, int[]newOrder_) {
  for (int i=0; i<newOrder_.length; i++) {
    if (newOrder_[i] != -1) {
      print(s_.charAt( newOrder_[i] ));
    } else {
      print(" ");
    }
  }//for
  println("");
}//func 

// =================================================================================
// classes 

class OneWord {

  String s1; 
  int arrayStart;

  // constr 
  OneWord (String s1_, int pos_) {
    s1         = s1_;
    arrayStart = pos_;
  }// constr 
  //
}//class 
//
2 Likes

Dear @Chrisir,
How to thank you enough for helping me so much?!
I will look at your code more carefuly when I won’t be at work. It looks as the solution was more complex than what I thought…
Truly tours,
L

1 Like

Dear Chrisir,
Thank you very much again for this great shorter version!
I have some questions, even if dummies, I want to be sure to understand and to be able to use
this logic into my next codes…

 // prepare empty array 
  for (OneWord ow : newArrayWords) {
    len1+=ow.s1.length();
  }
  result = new int [  len1 + newArrayWords.length  ];

When you write : ow.s1.length() it means that in this way you get access to the length of each word inside the sentence? The dot means “of the previous”?! Sorry I have vague notions in Java and didn’t know you can write this that way! It looks like the key notion inside this sketch.

// fill array
int i=0;
for (int i2=0; i2<st.length; i2++) {
// for (OneWord ow : newArrayWords) {
OneWord ow = newArrayWords[order[i2]];// give new array of words the order length = 3
int countChar=0; //var to stock the number of char
for (char c : ow.s1.toCharArray()) { // embeded for loop to get the char inside the array of words
println(“char c”+":"+c);
result[ i ] = ow.arrayStart + countChar;// index of each char (arrayStart comes from the OneWord class)
countChar++;// increase index of char
i++;//incresae index of result
//println(result);
}
result[ i ] = -1;// if char ==’ ’ increase index i
i++;
}

return result;
}// func

Are my comments all right? I hope so in this case I quite understand your code :sweat_smile:
Sorry to bother you with that but if I am not sure I won’t make any progress.
Thank you very very much for your great help, pedagogy and patience.
Best wishes,
L

1 Like

there is a tutorial about OOP: https://www.processing.org/tutorials/objects/

please learn about the dot there.

  • ow is the object
  • s1 ist the String in it (see inside the class)
  • length() is the length of the String S1

In this for loop we just measure how long all words are together so we can make the array result of the size.

Chrisir :wink:

2 Likes

Thank you sooooomuch I’ll have a look at the tutorial!
Ok it means that I understood this at least but didn’t know how to put it at all in code!!!
Thank you Master @Chrisir :pray:t2: :pray:t2: :pray:t2:

(you didn’t format code correcty.)

your comment isn’t very good.

See, in the outer for loop we loop over the words in st, but we pick the word ow from newArrayWords. But not in the order 0,1,2 but in the order dictated by order[].

Therefore we write newArrayWords[order[i2]] (and not newArrayWords[i2])

so your comment should read, pick word ow from list newArrayWords based on the order in array order[] which we use with i2.


Explanation

Remember, we want to get

6, 7, 8, -1, 3, 4, 5, -1, 0, 1, 2

that goes into the array result.

  • Therefore in the outer for-loop we pick the words ow in the given order, 2,1,0. We get ow.

  • In the inner for-loop we fill result with the char numbers for that word, e.g. 6,7,8. We use ow (which are words coming in in the right order like 2,1,0) and calculate their char positions (e.g. 6,7,8) based on ow.arrayStart (this is the trick: we stored ow.arrayStart into the words list newArrayWords when we made the list so each word knows that it starts at 6 or 3 or 0 and we use this now). Because we set countChar = 0 every time before the inner for-loop, we can just add countChar to ow.arrayStart to go from 6 to 6,7,8 (and 0,1,2 and 3,4,5).

  • To bring in the -1 into 6, 7, 8, -1, 3, 4, 5, -1, 0, 1, 2, we have a line result[ i ] = -1; after the inner for-loop. So every time a word is finished.


New Version

Here is a new version with a better wording and better for-loops in the function arrange

I am sure that can be greatly simplified.

I just made the class OneWord to help me thinking…


// https://discourse.processing.org/t/how-to-change-string-order-and-position-and-keep-char-order-of-each-string/23656

String  s = "one for all"; // Start String 

int[] order1 = new int[] {0, 1, 2}; // different word orders 
int[] order2 = new int[] {2, 1, 0};
int[] order3 = new int[] {2, 0, 1};

// -------------------------------------------------------------------------------------
//  the 2 core functions of processing 

void setup() {

  size(1000, 1000);

  // split String s
  String []st = split(s, ' ');
  // make s again but without the ' '
  String message = "";
  for (int i=0; i<st.length; i++) {
    message += st[i];
  }

  // Now test the function arrange (which is the core function) 
  testOutputOneOrder(message, order1);
  testOutputOneOrder(message, order2);
  testOutputOneOrder(message, order3);
  //
} // setup

void draw() {
  background(0);
}//draw

// ------------------------------------------------------------------------------------------
// test function 

void testOutputOneOrder(String message_, int[] order1_) {
  // Now test the function arrange (which is the core function) 
  int[] newOrder = arrange(s, order1_);
  printArrayMy(order1_);
  printArrayMy(newOrder); 
  printWordMy(message_, newOrder); 
  println("");
}

// ------------------------------------------------------------------------------------------
//  the core function and other functions

int[] arrange(String incomingString_, int[] order) {
  // the core function!

  // the function should accept two things – a String, and an int[] word order number sequence – and it should return an int[] of the letter id order

  int[] result; 
  int len1=0;

  // split s  -------------------------------------------------
  String []st; // split String
  st = split(incomingString_, ' ');

  // build an array newArrayWords from st to keep track of letter positions   -------------------------------------------------
  OneWord[] newArrayWords = new OneWord[st.length]; 

  int j=0; 
  for (int i=0; i<st.length; i++) {  // for-loop over st
    newArrayWords[i] = new OneWord(st[i], j); // put this word AND its start position j into array newArrayWords (defining ow.arrayStart from j)
    j += st[i].length();
  }

  testPrintlnNewArrayWords(newArrayWords);

  if (newArrayWords.length != order.length) {
    println("Error +++++++++++++");
  }

  // prepare empty array result  -------------------------------------------------
  for (OneWord ow : newArrayWords) {
    len1 += ow.stringS.length(); // get the length len1 for the array
  }
  result = new int [ len1 + newArrayWords.length ]; 

  // fill array result -----------------------------------------------
  int indexOfResult=0;

  for (int i_order=0; i_order<order.length; i_order++) { // outer for-loop

    OneWord ow = newArrayWords[order[i_order]]; // get the word ow according to order 

    // read the letter numbers for ow starting at ow.arrayStart
    for (int i_Count_Char=0; i_Count_Char < ow.stringS.length(); i_Count_Char++) {  // inner for-loop
      result[ indexOfResult ] = ow.arrayStart + i_Count_Char; // 6,7,8 etc. 
      indexOfResult++;
    }//inner for-loop

    result[ indexOfResult ] = -1;
    indexOfResult++;
  }//outer for-loop

  // return the result -----------------------------------------------
  return result;
}// func 

void testPrintlnNewArrayWords(OneWord[] newArrayWords_) {
  for (OneWord ow : newArrayWords_) {
    println ( ow.stringS, ow.arrayStart);
  }
  //println("");
}//func 

void printArrayMy(int[] list_) {
  for (int i1 : list_) {
    print(i1+", ");
  }
  println("");
}//func 

void printWordMy(String s_, int[]newOrder_) {
  for (int i=0; i<newOrder_.length; i++) {
    if (newOrder_[i] != -1) {
      print(s_.charAt( newOrder_[i] ));
    } else {
      print(" ");
    }
  }//for
  println("");
}//func 

// =================================================================================
// classes 

class OneWord {

  String stringS; 
  int arrayStart; // start pos of this word in the original String 

  // constr 
  OneWord (String stringS_, int pos_) {
    stringS    = stringS_;
    arrayStart = pos_;
  }// constr
  // 
  // not methods in this class
  //
}//class 
//

Chrisir

2 Likes

Very dear @Chrisir,
Sorry for my stupid comment, I did understood that we pick the word ow from newArrayWords in the order dictated by order[]. Thank you very much for explaining me again and in details the trick with ow.arrayStart and for rewriting the code again using var names that are even clearer! Very useful for a beginner like me…
Great job as usual :wink:
Thanks a million
:pray:t2: :100: :brown_heart:
Lolonulu

1 Like

Dear @Chrisir and @jeremydouglass,

Sorry for the delay but I was very busy at work for a long while…
Please find below a simpler version of @Chrisir previous code. I hope it works as the println indicate it!
I try to find out a way to switch from the original positions to the new ones, but don’t know how to handle it yet.
In fact I don’t get what you wrote here @jeremydouglass :

for (int i=0; i<targets.length; i++) {
  PVector targetPos = posFromID(targets[i]);
  PVector pos = PVector.lerp(originPos[i], targetPos, amt);
}

Sorry for being such a noob, if you can explain me little bit that I will find how to lerp from the original PVector to the new positioned PVector, it would be great and greatly appreciated!
Here is the code:

String jointS;
PVector []originPos;
PVector[] targetsPos; 
float arcLength;
String [] wordsList;
int []origins;
int[]targets;
float amt=0.02;
String m;
float rad =200;
String  s = "one for all";
char [] c;
int[] order;
int arrayStart = 0;
String message = "";
int[] order1 = new int[] {0, 1, 2};
int[] order2 = new int[] {2, 1, 0};

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/

void setup() {

  size(1000, 1000);
  textFont(createFont ("Lucida sans", 20));
  textSize(30);
  textAlign(CENTER, CENTER);
  String []st = split(s, ' ');
  jointS = join(st, ' ');
  jointS=jointS+char(' ');
  targetsPos = chosenPos(jointS.length());
  originPos = chosenPos(jointS.length());
  c = new char[jointS.length()]; 
  //int[]origins = targetPositions("all for one", order1);
  //int[]targets = targetPositions("all for one", order2);
  for (int i=0; i<(jointS.length()); i++) {
    c[i] =jointS.charAt(i);
  }

  for (int i=0; i<(jointS.length()); i++) {
    targets = new int [jointS.length()];
  }

  for (int i=0; i<st.length; i++) {
    message += st[i];
    message = trim(message);
  }
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/

void draw() {
  background(0);
  arcLength=0;

  translate(width/2, height/2);
  //println(jointS.length());
  int[]origins = targetPositions("all for one", order1);
  for (int i=0; i<origins.length; i++) {
    //println("origins"+":"+origins.length);
    char [] c =jointS.toCharArray(); 

    char currentChar = jointS.charAt(i);
    float w = textWidth(currentChar);
    arcLength +=w/2+10;
    float theta = PI+arcLength/rad;
    targetsPos[i].x = cos(theta)*rad;
    targetsPos[i].y = sin(theta)*rad; 

    originPos[i].lerp(targetsPos[i], 0.02); 
    pushMatrix();
    // draw words + rect
    translate(originPos[i].x, originPos[i].y); 
    rotate(theta+PI/2);
    noFill();
    stroke(255, 0, 0, 200);
    strokeWeight(3);
    rect(-5, 4, 10, 10);
    fill(255, 200);
    text(c[i], 0, 0);
    popMatrix();
    arcLength+=w/2;
  }
}


/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/
void keyReleased() {
  if (key=='0') {

    int[]origins = targetPositions("all for one", order1);
    println(targetPositions("one for all", order1));
    //println(origins.length);
  } else if (key=='1') {


    int[]targets = targetPositions("all for one", order2);

    println(targetPositions("one for all", order2));
  }
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/

PVector[] chosenPos(int count) {
  PVector[] originPos = new PVector[count];
  for (int i=0; i<jointS.length(); i++) {
    originPos[i] = new PVector(0, 0);
    //println(jointS.length());
  }
  return originPos;
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/

int [] targetPositions (String s, int[]order) {

  int len1=0;
  int[] origins;
  String[]st = split(s, ' ');
  String[]ns = new String [st.length];

  ns=st;

  if (ns.length != order.length)
    println("Error +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");

  //empty array
  for (int i =0; i<st.length; i++) {
    len1+=st.length;
  }
  origins = new int [message.length()+st.length];
  //println("origins.length"+":"+origins.length);

  int i =0;
  for (int i2=0; i2<st.length; i2++) {
    ns = new String [order[i2]];

    ns=st;
    int countChar=0;
    for (char c : ns[order[i2]].toCharArray()) { 
      arrayStart = message.indexOf(str(ns[order[i2]].charAt(0)));
      origins[i] = arrayStart+countChar;
      countChar++;
      i++;
    }
    origins[i] = -1;
    i++;
  }
  return origins;
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/

Thanks a lot in advance.
Best,
L

just check lerp() in the reference

increase amt slowly!!!



final int BETWEEN_DOTS=200;
float amt;

void setup() {
  size(1500, 500);
}

void draw() {
  background(#24B41D);
  strokeWeight(6);
  stroke(#FC8412);
  fly1();
}

void fly1 () {
  noFill();
  stroke(255, 0, 0);

  PVector a= new PVector(
    width/2+310, height/2+BETWEEN_DOTS/2); 
  PVector b= new PVector(
    width/2+BETWEEN_DOTS/2, height/2-BETWEEN_DOTS/2);
  PVector pos=  PVector.lerp(a, b, amt); 

  ellipse(pos.x, pos.y, 9, 9);

  amt+=0.01;
  if (amt>=1) 
    amt=0.0;
}
1 Like

Dear Chrisir,
Thanks a lot for this simple example. I’ll see how to relate it to my own sketch.
Thanks for your great help.
Best,

Laurent

here is a explanation: https://www.processing.org/reference/lerp_.html

also see this, which I actually used (Linear interpolate the vector to another vector): https://www.processing.org/reference/PVector_lerp_.html

1 Like

Dear @Chrisir,
please find below a code that works for the interpolation between letters, but here it’s harcoded so I undertsand it :

String message;
PVector []originPos;
PVector[] targetsPos; 
PVector []posFromID;
int[]targets;
float arcLength;
PVector pos = new PVector(0, 0);
String []st ;
String [] wordsList;
int []origins;
float amt=0.02;
String m;
float rad =200;
int index;
String  s = "one for all";
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ, ";
float [] originPositionsX = new float [alphabet.length()];
float [] originPositionsY = new float [alphabet.length()];
char[]c;



void setup() {

  size(1000, 1000);
  textFont(createFont ("Lucida sans", 20));
  textSize(70);
  textAlign(CENTER, CENTER);
  st = split(s, ' ');
  message = join(st, ' ');
  targetsPos = chosenPos(message.length());
  originPos = chosenPos(message.length());
  c = new char[message.length()]; 
  for (int i=0; i<message.length(); i++) {

    c[i] =message.charAt(i);
    //println(c[i]);
  }
  for (int i=0; i<message.length(); i++) {
    targets = new int [message.length()];
  }
}


void draw() {
  background(0);
  arcLength=0;

  translate(width/2, height/2);

  for (int i = 0; i <message.length(); i++) {
    String st = str(message.charAt(i)).toUpperCase();
    char upperCaseChar = st.charAt(0);
    index = alphabet.indexOf(upperCaseChar);
    if (index < 0)continue;
    if (originPositionsX[index] != 0 && originPositionsY[index] != 0) {
      pushMatrix();
      noFill();
      stroke(255, 0, 0, 200);
      strokeWeight(1);
      bezier(originPositionsX[index], originPositionsY[index], originPos[i].x-50, originPos[i].y+20, originPos[i].x+80+noise(originPos[i].x+800), originPos[i].y-80, originPos[i].x, originPos[i].y);
      popMatrix();
    }
    originPositionsX[index] = originPos[i].x;
    originPositionsY[index] = originPos[i].y;
  }

  for (int i=0; i<message.length(); i++) {
    // println(message.length());
    char currentChar = message.charAt(i);
    float w = textWidth(currentChar);
    arcLength +=w/2+10;
    float theta = PI+PI/7+arcLength/rad;
    targetsPos[i].x = cos(theta)*rad;
    targetsPos[i].y = sin(theta)*rad; 
    originPos[i].lerp(targetsPos[i], 0.02);
    pushMatrix();
    // draw words + rect
    translate(originPos[i].x, originPos[i].y); 
    rotate(theta+PI/2);
    noFill();
    stroke(255, 0, 0, 200);
    strokeWeight(3);
    rect(0, 0, 10, 10);
    fill(255, 200);
    text(c[i], 0, 0);
    popMatrix();
    arcLength+=w/2;
  }
}



/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/
void keyReleased() {
  if (key=='0') {
    // reorder(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    /*int[] order1 = new int[] {0, 1, 2};
     int[] origins = targetPositions(s, order1); 
     println(order1);
     println(origins);*/
  } else if (key=='1') {
    reorder(8, 9, 10, 7, 4, 5, 6, 3, 0, 1, 2);
    /* int[] order2 = new int[] {2, 1, 0};
     int[] targets = targetPositions(s, order2);
     println(order2);
     println(targets);*/
  } else if (key=='2') {
    reorder(4, 5, 6, 3, 0, 1, 2, 7, 8, 9, 10);
  }
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/

PVector[] chosenPos(int count) {
  PVector[] originPos = new PVector[count];
  for (int i=0; i<message.length(); i++) {
    originPos[i] = new PVector(0, 0);
  }
  return originPos;
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------------*/
void reorder (int... order) {
  //char [] c = new char[message.length()]; 
  char [] nc = new char[message.length()];
  nc[0] = c[order[0]];
  nc[1] = c[order[1]];
  nc[2] = c[order[2]];
  nc[3] = c[order[3]];
  nc[4] = c[order[4]];
  nc[5] = c[order[5]];
  nc[6] = c[order[6]];
  nc[7] = c[order[7]];
  nc[8] = c[order[8]];
  nc[9] = c[order[9]];
  nc[10] = c[order[10]];

  c=nc;

  PVector [] nv = new PVector[message.length()];
  nv[0] = originPos[order[0]];
  nv[1] = originPos[order[1]];
  nv[2] = originPos[order[2]];
  nv[3] = originPos[order[3]];
  nv[4] = originPos[order[4]];
  nv[5] = originPos[order[5]];
  nv[6] = originPos[order[6]];
  nv[7] = originPos[order[7]];
  nv[8] = originPos[order[8]];
  nv[9] = originPos[order[9]];
  nv[10] = originPos[order[10]];

  originPos=nv;
}

But with the method you wrote I ‘lose track’ of my originPos. I know that the idea is to pass to the originPos the new order store in origins, but I don’t know where nor how?! The originPos vector order should be modified into the main method as in the example here above. Sorry to bother once again, but I’d like to understand… Thank you very much @Chrisir.
Best wishes,
L

I don’t have time but I am sure you can figure it out.

1 Like

Dear @Chrisir,
Thanks a lot for your message. When you will have time could you please tell me if the sketch I’ve sent you
yersteday is wright?! I will try to figure out. I certainly need to do exactly the same with the PVector[]originPos than we did with the order[]int inside the core method in order to change its order too…

here is an example with a class.

A “class” belongs to OOP paradigm, like “objects”.

Please learn it.

Then you will see the light.

see https://www.processing.org/tutorials/objects/

Chrisir

example with a class

PFont generatedFont;
float myOpacity;
boolean flagLettersGoToTheirSpot;

int lenArray = 3; 
String [] txt = new String[lenArray];

Letter[] lets;

final int stateNormal=0;
final int stateWait  =1;
int state = stateNormal;

boolean blockSpaceBar = false;  

int timer;

// ===================================

void setup() {
  // this runs only once

  size(1024, 768, JAVA2D);
  generatedFont = createFont("Bodoni-PosterCompressed-48.vlw", 15); 
  frameRate(60);

  txt[0] = "IT'S BETTER TO BURN OUT #THAN TO FADE AWAY";
  txt[1] = "I'D RATHER BE HATED FOR WHO I AM, #THAN LOVED FOR WHO I AM NOT";
  txt[2] = "I NEVER WANTED TO SING, I JUST #WANTED TO PLAY RHYTHM GUITAR - #HIDE IN THE BACK AND JUST PLAY";

  // this runs often 
  initLetters();  
  //
} // func  

void draw() {
  // this runs on and on
  background(0);  
  fill (255, 125);

  for (int i=0; i<lets.length; i++) {
    if (lets[i]!=null)
      lets[i].draw();
  } // for

  if (state == stateWait) {
    if (timer+2000<millis()) {   
      println ("waiting is over");
      state = stateNormal;
      blockSpaceBar = false;      
      flagLettersGoToTheirSpot=false;
      initLetters();
    }
  }
} // func

// -----------------------------------

void keyPressed() {
  if (!blockSpaceBar) {
    if (state != stateWait) {
      // if it was the space key
      if (key == ' ') {
        // set
        flagLettersGoToTheirSpot=true;
        blockSpaceBar = true; 
        initLetters();
      } // if
    } // if
  } // if
} // func 

void initLetters() { 
  // we choose a new sentence and init the letters 
  //
  // choose a random index for the sentence
  int rndIndex = int ( random (lenArray) );
  // take this sentence from the array 
  String currentSentence = txt[rndIndex];    
  // save the length of that sentence
  int lenSentence = currentSentence.length();  

  // init our array of letters 
  lets = new Letter[lenSentence];

  boolean useTwoLines=false;

  //  if (lenSentence>13)
  //    useTwoLines=true; 

  if (currentSentence.indexOf('#')>0)
    useTwoLines=true; 

  int xPos;
  int yPos; 
  int xAdd=0; 

  if (useTwoLines) {  
    xPos = 19; 
    yPos = height/2-10; 
    xAdd = 34;
  } else {
    xPos = 19; 
    yPos = height/2; 
    xAdd = ((width - 20) / lenSentence) - 0;
  }

  // for-loop
  int i=0;
  int lineNumber=1;
  for ( int j=0; j < lenSentence; j++ ) {
    if (currentSentence.charAt(j) == '#') {
      if (useTwoLines) {
        // new line 
        xPos=19;
        yPos = height/2+70*lineNumber;
        lineNumber++;
      }
    } else {
      lets[i] = new Letter( currentSentence.charAt(j), 
        xPos, 
        yPos );

      xPos = xPos + xAdd; 
      if (lets[i].c==' ') xPos-=10;
      else if (lets[i].c=='I') xPos-=15;
      else if (lets[i].c=='H') xPos-=-5;
      i++;
    } // else
  } // for
} // func 
//
// =================================================================================

class Letter { 
  char c; // the letter 
  float x, y, dx, dy, gx, gy;
  float angle=random(2*PI);  
  float angleAdd;

  Letter(char ic, float igx, float igy) {
    c = ic;
    gx = igx;
    gy = igy;
    x = random(width);
    y = random(height);
    dx=random(0.4, 1.5);
    if (random(100)<50)
      dx*=-1; 
    dy=random(0.4, 1.5);
    if (random(100)<50)
      dy*=-1;
    // how to change angle
    angleAdd = random(.01, .01);
    if (random(100)<50)
      angleAdd*=-1;
  } // constr

  void draw() {
    simulate();
    render();
  }

  void simulate() {
    if (flagLettersGoToTheirSpot) {
      // t is true: go to the right places 
      x=lerp(gx, x, .9);
      y=lerp(gy, y, .9);
      if (state==stateNormal)
        if (abs(gx-x)<.2 && abs(gy-y)<.2) {
          state = stateWait; 
          blockSpaceBar = true;  
          timer = millis();
          // println("start wait");
        }
    } else {
      // not t: free float  
      x+=dx;
      y+=dy;
      angle+=angleAdd;
      if (x<0) {
        x=0;
        dx*=-1;
      }
      if (y<0) {
        y=0;
        dy*=-1;
      }
      if (x>width) {
        x=width;
        dx*=-1;
      }
      if (y>height) {
        y=height;
        dy*=-1;
      }
    }
  }

  void render() {
    textFont(generatedFont, 50);
    myOpacity = mapValueWithPeak(y);
    fill (255, myOpacity);
    if (flagLettersGoToTheirSpot) {
      text(c, x, y);
    } else {   
      pushMatrix();
      translate(x, y);
      rotate(angle);    
      text(c, 0, 0);
      popMatrix();
    }
  }

  int mapValueWithPeak(float inputValue) {
    // this is similar to map() but with a peak in the middle of the target range:
    // this range: / goes to this range: /\

    // calculate the input for sin based on the input range
    float result = map (inputValue, 0, height, 0, PI); // 0-PI = half radius
    // calculate sin from that input
    float result2 = sin (result);
    // scale this result to the range you need
    float result3 = map(result2, 0, 1, 0, 255);

    return  int(result3);
  }
} // class
//
1 Like

Dear @Chrisir,
Your sketch is simply marvelous! The kind of thing I would spend months to do that you make in a couple of hours! Thank you so much for this brillant demonstration Master :pray: :pray: :pray: !!

My problem is not really to learn class, OOP, or function, but to understand how to solve problems thanks to them! I don’t know how to write a function to get the result I want except for very simple stuff…
How to improve?! I’ll check out the tutorials anyway. Thank you so much @Chrisir for your great help and patience towards me, I greatly appreciate. :heart_eyes:
Best, L

1 Like

Dear @Chrisir,

I really apologize to write you after so much time once again but I had a lot of work…
Here is a poor attempt to lerp from originpos to targetpos, but I can’t find the solution.

Despite all, I took some time to learn more about OOP as you advised me with Daniel Schiffman tutorilas that are great. I have learned quite a lot but still not enougth to solve this problem!! The letters start to move to the right spot, but… Sorry to bother with this. Thanks a lot for your help.
Best wishes,
L

String s = "all for one"; // Start String 
String alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
String []st;
String message;
PVector []posFromID;
int[] order1 = new int[] {0, 1, 2};
int[] order2 = new int[] {2, 1, 0};
int[] order3 = new int[] {2, 0, 1};
int[]targets;
PVector[]originPos;
PVector[] targetsPos;
float arcLength;
float rad =200;
PVector [] chosenPos;
char[] c;
OneWord[] newArrayWords;
float [] originPositionsX = new float [alphabet.length()];
float [] originPositionsY = new float [alphabet.length()];
String joinedText ;
boolean flagLettersGoToTheirSpot;
Letter[] letters;

// -------------------------------------------------------------------------------------

void setup() {

  size(1000, 1000);
  // split String s
  textFont(createFont ("Lucida sans", 30));
  textSize(80);
  textAlign(CENTER, CENTER);
  //String joinedText = join(s, ' ');
  String []st = split(s, ' ');
  // make s again but without the ' '
  //println(st.length);
  OneWord[] newArrayWords;
  newArrayWords = new OneWord [st.length];

  int j=0; 
  for (int i=0; i<st.length; i++) {// for-loop over st
    newArrayWords[i] = new OneWord(st[i], j); // put this word into array newArrayWords
    j += st[i].length();
    //println(j);
  }
  //joinedText=join(s, " ");
  message = "";
  originPos = chosenPos(s.length());
  targetsPos = chosenPos(s.length());

  for (int i=0; i<st.length; i++) {
    message += st[i];
    // println(message.length());
  }
  letters = new Letter[s.length()];
  for (int i=0; i<s.length(); i++) {

    letters[i]= new Letter(0, 0, s.charAt(i), 300);
  }
} // setup

void draw() {
  background(0);
  arcLength=0;
  translate(width/2, height/2);

  for (int i=0; i<s.length(); i++) {

    String st = str(s.charAt(i)).toUpperCase();
    char upperCaseChar = st.charAt(0);
    int idx = alphabet.indexOf(upperCaseChar);
    if (idx <0) continue;

    if (originPositionsX[idx]!=0 && originPositionsY[idx]!=0) {
      pushMatrix();
      rotate(PI/4);
      noFill();
      stroke(255, 0, 0);
      strokeWeight(1);
      //line(originPositionsX[idx], originPositionsY[idx], originPos[i].x, originPos[i].y);
      bezier(originPositionsX[idx], originPositionsY[idx], originPos[i].x-50, originPos[i].y+30, originPos[i].x+noise(originPos[i].x+800), originPos[i].y-40, originPos[i].x, originPos[i].y);
      popMatrix();
    }
    originPositionsX[idx] = originPos[i].x;
    originPositionsY[idx] = originPos[i].y;


    //char c = s.toCharArray();
    char currentChar = s.charAt(i);
    float w = textWidth(currentChar);

    arcLength+=w/2;
    float theta= PI+arcLength/rad;
    targetsPos[i].x =  cos(theta)*rad;
    targetsPos[i].y = sin(theta)*rad;
    originPos[i].lerp(targetsPos[i], 0.02);

    pushMatrix();
    rotate(PI/4);
    translate(originPos[i].x, originPos[i].y); 
    rotate(theta+PI/2);
    noFill();
    stroke(255, 0, 0);
    strokeWeight(2);
    rect(0, 0, 10, 10);
    fill(255);
    textAlign(CENTER, CENTER);
    text(s.charAt(i), 0, 0);
    //x= x+textWidth(c[i]);
    popMatrix();
    arcLength+=w/2;
  }
}
//draw

// =================================================================================
PVector [] chosenPos (int count) {
  PVector [] originPos = new PVector[count];
  for (int i = 0; i<s.length(); i++) {
    originPos[i]= new PVector(0, 0);
    //println(s.length());
  }
  return originPos;
}

// =================================================================================

int[] arrange(String s, int [] order) {

  int[] result;// value to return: index of each char 
  int len1=0;// total length of the words
  // split
  String []st; // split String
  st = split(s, ' ');
  // build an array newArrayWords to keep track of letter positions 
  OneWord []newArrayWords = new OneWord [st.length]; 
  int j=0; 
  for (int i=0; i<st.length; i++) {// for-loop over st
    newArrayWords[i] = new OneWord(st[i], j); // put this word into array newArrayWords
    j += st[i].length();
  }
  if (newArrayWords.length != order.length) { 
    println("Error +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
  }
  // prepare empty array 
  for (OneWord ow : newArrayWords) {
    len1+=ow.s1.length(); //increase len1 adding the String s1.length of each word inside the array ow (?!) so 3+3+3=9
    //println(len1);
  }
  result = new int [len1 + newArrayWords.length]; 
  // (len1 = s1 length = 9) + (the length of the array of Strings = 3) = 12 the total length of s spaces included 
  int i=0; 
  for (int i2=0; i2<order.length; i2++) {
    // for (OneWord ow : newArrayWords) {
    OneWord ow = newArrayWords[order[i2]];// give new array of words the order dictated by order[]

    for (int i_Count_Char=0; i_Count_Char < ow.s1.length(); i_Count_Char++) {

      result[ i ] = ow.arrayStart + i_Count_Char;// index of each char (arrayStart comes from the OneWord class)
      if (key=='1') {
        originPos[i].x=originPos[result[ i ]].x;
        originPos[i].y=originPos[result[ i ]].y;
        originPos[i].lerp(originPos[result[ i ]], 0.02);
      }
      i++;//incresae index of result
    }
    result[ i ] = -1;// if char ==' ' increase index i
    i++;
  }

  return result;
}// func 


// =================================================================================

void keyReleased () {
  if ( key=='0') {
    int[ ]order1 = new int []{0, 1, 2};
    arrange("all for one", order1);

    //println(order3);
    println(arrange("all for one", order1));
  } else if (key=='1') {
    int[ ]order2 = new int []{2, 1, 0};
    arrange("all for one", order2);
    println(arrange("all for one", order2));
  }
}

// =================================================================================
// classes 

class OneWord {

  String s1; 
  int arrayStart;

  // constr 
  OneWord (String s1_, int pos_) {
    s1         = s1_;
    arrayStart = pos_;
  }// constr 
  //
}//class 

class Letter { 
  char letter; // the letter 
  float x, y, r, gx, gy;

  Letter(float _x, float _y, char _l, float _r) {

    x = _x;
    y = _y;
    letter=_l;
    r=_r;
  }
  // constr
}