Text on a free line (SVG)

Hi, I am almost a newbie on Processing.

I found this tutorial where it is also explained how to draw a text over a circle: Strings and Drawing Text / Processing.org .

My questions are:

  • is it possible to draw a text on a line different from a circle (e.g. a spiral or a free line drawn by myself) and that the line is hidden after putting the text on?

  • can the text be automatically adapted and sized on the length of the line in order that, if I put a text of 1000 characters (e.g.), this fits exactly?

Thanks in advance

Errel

Hi @humus,

Glad to see you back :wink:

When drawing a text along a path, the letter is always perpendicular to the tangent on that curve. (for the circle case, it’s directed toward the center)

Then it depends how your curve/line is constructed, either with beginShape and vertex() or curveVertex() (it might be difficult to sample points on it) or with bezier curves where you can find the tangent on a curve with bezierTangent() (check the second example in the docs).

Yes, you need to divide the length of your curve by the number of characters to display, then adapt the font size so it matches the right step.

Let us know if you have more questions!

2 Likes

humus, is this what you’re looking to do?
http://www.generative-gestaltung.de/1/P_2_3_3_01

You can download the code for Processing 3.x. There may be a problem with variables in size(), so change those to whatever numbers you’d like.

Hi Perry, many thanks for your reply and sorry for the delay !

The code is really interesting! I tried to activate the section where to set a background image but it doesn’t work: why?
Because I would like to use the background image as a guideline to draw by the text. In relation with this aspect, do you think that it should be possible the entire text to fit exactly the background guidelines not manually but automatically? And, with some code, the sketch recognize the number of characters of the text in order that the text was not repeated after ending?

Thanks
Best regards
Humus

Thanks Joseph, sorry for the delay. As I wrote to Perry, I would like to use a background path line, distribute automatically the text by optimizing it on that path (in size and distance from character to character) and, than, cancel the original path line in order that it only remains the text as the line path.
Than, save this as a image.

Thanks
Best regards
Humus

Hi @humus,

This is a little bit confusing, can you elaborate on that? Can you post the image you want to use?

1 Like

Hi Joseph, just as an example, here is an image. I simply would live to substitute the black line of the woman face with a text that follows the same path as the black line… thanks

Hi @humus,

If it’s an SVG you can read it with Processing and extract the path lines. Then use them to display text.
If it’s one continuous line it might help thought :wink:

2 Likes

Ok thanks Joseph, I will try and I will come back (very very probably :relaxed:)

But how to display the text instead of the line path?

1 Like

can you post the svg for this?


Step 1:

retrieve PVectors from a SVG and display every 22nd PVector as a letter “a”

I used a free shape https://freesvg.org/tocantins-region-vector-map-drawing

It’s a bit tricky since it contains a child and a sub-child and only then the vertices


// https://processing.org/tutorials/pshape
// https://freesvg.org/tocantins-region-vector-map-drawing


PShape svg;

void setup() {
  size(940, 1360, P2D);
  svg = loadShape("map_of_Tocantins.svg");

  println(svg.getVertexCount());
  println(svg.getChildCount());

  PShape svg2 = svg.getChild(0); // id  on svg file
  println(svg2.getChildCount());

  PShape svg3 = svg2.getChild(0); // id  on svg file
  println(svg3.getVertexCount());

  for (int i = 0; i < svg3.getVertexCount(); i++) {
    PVector v = svg3.getVertex(i);
    v.x += random(-1, 1);
    v.y += random(-1, 1);
    //  ellipse(v.x, v.y, 12, 12);
    if (i%22==0) {
      text ("a", v.x, v.y);
      //  svg2.setVertex(i,v.x,v.y);
    }
  }
}

void draw() {
  // background(255);
  // shape(svg);
}
//


Step 2

unsuccessfully attempting to rotate the individual letter so that is perpendicular to the line


// https://processing.org/tutorials/pshape
// https://freesvg.org/tocantins-region-vector-map-drawing

PShape svg;
String myText="The sketch has been resized from 940?1360 to 940?1061 by the window manager.";

float prevX=-1100, prevY;

void setup() {
  size(940, 1060, P2D);
  svg = loadShape("map_of_Tocantins.svg");

  println(svg.getVertexCount());
  println(svg.getChildCount());

  PShape svg2 = svg.getChild(0); // id  on svg file
  println(svg2.getChildCount());

  PShape svg3 = svg2.getChild(0); // id  on svg file
  println(svg3.getVertexCount());

  translate(300, 0);
  int k=0;
  for (int i = 0; i < svg3.getVertexCount(); i++) {

    PVector v = svg3.getVertex(i);

    float angle=0 ;

    //v.x += random(-1, 1);
    //v.y += random(-1, 1);
    if (k==0)
      ellipse(v.x-19, v.y, 12, 12);
    if (i%22==0) {
      if (prevX!=-1100) {
        PVector prev = new PVector(prevX, prevY);
        angle = 20*PVector.angleBetween(v, prev);
        angle += TWO_PI / 4.0;
        print(angle, " ");
      }//if

      pushMatrix();
      translate( v.x, v.y);
      rotate(angle);
      text (myText.charAt(k%myText.length()), 0, 0);
      popMatrix();

      k++;
    }//if

    if (i%50==0) {
      prevX=v.x;
      prevY=v.y;
    }
  }//for
}//func

void draw() {
  // background(255);
  // shape(svg);
}
//

1 Like

This approach works for the angles:

    float x = path.getVertexX(i); 
    float y = path.getVertexY(i); 
    PVector curr = new PVector(x, y);      
 
    x = path.getVertexX(i+1); 
    y = path.getVertexY(i+1); 
    PVector next = new PVector(x, y);       
    
    float angle = atan2(next.copy().sub(curr).y,  // Need to copy() otherwise it modifies next
                        next.copy().sub(curr).x); // Same as above                 
    println(degrees(angle));

Using the sine wave example from the PShape tutorial to create vertices to use for text:

image

The bottom two sine waves were spaced along the curve.

Applied to the map:

:)

1 Like

Hi Perry,

In this code, I can’t load an image in background: why?

Thanks

/*
// load an image in background
PImage img = loadImage(selectInput(“select a background image”));
image(img, 0, 0, width, height);
*/

Hi glv, thanks for your reply. So, finally, which is the complete code to do this? Thanks

That block of code is commented out, but I assume that it’s not so in your .pde file. the selectInput requires a prompt string, which you have, but it also needs a callback function to handle the result, which you don’t have. If you feed loadImage() a file path from within draw(), you’ll get your image loaded.