# Using fisica and geomerative to add physics to typography

Hi guys.

I have this idea for a project but I can’t really figured it out and the documentation for both of these libraries (fisica and geomerative) that I want to use are not that good. Does anyone know how can this be in the easiest way possible?

Thanks! 1 Like

It depends.

What kind of physics to what kind of typography?

Some very simple collision. I want to have a static text in the bottom of my canvas and lets say I have in every x frames a new FCircle (that is not static) at the top of my canvas. When it comes down I want this circle to collide with the text. Don’t know if I made it clear.

Thanks for quick answer Jeremy! 1 Like

There are several ways of doing this. The collision detection itself you can do without a physics engine – you just need a vertex list for the letter forms. Do you need additional physics, or just a bouncing ball that reacts to letter shapes?

If you don’t need additional physics, then you can create the effect you want by combining these two things:

1. This geomerative example: Tutorial_07_HelloWorld_getPoints.pde

2. polygon-circle collision detection. http://jeffreythompson.org/collision-detection/poly-circle.php

Your list of letter points is the polygon. Run it through the polygon-circle collision algorithm to check whether the circle is colliding. Then bounce the ball (or whatever action you choose).

Here is a simple demo with a mouse.

``````/**
* LetterCollisions
* 2020-05-24 Jeremy Douglass - Processing 3.5.4
*
* Move the mouse over letters to test collision detection.
*
* Combines:
* 1. This geomerative example: Tutorial_07_HelloWorld_getPoints.pde
* 2. polygon-circle collision detection. http://jeffreythompson.org/collision-detection/poly-circle.php
*/

import geomerative.*;

// Declare the objects we are going to use, so that they are accesible from setup() and from draw()
RFont f;
RShape grp;
RPoint[] points;

void setup() {
// Initilaize the sketch
size(600, 400);
frameRate(24);

// Choice of colors
background(255);
fill(255, 102, 0);
stroke(0);

// VERY IMPORTANT: Allways initialize the library in the setup
RG.init(this);

//  Load the font file we want to use (the file must be in the data folder in the sketch floder), with the size 60 and the alignment CENTER
grp = RG.getText("Hello world!", "FreeSans.ttf", 90, CENTER);

// Enable smoothing
smooth();
}

void draw() {
// Clean frame
background(255);

// Set the origin to draw in the middle of the sketch
int xoff = width/2;
int yoff = 3*height/5;
translate(xoff, yoff);

// express mouse in new coordinates
int mx = mouseX-xoff;
int my = mouseY-yoff;
boolean hit = false;

// Draw the group of shapes
noFill();
stroke(0, 0, 200, 150);
grp.draw();

// Get the points on the curve's shape
//RG.setPolygonizer(RG.UNIFORMSTEP);
//RG.setPolygonizerStep(map(float(mouseY), 0.0, float(height), 0.0, 1.0));

RG.setPolygonizer(RG.UNIFORMLENGTH);
RG.setPolygonizerLength(8);  // set gap in px between points around letter

// Loop over individual letters in group
// and process their points separately
for (int c=0; c<grp.children.length; c++) {
points = grp.children[c].getPoints();
// If there are any points
if (points != null) {
// draw the letter outline
fill(0, 200, 0, 32);
stroke(0, 200, 0);
beginShape();
for (int i=0; i<points.length; i++) {
vertex(points[i].x, points[i].y);
}
endShape();

// draw box on each vertex
stroke(0, 128, 0);
for (int i=0; i<points.length; i++) {
rect(points[i].x-1, points[i].y-1, 3, 3);
}

// check for mouse collision with this letter
// record a hit if mouse is touching this letter
// and use it for drawing later
if(polyCircle(points, mx, my, 10)) hit=true;
}
}
// draw the mouse is hit(red) or not(blue)
if(hit) fill(255,0,0,64);
else fill(0,0,255,64);
ellipse(mx, my, 20, 20);
}

// PolyCircle collision functions adapted from:
// http://jeffreythompson.org/collision-detection/poly-circle.php
// 1. replace "PVector" with "RPPoint"
// 2. remove "closest point" circle display

// POLYGON/CIRCLE
boolean polyCircle(RPoint[] vertices, float cx, float cy, float r) {

// go through each of the vertices, plus
// the next vertex in the list
int next = 0;
for (int current=0; current<vertices.length; current++) {

// get next vertex in list
// if we've hit the end, wrap around to 0
next = current+1;
if (next == vertices.length) next = 0;

// get the RPoints at our current position
// this makes our if statement a little cleaner
RPoint vc = vertices[current];    // c for "current"
RPoint vn = vertices[next];       // n for "next"

// check for collision between the circle and
// a line formed between the two vertices
boolean collision = lineCircle(vc.x,vc.y, vn.x,vn.y, cx,cy,r);
if (collision) return true;
}

// the above algorithm only checks if the circle
// is touching the edges of the polygon – in most
// cases this is enough, but you can un-comment the
// following code to also test if the center of the
// circle is inside the polygon

// boolean centerInside = polygonPoint(vertices, cx,cy);
// if (centerInside) return true;

// otherwise, after all that, return false
return false;
}

// LINE/CIRCLE
boolean lineCircle(float x1, float y1, float x2, float y2, float cx, float cy, float r) {

// is either end INSIDE the circle?
// if so, return true immediately
boolean inside1 = pointCircle(x1,y1, cx,cy,r);
boolean inside2 = pointCircle(x2,y2, cx,cy,r);
if (inside1 || inside2) return true;

// get length of the line
float distX = x1 - x2;
float distY = y1 - y2;
float len = sqrt( (distX*distX) + (distY*distY) );

// get dot product of the line and circle
float dot = ( ((cx-x1)*(x2-x1)) + ((cy-y1)*(y2-y1)) ) / pow(len,2);

// find the closest point on the line
float closestX = x1 + (dot * (x2-x1));
float closestY = y1 + (dot * (y2-y1));

// is this point actually on the line segment?
// if so keep going, but if not, return false
boolean onSegment = linePoint(x1,y1,x2,y2, closestX,closestY);
if (!onSegment) return false;

// optionally, draw a circle at the closest point
// on the line
//////fill(255,0,0);
//////noStroke();
//////ellipse(closestX, closestY, 20, 20);

// get distance to closest point
distX = closestX - cx;
distY = closestY - cy;
float distance = sqrt( (distX*distX) + (distY*distY) );

// is the circle on the line?
if (distance <= r) {
return true;
}
return false;
}

// LINE/POINT
boolean linePoint(float x1, float y1, float x2, float y2, float px, float py) {

// get distance from the point to the two ends of the line
float d1 = dist(px,py, x1,y1);
float d2 = dist(px,py, x2,y2);

// get the length of the line
float lineLen = dist(x1,y1, x2,y2);

// since floats are so minutely accurate, add
// a little buffer zone that will give collision
float buffer = 0.1;    // higher # = less accurate

// if the two distances are equal to the line's
// length, the point is on the line!
// note we use the buffer here to give a range, rather
// than one #
if (d1+d2 >= lineLen-buffer && d1+d2 <= lineLen+buffer) {
return true;
}
return false;
}

// POINT/CIRCLE
boolean pointCircle(float px, float py, float cx, float cy, float r) {

// get distance between the point and circle's center
// using the Pythagorean Theorem
float distX = px - cx;
float distY = py - cy;
float distance = sqrt( (distX*distX) + (distY*distY) );

// if the distance is less than the circle's
// radius the point is inside!
if (distance <= r) {
return true;
}
return false;
}

// POLYGON/POINT
// only needed if you're going to check if the circle
// is INSIDE the polygon
boolean polygonPoint(RPoint[] vertices, float px, float py) {
boolean collision = false;

// go through each of the vertices, plus the next
// vertex in the list
int next = 0;
for (int current=0; current<vertices.length; current++) {

// get next vertex in list
// if we've hit the end, wrap around to 0
next = current+1;
if (next == vertices.length) next = 0;

// get the RPoints at our current position
// this makes our if statement a little cleaner
RPoint vc = vertices[current];    // c for "current"
RPoint vn = vertices[next];       // n for "next"

// compare position, flip 'collision' variable
// back and forth
if (((vc.y > py && vn.y < py) || (vc.y < py && vn.y > py)) &&
(px < (vn.x-vc.x)*(py-vc.y) / (vn.y-vc.y)+vc.x)) {
collision = !collision;
}
}
return collision;
}
``````

2 Likes

You may also be interested in reading the past posts of @lolonulu, who has done a lot of work with the geomerative library and text vertex data.

2 Likes

Thank you @jeremydouglass and @lolonulu, you guys are amazing.

1 Like