How to add methods to imported library or class

Wondering if there’s a basic technique to add/overwrite methods to an imported library and class instance? Maybe this is possible with extends/implements, which I don’t totally understand…

I’m messing with the Hershey font library, and initializing it like so:

import de.ixdhof.hershey.*;
HersheyFont hf;

void setup()
{
  size(500, 500, P3D);
  hf = new HersheyFont(this, "rowmans.jhf");
}

It has a built in text rendering:

hf.textSize(50);
hf.text("hello", 0, 0);

I’m interested in either overriding the hf.text() method or adding a new one, ie. hf.textCustom(). That custom function would then call another custom function, that uses built-in functions from the original library/class.

Curious if there’s a smooth way to do just that (add method while referring to others) or is it necessary to have custom version of library/class from the start?

1 Like
static final class MyOwnHersheyFont extends HersheyFont {
  MyOwnHersheyFont(final PApplet p, final String font) {
    super(p, font);
  }

  @Override void text(final String msg, final float x, final float y) {
    super(msg, x, y);
  }
}
2 Likes

Curious when/how this makes reference to the original HersheyFont class, in order to still make use of other functions from the library? Realized I don’t need to change the hf.text() function, but rather the draw_character() function that it uses within… nevertheless, there’s vars/functions it calls within the library.

More detail of what I’m trying to do. The library has the following function to render text to screen:

private void draw_character(int c)
{
	int max_y = -1000;
	int min_y = 1000;

	String h = hershey_font[c - 32 ];

	int start_col = h.indexOf(" ");

	int vertices_length = Integer.parseInt(h.substring(start_col+1, start_col+3).trim());

	int h_left = hershey2coord(h.charAt(start_col+3));
	int h_right = hershey2coord(h.charAt(start_col+4));
	float h_width = h_right - h_left * hfactor;

	String[] h_vertices = h.substring(start_col+5, h.length()).replaceAll(" R", " ").split(" ");

	for (int i=0; i<h_vertices.length; i++)
	{
		parent.beginShape(parent.LINES);
		for (int j=2; j<h_vertices[i].length (); j+=2)
		{
			float hx0 = hershey2coord(h_vertices[i].charAt(j-2)) * hfactor;
			float hy0 = hershey2coord(h_vertices[i].charAt(j-1)) * hfactor;
			parent.vertex(hx0, hy0);
			float hx1 = hershey2coord(h_vertices[i].charAt(j)) * hfactor;
			float hy1 = hershey2coord(h_vertices[i].charAt(j+1)) * hfactor;
			parent.vertex(hx1, hy1);
		}
		parent.endShape(parent.CLOSE);
	}
	parent.translate(h_width + 5 * hfactor, 0);
}

I just want to replace the drawn functions (beginShape(), vertex(), endShape()) with a custom class, (xy.beginShape(), xy.vertex(), xy.endShape()), which would look like so:

void draw_character(final int c) {
    //super(msg, x, y);
	int max_y = -1000;
	int min_y = 1000;

	String h = hershey_font[c - 32 ];

	int start_col = h.indexOf(" ");

	int vertices_length = Integer.parseInt(h.substring(start_col+1, start_col+3).trim());

	int h_left = hershey2coord(h.charAt(start_col+3));
	int h_right = hershey2coord(h.charAt(start_col+4));
	float h_width = h_right - h_left * hfactor;

	String[] h_vertices = h.substring(start_col+5, h.length()).replaceAll(" R", " ").split(" ");

	for (int i=0; i<h_vertices.length; i++) {
      xy.beginShape(); // parent.LINES
      for (int j=2; j<h_vertices[i].length (); j+=2) {
      	float hx0 = hershey2coord(h_vertices[i].charAt(j-2)) * hfactor;
      	float hy0 = hershey2coord(h_vertices[i].charAt(j-1)) * hfactor;
      	xy.vertex(hx0, hy0);
      	float hx1 = hershey2coord(h_vertices[i].charAt(j)) * hfactor;
      	float hy1 = hershey2coord(h_vertices[i].charAt(j+1)) * hfactor;
      	xy.vertex(hx1, hy1);
      }
      xy.endShape();
  }
  translate(h_width + 5 * hfactor, 0);
}

… this is for implementing single line fonts with XYscope - thought it best to have user include existing HersheyFont library (and overrule it) rather than copying elements from library I need (maybe this is better?).

1 Like

Never heard of that library! This is as far as I can help based on what you have posted so far: :flushed:

import de.ixdhof.hershey.HersheyFont;
import xyscope.XYscope;

static final class MyOwnHersheyFont extends HersheyFont {
  final XYscope xy;

  MyOwnHersheyFont(final XYscope scope, final PApplet p, final String font) {
    super(p, font);
    xy = scope;
  }

  @Override void draw_character(final int c) {
  }
}
2 Likes

@GoToLoop – Sorry for the lag in checking this, I didn’t get an email notification of your reply…

Thanks for the updated snippet – which looks closer to my needs, however when I try it out, I’m getting the following error that’s over my head on the attempt to Override the draw_character() function:

The method draw_character(int) of type hershey_font_test_override.MyOwnHersheyFont must override or implement a supertype method

Perhaps since both libs are GNU – it’s simplest to just embed the lib/class and modify for my purpose (with proper attribution). Nevertheless, still curious of how it would work in Java to add onto imported lib while making reference to another lib.

Here’s the complete code that I’m testing out. This has a copy + paste of the library (which isn’t too large of a class) – at the bottom of the code (instead of importing library, commented out) so I could add two functions (Hershey Fonts found here):

import xyscope.*; 
XYscope xy; 
import ddf.minim.*;  

//import de.ixdhof.hershey.*;
HersheyFont hf;
String txt = "hello";

void setup() {
  size(500, 500, P3D);
  xy = new XYscope(this); 

  hf = new HersheyFont(this, "meteorology.jhf");
}

void draw() {
  background(0);
  xy.clearWaves(); 

  push();
  stroke(0);

  // draw via custom override of Hershey Font lib:
  hf.textSize(50);
  hf.textXY(txt, mouseX, mouseY); // custom version of hf.text() below

  // draw via grabbing the shape from Hershey Font lib:
  translate(width/2, height/2);
  PShape f = hf.getShape(txt);
  int children = f.getChildCount();
  for (int i = 0; i < children; i++) {
    PShape child = f.getChild(i);
    int total = child.getVertexCount();
    beginShape();
    for (int j = 0; j < total; j+=2) {
      PVector v = child.getVertex(j);
      PVector v2 = child.getVertex(j+1);
      xy.line(v.x, v.y, v2.x, v2.y);
    }
    endShape();
  }
  pop();

  xy.buildWaves(); 
  xy.drawWaveform(); // wavetable
  xy.drawXY(); // scope viewer
}

void keyPressed() {
  if (keyCode >= 32 && keyCode <= 90) {
    txt += key + "";
  }
  if (keyCode == 8) {
    txt = "";
  }
}


public class HersheyFont {

  // myParent is a reference to the parent sketch
  PApplet parent;

  public final static String VERSION = "1.0.0";


  /**
   * a Constructor, usually called in the setup() method in your sketch to
   * initialize and start the library.
   * 
   * @example Hello
   * @param theParent
   */

  String hershey_font[];
  int hheight = 21;
  float hfactor = 1;

  public HersheyFont(PApplet theParent, String fontfile) {
    parent = theParent;

    System.out.println("HersheyFont 1.0.0 by Michael Zšllner http://ixd-hof.de");

    String [] hershey_font_org;

    //if (fontfile.indexOf(".jhf") != -1)
    hershey_font_org = parent.loadStrings(fontfile);

    String hershey_font_string = "";

    for (int i=0; i<hershey_font_org.length; i++)
    {
      String line = hershey_font_org[i].trim();
      if (line.charAt(0) >= 48 && line.charAt(0) <= 57)
        hershey_font_string += line + "\n";
      else
      {
        hershey_font_string = hershey_font_string.substring(0, hershey_font_string.length()-1) + line + "\n";
      }
    }
    hershey_font = hershey_font_string.split("\n");
  }

  public void textSize(float size)
  {
    hfactor = size/hheight;
  }

  public PShape getShape(String s)
  {
    int swidth = 0;
    for (int i=0; i<s.length (); i++)
    {
      swidth += get_character_width(s.charAt(i));
    }

    float pos_x = 0;
    PShape sh = parent.createShape(parent.GROUP);

    for (int ss=0; ss<s.length (); ss++)
    {
      PShape shc = parent.createShape();
      char c = s.charAt(ss);
      String h = hershey_font[c - 32 ];

      int start_col = h.indexOf(" ");

      int vertices_length = Integer.parseInt(h.substring(start_col+1, start_col+3).trim());

      int h_left = hershey2coord(h.charAt(start_col+3));
      int h_right = hershey2coord(h.charAt(start_col+4));
      float h_width = h_right - h_left * hfactor;

      String[] h_vertices = h.substring(start_col+5, h.length()).replaceAll(" R", " ").split(" ");

      for (int i=0; i<h_vertices.length; i++)
      {
        shc.beginShape(parent.LINES);
        for (int j=2; j<h_vertices[i].length (); j+=2)
        {
          float hx0 = pos_x + hershey2coord(h_vertices[i].charAt(j-2)) * hfactor;
          float hy0 = hershey2coord(h_vertices[i].charAt(j-1)) * hfactor;
          shc.vertex(hx0, hy0);
          float hx1 = pos_x + hershey2coord(h_vertices[i].charAt(j)) * hfactor;
          float hy1 = hershey2coord(h_vertices[i].charAt(j+1)) * hfactor;
          shc.vertex(hx1, hy1);
        }
        shc.endShape(parent.CLOSE);
      }
      pos_x += h_width + 5 * hfactor;
      sh.addChild(shc);
    }
    return sh;
  }

  public void text(String s, int x, int y)
  {
    parent.pushMatrix();
    parent.translate(x, y);
    for (int i=0; i<s.length (); i++)
    {
      draw_character(s.charAt(i));
    }
    parent.popMatrix();
  }

  public void textXY(String s, int x, int y)
  {
    parent.pushMatrix();
    parent.translate(x, y);
    for (int i=0; i<s.length (); i++)
    {
      draw_character_xy(s.charAt(i)); // custom drawChar for XYscope
    }
    parent.popMatrix();
  }

  private float get_character_width(int c)
  {
    String h = hershey_font[c - 32 ];

    int start_col = h.indexOf(" ");

    int vertices_length = Integer.parseInt(h.substring(start_col+1, start_col+3).trim());

    int h_left = hershey2coord(h.charAt(start_col+3));
    int h_right = hershey2coord(h.charAt(start_col+4));
    float h_width = h_right - h_left * hfactor;

    return h_width;
  }

  private void draw_character(int c)
  {
    int max_y = -1000;
    int min_y = 1000;

    String h = hershey_font[c - 32 ];

    int start_col = h.indexOf(" ");

    int vertices_length = Integer.parseInt(h.substring(start_col+1, start_col+3).trim());

    int h_left = hershey2coord(h.charAt(start_col+3));
    int h_right = hershey2coord(h.charAt(start_col+4));
    float h_width = h_right - h_left * hfactor;

    String[] h_vertices = h.substring(start_col+5, h.length()).replaceAll(" R", " ").split(" ");

    for (int i=0; i<h_vertices.length; i++)
    {
      parent.beginShape(parent.LINES);
      for (int j=2; j<h_vertices[i].length (); j+=2)
      {
        float hx0 = hershey2coord(h_vertices[i].charAt(j-2)) * hfactor;
        float hy0 = hershey2coord(h_vertices[i].charAt(j-1)) * hfactor;
        parent.vertex(hx0, hy0);
        float hx1 = hershey2coord(h_vertices[i].charAt(j)) * hfactor;
        float hy1 = hershey2coord(h_vertices[i].charAt(j+1)) * hfactor;
        parent.vertex(hx1, hy1);
      }
      parent.endShape(parent.CLOSE);
    }
    parent.translate(h_width + 5 * hfactor, 0);
  }

  // custom version for XYscope
  private void draw_character_xy(int c)
  {
    int max_y = -1000;
    int min_y = 1000;

    String h = hershey_font[c - 32 ];

    int start_col = h.indexOf(" ");

    int vertices_length = Integer.parseInt(h.substring(start_col+1, start_col+3).trim());

    int h_left = hershey2coord(h.charAt(start_col+3));
    int h_right = hershey2coord(h.charAt(start_col+4));
    float h_width = h_right - h_left * hfactor;

    String[] h_vertices = h.substring(start_col+5, h.length()).replaceAll(" R", " ").split(" ");

    for (int i=0; i<h_vertices.length; i++)
    {
      xy.beginShape(); // parent.LINES
      for (int j=2; j<h_vertices[i].length (); j+=2)
      {
        float hx0 = hershey2coord(h_vertices[i].charAt(j-2)) * hfactor;
        float hy0 = hershey2coord(h_vertices[i].charAt(j-1)) * hfactor;
        xy.vertex(hx0, hy0);
        float hx1 = hershey2coord(h_vertices[i].charAt(j)) * hfactor;
        float hy1 = hershey2coord(h_vertices[i].charAt(j+1)) * hfactor;
        xy.vertex(hx1, hy1);
      }
      xy.endShape();
    }
    parent.translate(h_width + 5 * hfactor, 0);
  }

  private int hershey2coord(char c)
  {
    return c - 'R';
  }

  private int hershey2int(char c)
  {
    return c;
  }
}
1 Like

Seems like method HersheyFont::draw_character() is declared as private, which is the #1 enemy of customization & can’t be @Override! :angry:

Most we can do is invoke it via reflection. But we can’t change it via inheritance. :cry:

1 Like

Thanks for having a look at this and ooh that’s a bummer about private function limitations – guess in an ideal world, everything in a lib is public, just undocumented for the ‘private’ bits.

1 Like