How to sort words alphabetically from a String?

Thank you very much dear @jeremydouglass I will check out this exemple asap. Thank you for your precious help ! Best wishes
L

Very impressive thread and very impressive project with nice visuals here!

And great how much effort Jeremy puts into this. Thank you!

2 Likes

Dear Chrisir,
Thank you so much for your compliments even if I feel I don’t deserve them.
Jeremy is amazingly patient and dedicated and he puts so much effort into this project
that I really feel very much indebted and thankfull for his great help and also ashame not to understand better and faster what he spends a lot of time to explain me…
Hope I 'll get it at the end and that this project will come true. All volunteers on this forum are great you included of course and I don’t miss to quote your names once I show my projects, I owe you a lot. Thanks! :pray: :pray: :pray: :heart: :heart: :heart:

1 Like

@lolonulu hope you are well – were you able to make any progress on this using the example that I shared?

2 Likes

Dear @jeremydouglass,
Thank you for your message and for taking care so much. I played a bit with the example you’ve sent me yersteday, thank you very much for your help as usual. Unfortunately I worked today and couldn’t apply the example to my sketch, but I will tomorrow! I’ll let you know…

1 Like

Dear @jeremydouglass,
Sorry for not replying before, but I had a lot of work.
In my main sketch when I use lerp(), the y positions act strangely and though I’ve been looking for a solution, I haven’t found a way to solve the problem…

1rst PIC without lerp() :

BECKETT

2nd PIC with lerp() :

BECKETT_LERP

Since then I rewrote the sketch and I thought about using lerp on the char instead of the words, but it turns to be difficult with hundreds of letters… But here at least lerp() works smoothly. What would be then the good solution to use a smooth lerp() function over the words please ?!! Thank you very much in advance. Best wishes,
L

String[] words;    // a list of words
PVector[] pos;     // where each word is
PVector[] targets; // where each word is going
float arcLength;
float rad =200;
float w;
float theta;
String message;
String text;
int index;
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ, ";
String [] wordsList;
char [] c;
float [] originPositionsX = new float [alphabet.length()];
float [] originPositionsY = new float [alphabet.length()];

void setup() {
  size(1000, 1000);
  stroke(128);
  textSize(20);
  words = new String[] {
    "Lorem", "rolem"};

  message = join(words, " ");
  wordsList =split(join(words, " "), " ");
  pos = randomPos(11);
  targets = randomPos(11);
  textAlign(CENTER);
  c = new char [message.length()];
  for (int i=0; i<message.length(); i++) {
    c[i]=message.charAt(i);
  }
  for (int i=0; i<words.length; i++) {
    words[i] =words[i].replaceAll(",", "\\$*");
    println(words[i]);
  }
}

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

  // targets
  for (int i = 0; i <message.length(); i++) {

    char currentChar = message.charAt(i);
    float w = textWidth(currentChar);
    arcLength +=w/2+15;
    float theta = PI+arcLength/rad;
    targets[i].x = cos(theta)*rad;
    targets[i].y = sin(theta)*rad;
  }
  for (int i = 0; i <message.length(); i++) {
    if (i <= words[0].length()) {
      rad=100;
    } else if (i > words[1].length()) {
      rad=100+50;
    }
    char currentChar = message.charAt(i);
    float w = textWidth(currentChar);
    arcLength +=w/2+15;
    float theta = PI/2+arcLength/rad;
    targets[i].x = cos(theta)*rad;
    targets[i].y = sin(theta)*rad; 
    pos[i].lerp(targets[i], 0.02);
    pushMatrix();
    fill(255, 0, 0, 64);
    //rect(targets[i].x, targets[i].y, 10, 10); 

    popMatrix();
  }
  // draw lines
  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, 200);
      strokeWeight(0.5);
      rect(pos[i].x, pos[i].y, 10, 10); 
      bezier(originPositionsX[index], originPositionsY[index], pos[i].x-50, pos[i].y+20, pos[i].x+80+noise(pos[i].x+800), pos[i].y-80, pos[i].x, pos[i].y);
      popMatrix();
    }
    originPositionsX[index] = pos[i].x;
    originPositionsY[index] = pos[i].y;
  }

  // draw words
  for (int i=0; i<message.length(); i++) {
    char currentChar = message.charAt(i);
    float w = textWidth(currentChar);
    arcLength=w/2+10;
    float theta = PI+arcLength/rad;
    pushMatrix();
    translate(pos[i].x, pos[i].y); 
    rotate(theta-PI);
    fill(255, 0, 0);
    textSize(30);

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

// return a list of random positions on the canvas
PVector[] randomPos(int count) {
  PVector[] pos = new PVector[count];
  for (int i=0; i<message.length(); i++) {
    pos[i] = new PVector(0, 0);
  }
  return pos;
}

void mouseReleased() {

  reorder(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  targets = randomPos(message.length());
}

void keyReleased() {
  if (key=='0') {
    reorder(0, 5, 9, 3, 4, 2, 10, 8, 7, 6, 1);
  } else if (key=='1') {
    reorder(10, 0, 8, 2, 7, 9, 3, 1, 4, 5, 6);
  } else if (key=='2') {
    reorder(1, 2, 5, 10, 4, 9, 6, 0, 7, 8, 3);
  } else if (key=='3') {
    reorder(0, 1, 10, 4, 3, 5, 7, 9, 8, 6, 2);
  } else if (key=='4') {
    reorder(9, 2, 0, 3, 4, 10, 1, 6, 5, 8, 7);
  } else if (key=='5') {   
    //c = sort(c);
    reorder(8, 3, 2, 4, 10, 6, 1, 0, 9, 5, 7);
  } else if (key=='6') {   
    reorder(7, 6, 2, 1, 4, 9, 5, 10, 0, 8, 3);
  }
}

void reorder(int... idx) {
  char[] nw = new char[message.length()];
  nw[0]=c[idx[0]];
  nw[1]=c[idx[1]];
  nw[2]=c[idx[2]];
  nw[3]=c[idx[3]];
  nw[4]=c[idx[4]];
  nw[5]=c[idx[5]];
  nw[6]=c[idx[6]];
  nw[7]=c[idx[7]];
  nw[8]=c[idx[8]];
  nw[9]=c[idx[9]];
  nw[10]=c[idx[10]];
  c = nw;

  PVector[] np = new PVector[message.length()];
  np[0]=pos[idx[0]];
  np[1]=pos[idx[1]];
  np[2]=pos[idx[2]];
  np[3]=pos[idx[3]];
  np[4]=pos[idx[4]];
  np[5]=pos[idx[5]];
  np[6]=pos[idx[6]];
  np[7]=pos[idx[7]];
  np[8]=pos[idx[8]];
  np[9]=pos[idx[9]];
  np[10]=pos[idx[10]];
  pos = np;
}

I just examined the code that you shared – not the one in your screenshots, but this:

Screen Shot 2020-07-29 at 12.12.31 PM

Your character-based resort lerping seems to be working fine. However, there are character positioning issues. The rectangles look fine, but the character alignment and spacing is awkward.

Screen Shot 2020-07-29 at 12.13.36 PM

I think this is due to a combination of:

  1. not vertically centering your characters, and
  2. not using a fixed-distance font

I’d recommend making these changes to setup:

  textFont(createFont("Monaco", 32));
  textAlign(CENTER, CENTER);

Screen Shot 2020-07-29 at 12.20.10 PM

1 Like

Thank you very much @jeremydouglass thanks to you it looks much better, but there is an extra square standing for the comma. I tried to remove it but it stays on the screen (even if not in the console). I use this method:

for (int i=0; i<words.length; i++) {
    words[i] =words[i].replaceAll(",", "\\$*");
  }

The angle of each char is akward too! : :sob:
Do you think I should lerp on each char? Because in the original there are hundreds of letters!!! SORRY :confounded: Thank you for your great help

Dear @jeremydouglass,
I’ve solved the angle issue for each char, but I still get an extra rectangle corresponding to the trailing comma between the strings despite the fact I remove it using the appropriate method ?! Is there any way to remove it?! More important: is there a way to lerp between strings keeping track of the positions and angles for each char!!! Sorry I try my best but I lack knowledge+experience! Thanks a lot… Best, L

I’m sorry, maybe I don’t understand this question, or what the amount of letters has to do with anything. You are positioning letters on the screen, then repositioning them. You want each letter to move to a new position, right? So, when you compute that position, you use lerp – for 4, or 40, or 40,000 positions. Isn’t that the whole idea?

1 Like

In your example sketch you have three things – words, message, and wordList. They look like this:

words: {“Lorem”, “rolem”}
join words with a space:
message: “Lorem rolem”
join words with a space, then split on spaces:
wordList: {“Lorem”, “rolem”}

When you draw word characters, you use message. It has a space in it, because you put it there. When you draw each character, one of the characters is a space.

In your draw lines loop, you might want to have something like “if the character is a space, continue”. You could also do that in your draw character text loop.

1 Like

Thank you ver much for your answers Jeremy. I mean that in this new sketch I manage to use the lerp method to change each letter position but in my main sketch I change each word position but don’t manage to use the lerp method!! And if I need to write an array of 100 string positions for words it’s better than one with 1000 char positions!!:crazy_face: The question is if I want to use lerp over strings (100 positions) and ellipse+bezier curves chat should I do?! Thanks a lot

Sorry for this question but thank you very much for your very clear answer and your patience…

2 Likes

I think you may be confused about your main sketch. I can see that you are drawing the characters one at a time, each with their own positions (and not one word at a time with a word position), because they are curved. For example, the word “folly” is curved – each letter has its own position.

1 Like

oh I see, I mean that Imove the letter’s position but that the whole word with its letters move together. When the word folly move all its letters move together to a new location where they are also curved.But I can’t use lerp since it mess up all the positions?!

In the other sketch each letter move independantly one from the other smoothly and there I can use lerp. But Since I have 867 letters I won’t write 867 times, nw[0]=words[idx[0]];?!

void reorder(int... idx) {
  String[] nw = new String[words.length];
  nw[0]=words[idx[0]];
  nw[1]=words[idx[1]];
  nw[2]=words[idx[2]];
  nw[3]=words[idx[3]];
  nw[4]=words[idx[4]];
  words = nw;

  PVector[] np = new PVector[pos.length];
  np[0]=pos[idx[0]];
  np[1]=pos[idx[1]];
  np[2]=pos[idx[2]];
  np[3]=pos[idx[3]];
  np[4]=pos[idx[4]];
  pos = np;
}

There is certainly a way to use the lerp function in my main sketch without messing up the positions, but I don’t find the solution…Thank you very much for your help Jeremy

If you have some words:

“one for all”

[0, 1, 2]

then their characters:

['o', 'n', 'e', ' ', 'f', 'o', 'r', ' ', 'a', 'l', 'l']

could be identified by word id:

[0, 0, 0, -1, 1, 1, 1, -1, 2, 2, 2]

In fact, each letter could have an id based on initial position:

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

so to change the words around, you need a new order of ids:

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

= “all for one”

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);
}
2 Likes

Dear @jeremydouglass,
It looks wonderful !! Exactly the solution I couldn’t find. Thanks a million, I’ll try to integrate it to my sketch asap! Thanks for your generosity and great dedication I feel very lucky and grateful. Best wishes, L

2 Likes

Dear @jeremydouglass,

Thank you very much again, but not sure I understand everything. When you wrote :

Blockquote

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

Blockquote

So the function should look like this?

int targetPositions(String s, intidx) {

  • String split in a list [0,1,2]

  • PVector list of the positions of the words into the String list

  • List of int origins + list of char [s.length()]

  • Pvector list of the positions of the letters

  • return origins the int of the letter id order
    }
    Sorry to be so slow to respond…
    Thanks a lot for your help.
    Best wishes,

L

Dear @jeremydouglass,

I have some questions: how come that blank space return -1?!
I wonder if I should split the String into substrings ‘one’, ‘for’, ‘all’?
Thank you very much for your help and patience.
Best wishes,
L

Dear @jeremydouglass,
I hope you are fine. I wanted to ask you a question: is posFromID is supposed to be a method?
How in this method can I pass the id letter order?!
Thanks a lot in advance for your answer. Sorry to bother you again with this old story, but I don’t find the answer…
Best,
L