Path

With the points of each letter safely in a array, it was time to find way to convert the data of each point into a path that eventually a pen could follow. As I am using a stepping motor is seemed obvious that I had to split the path up into a long array of small steps. Last year when I was making this move in Processing, I used to simply find the difference between the two points, divide that by a constant, say n, and add that new vector to the current position n number of times. This way a point would travel from A to B in a fixed time, for most computer animated stuff this worked fine. However, for Pedro the pen had to travel at a fixed velocity, not from A to B in a fixed time. This maximum velocity would be the fastest the pen could move over the paper whilst still drawing properly. I don't know what this speed is at the moment but I had to design my virtual model so that I could factor it in.

My first idea was this: iterate through the whole array and take the difference in position between point A and B, this would give two answers; dx and dy. Then after finding the maximum between the two, divide both by the maximum, this would give, say; ix and iy. Then push on to the new array of vectors ix and iy the maximum number of times. All this super long-winded code might look a bit like:

for (int i = 0; i < letter.contours.size(); i++) {
	for (int j = 0; j < letter.contours[i].pts.size() - 1; j++) {
		
		float x1 = letter.contours[i].pts[j].x;
		float y1 = letter.contours[i].pts[j].y;
		
		float x2 = letter.contours[i].pts[j+1].x;
		float y2 = letter.contours[i].pts[j+1].y;

		float dx = x2-x1;
		float dy = y2-y1;
		
		float maxd = max(dx, dy);
		
		float ix = dx/maxd;
		float iy = dy/maxd;
		
		for (int i = 0; i < maxd; i++) {
			path.push_back(ofxVec2f(ix, iy));
		}
		
	}
}

I won't go into much detail but even though I have thought my theory was flawless it was in fact far from it. No matter how much I messed with it, it gave some pretty weird results some looking a bit like this:

messed_up_k

So it was time for a new algorithm, after chatting a few chats with people I came up with a new way of doing things. Similarly to the first method it started by taking the difference between the two points. Then find the distance between the two points, call this hyp. The find the unit vector of the of the vector dx, dy. The push on the array the the unit vector, hyp number of times. The code for this in a nice little method looks like this:

void testApp::addToPath(ofPoint a, ofPoint b) {
	
	float dx = b.x - a.x;
	float dy = b.y - a.y;
	
	float hyp = ofDist(a.x, a.y, b.x, b.y);
	ofxVec2f uv = ofxVec2f(dx, dy);
	//get unit vector									 
	uv = uv.normalize();
	
	//add hyp number of unit vectors to the path...
	for (int i = 0 ; i < hyp; i++) {
		path.push_back(uv);
	}
}

Suddenly things started looking up, I was getting what looked like some pretty good results but they were not perfect, they look like this:

wrong_n

First I realised that there was a small bit being missed as hyp was a floating point number and anything after the decimal point was not being added, so I took care of this simply with:

void testApp::addToPath(ofPoint a, ofPoint b) {
	
	float dx = b.x - a.x;
	float dy = b.y - a.y;
	
	float hyp = ofDist(a.x, a.y, b.x, b.y);
	ofxVec2f uv = ofxVec2f(dx, dy);
	//get unit vector									 
	uv = uv.normalize();
	
	//add hyp number of unit vectors to the path...
	for (int i = 0 ; i < hyp; i++) {
		path.push_back(uv);
	}
	
	//now add the little remainder that didn't get added in the loop
	//as will chop off anything after the decimal point
	double ip;
	float r = modf(hyp, &ip);
	uv.set(uv.x*r, uv.y*r);
	path.push_back(uv);
	
}

But things still didn't look right:

justwrong-f

The the thought occurred to me, hyp was a floating point number so if it was say; 1.26 the for loop would iterate twice which would be wrong as it was adding a full unit vector for the 0.26. So I simply change the loop to start at 1 and, finally:

right-f

I then added in little things to move the pen up and down. Giving a final show of this: