# Drawing a font "in code" - AxiDraw + Processing

**URL:** <https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344>\
**Category:** Libraries\
**Created:** [March 3, 2020, 10:22am UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344 "2020-03-03T10:22:47Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![AndreasRef](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/andreasref/32/133_2.png) [@AndreasRef](https://discourse.processing.org/u/AndreasRef)\
**Post date:** [March 3, 2020, 10:22am UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/1 "2020-03-03T10:22:47Z")

</div>

I am working with the [AxiDraw](https://www.axidraw.com/) penplotter and want to interactively draw text using Processing as the interface.

For fonts I am running into trouble, since the way I communicative with [AxiDraw through Processing](https://github.com/evil-mad/AxiDraw-Processing) only lets me specify coordinates for it to move to, which makes writing text a bit tricky…

Any ideas for workarounds?  
I am looking into getting the outlines of the fonts like they do in the Generative Design Book [http://www.generative-gestaltung.de/1/P\_3\_2\_1\_01](http://www.generative-gestaltung.de/1/P_3_2_1_01) and the Geomerative library [https://github.com/rikrd/geomerative](https://github.com/rikrd/geomerative), but it gives me twice the number of key points needed, even for “thin” fonts that look like they are drawn with a single line. This make the AxiDraw draw the font twice, and I cannot find any real system in the way the points are organised.

Another idea might be to design a font from coordinates myself, but that would be my last resort… It would be very time consuming and also not give me the aesthetics I am looking for.

To sum up, I guess my question is something like this:

**How do I go from a font to a set of specific coordinates that I can connect in order to draw the font in code?**

---

<div class="post-metadata">

**Author:** ![AndreasRef](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/andreasref/32/133_2.png) [@AndreasRef](https://discourse.processing.org/u/AndreasRef)\
**Post date:** [March 3, 2020, 10:50am UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/2 "2020-03-03T10:50:52Z")

</div>

Here is my (failed) attempt using geomerative and a screenshot showing the double points.

```auto
import geomerative.*;
RFont font;
String myText = "help";

void setup() {
  size(640, 480);  
  RG.init(this);
  font = new RFont("Eng_VandLine.ttf", 250, RFont.LEFT);
  RCommand.setSegmentLength(20);
  RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
}

void draw() {
  background(255);
  RGroup grp;
  grp = font.toGroup(myText);
  grp = grp.toPolygonGroup();
  RPoint[] pnts = grp.getPoints();

  translate(20, 320);
  drawUsingLines(pnts);
}

void drawUsingLines(RPoint[] pnts) {
  fill(255, 0, 0);
  beginShape();
  for (int i = 0; i < pnts.length-1; i++ ) {    
    vertex(pnts[i].x, pnts[i].y);   
    text(i, pnts[i].x, pnts[i].y);
  }
  noFill();
  endShape();
}

```

 ![Screenshot 2020-03-03 at 11.48.30](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/db32cfaf2455dcad2e3e6313ec056490b447f9ab.png)

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [March 3, 2020, 3:22pm UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/3 "2020-03-03T15:22:18Z")

</div>

Hi @AndreasRef,

I can’t run your code at the moment but it seems to me that no matter how thin the font you load is, Geomerative will always try to find the contour points around it.

It means that even if your font is 1 pixel wide you will still end-up with points corresponding to the edges of it (outer/inner, left/right, up/down). In your case edges are probably colliding hence all the points appearing at the same location (roughly).

Maybe you could try to cull the duplicate points, i.e removing points that are below a chosen threshold distance from another point.

```auto
int N = 1000;

void setup() {
  size(640, 480);  
  background(255);
  strokeWeight(3);
  
  ArrayList<PVector> points = new ArrayList<PVector>();
  
  for (int i = 0; i < N; i++) {
    points.add(new PVector(random(width), random(height)));
  }
  

  ArrayList<PVector> culledPoints = cull(points, 10); 
  
  for (PVector pt : culledPoints) {
    point(pt.x, pt.y);
  }
   
}

public ArrayList<PVector> cull(ArrayList<PVector>arr, float t) {

  // arr = array of points to cull 
  // t = threshold distance
  
  ArrayList<PVector> plist = new ArrayList<PVector>();
  plist.add(arr.get(0));
  
  for (PVector pt1 : arr) {
    boolean add = true;
    for (PVector pt2 : plist) {
      if (pt1.dist(pt2) < t) {
        add = false;
        break;
      }
    }
    if (add == true) {
        plist.add(pt1);
    }
  }
    
    return plist;
    
  }

```

Also is there a reason why you are grouping your text and getting the corresponding points in `draw()` rather than in `setup()` ?

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [March 3, 2020, 3:45pm UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/4 "2020-03-03T15:45:37Z")

</div>

You want the outline (so a big letter?) or one line (as in your image?)

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [March 3, 2020, 3:50pm UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/5 "2020-03-03T15:50:00Z")

</div>

See also [Straight Skeleton - or how to draw a center line in a polygon or shape?](https://discourse.processing.org/t/straight-skeleton-or-how-to-draw-a-center-line-in-a-polygon-or-shape/17208/8)

---

<div class="post-metadata">

**Author:** ![AndreasRef](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/andreasref/32/133_2.png) [@AndreasRef](https://discourse.processing.org/u/AndreasRef)\
**Post date:** [March 3, 2020, 10:21pm UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/6 "2020-03-03T22:21:46Z")

</div>

Oh, that is a really neat idea actually!  
I’m gonna try that tomorrow. Thanks so much for the suggestion and the code.

And no, there is no reason for doing this in `draw()`.

---

<div class="post-metadata">

**Author:** ![AndreasRef](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/andreasref/32/133_2.png) [@AndreasRef](https://discourse.processing.org/u/AndreasRef)\
**Post date:** [March 3, 2020, 10:23pm UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/7 "2020-03-03T22:23:45Z")

</div>

One line 🙂

---

<div class="post-metadata">

**Author:** ![AndreasRef](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/andreasref/32/133_2.png) [@AndreasRef](https://discourse.processing.org/u/AndreasRef)\
**Post date:** [March 5, 2020, 11:51am UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/8 "2020-03-05T11:51:30Z")

</div>

The suggestion from @solub got my a lot further 🙂

However, I am still facing some trouble: With letters like “i” and “j” it is important that no line is drawn between the dot over the letter (the “tittle”: [https://en.wikipedia.org/wiki/Tittle](https://en.wikipedia.org/wiki/Tittle)). On the other hand, some letters will have (joints/points of connections/stitches) where the points are close, but should still be drawn and not culled by duplicate points - and example is the lower right part of the letter “h”.

 ![Screenshot 2020-03-05 at 12.45.45](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/b/b98c4e0e40e1716b56b9e5a16c3c39df5e216411.png)

What would be the logic for correctly setting the values (in my system these are currently `fontSize, cullDist, segmentLength & minPointDistWhenDrawing`), so my system will work for different fonts of different sizes? Or am I doing it an a fundamentally wrong way?

Below is my code. You cannot run it unless you [download the font I am using](https://andreasref.github.io/diverse/font.zip) or replace it with another .ttf font. You can also [download the whole project as a zip here](https://andreasref.github.io/diverse/fontsBoilerplateCull.zip).

```auto
import geomerative.*;
RFont font;
String myText = "ifhj";

int fontSize = 200;
int cullDist = 4;
int segmentLength = 10;  
int minPointDistWhenDrawing = 15;

void setup() {
  size(840, 480);  
  background(255);
  RG.init(this);
  font = new RFont("Eng_VandLine.ttf", fontSize, RFont.LEFT);
  RCommand.setSegmentLength(segmentLength);
  RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
  noFill();

  textSize(8);
  RGroup grp;
  grp = font.toGroup(myText);
  grp = grp.toPolygonGroup();
  RPoint[] pnts = grp.getPoints();

  ArrayList<PVector> plist = convertRPointsToArrayList(pnts);
  ArrayList<PVector> culledPoints = cull(plist, cullDist);

  translate(50, 220);
  drawUsingLinesMinSegment(culledPoints);
}

void drawUsingLinesMinSegment(ArrayList<PVector>arr) {
  beginShape();
  for (int i = 0; i < arr.size()-1; i++ ) {
    if (dist(arr.get(i).x, arr.get(i).y, arr.get(i+1).x, arr.get(i+1).y) < minPointDistWhenDrawing) { //Is this the right way to do it?
      vertex(arr.get(i).x, arr.get(i).y);
      push();
      fill(255, 0, 0);
      text(i, arr.get(i).x, arr.get(i).y);
      pop();
    } else {
      endShape();

      push();
      fill(255, 0, 0);
      text(i, arr.get(i).x, arr.get(i).y);
      pop();
      beginShape();
    }
  }
  noFill();
  endShape();
}

public ArrayList<PVector> cull(ArrayList<PVector>arr, float t) {
  // arr = array of points to cull 
  // t = threshold distance

  ArrayList<PVector> plist = new ArrayList<PVector>();
  plist.add(arr.get(0));

  for (PVector pt1 : arr) {
    boolean add = true;
    for (PVector pt2 : plist) {
      if (pt1.dist(pt2) < t) {
        add = false;
        break;
      }
    }
    if (add == true) {
      plist.add(pt1);
    }
  }
  return plist;
}

public ArrayList<PVector> convertRPointsToArrayList(RPoint[] pnts) {
  ArrayList<PVector> plist = new ArrayList<PVector>();
  for (int i = 0; i < pnts.length-1; i++ ) {
    plist.add(new PVector(pnts[i].x, pnts[i].y));
  }
  return plist;
}

```

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [March 6, 2020, 3:54pm UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/10 "2020-03-06T15:54:32Z")

</div>

> [@AndreasRef](#):
>
> Or am I doing it an a fundamentally wrong way?

I wouldn’t say that but in my opinion it is not the cleanest way to achieve that thin look you are looking for.

I personnaly would opt for the Straight Skeleton approach suggested above but it is a long and tricky process that can be daunting, especially when dealing with fonts. Actually the author of the Geomerative library himself had planned to implement this algorithm (most likely to retrieve the _medial axis_ of a letter) but never went ahead, probably for these very reasons.

Nevertheless, the best approach would probably consist in:

- computing the Straight Skeleton of a polygonized letter
- pruning the branches to retrieve the medial axis
- smoothening the axis or approximating it with piecewise cubic Bezier curves

Your workaround, however, has the advantage of being quite simple but requires to address all the edge cases manually. That is, making a connection between 2 consecutive points:

- unless their distance is equal to the distance from a dot (the “tittle”) to its corresponding glyph (letter “i” and “j”)

- if their distance is below a maximum threshold

These parameters will vary depending on the font size and the culling threshold.

Example: with a font size of `340` and culling threshold of `6`:

- the distances between the dot (tittle) and the glyph for letter “i” and “j” are `43` and `63`
- the distance between the 2 distant points on the back of the letter “d” is `70`
- the maximum connection distance between 2 consecutive points is `58`

```auto
add_library('geomerative')

fsize = 340

def setup():
    size(1900, 480, P2D)
    background('#FFFFFF')
    fill(255, 30, 30)
    strokeWeight(2)
    smooth(8)
    
    RG.init(this)
    font = RFont("Eng_VandLine.ttf", 300, RFont.LEFT)
    txt = "abcdefghij"

    grp = font.toGroup(txt)
    grp.translate(40, 340)
    pts = cull(grp.getPoints(), 6)
    

    for i, (p1, p2) in enumerate(zip(pts, pts[1:])):
        
        #rounded distance bewteen 2 consecutive points
        d = round(p1.dist(p2)) 
        
        #display index
        text(i, p1.x - 30, p1.y)
               
        # do not draw line if d = distance between the dot (tittle) and the glyph for letter "i" and "j" 
        if d == 43 or d == 63: 
            continue
        
        # draw line if d = distance between the 2 distant points on the back of the letter "d" 
        elif d == 70: 
            line(p1.x, p1.y, p2.x, p2.y)
            continue
            
        # draw line if d < maximum connection distance between 2 consecutive points
        elif d < 58: 
            line(p1.x, p1.y, p2.x, p2.y)

def cull(arr, t):
        
    cpts = [arr[0]]
    for pt in arr:
        for cpt in cpts:
            if pt.dist(cpt) < t: 
                break
        else:
            cpts.append(pt)
            
    return cpts

```

 ![Annotation 2020-03-06 153302](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/8/8e4640a4e21520fe2e9e8a8030ace99a17b1066b.png)  
 ![Annotation 2020-03-06 170544](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/b/bd34743c524999caf5c75b0c1ee0aaba013bc00b.png)  
 ![Annotation 2020-03-06 170651](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/e/e0e5060d514f9aabb918fa92647df6c1b8b15aaf.png)

---

<div class="post-metadata">

**Author:** ![AndreasRef](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/andreasref/32/133_2.png) [@AndreasRef](https://discourse.processing.org/u/AndreasRef)\
**Post date:** [April 20, 2020, 11:39am UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/11 "2020-04-20T11:39:50Z")

</div>

For anybody interested in this topic, I just discovered a really nice cross-platform library (with a example for Processing):  
[https://skeleton-tracing.netlify.app/](https://skeleton-tracing.netlify.app/)

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [September 10, 2020, 12:38am UTC](https://discourse.processing.org/t/drawing-a-font-in-code-axidraw-processing/18344/12 "2020-09-10T00:38:05Z")

</div>

I just accidentally rediscovered the **skeleton-tracing** library that you previously linked the demo for above, along with its Processing example:

> <https://github.com/LingDong-/skeleton-tracing/blob/master/java/ProcessingExample/ProcessingExample.pde>

It seems to work well with still images, webcam, fonts et cetera.

Despite the name, it isn’t specialized for detecting human poses – it will create a fantastical “skeleton” from a human silhouette. But it is _extremely_ versatile.
