IK Help * Solved *

Question about angles and IK

So I have a very simple IK Chain take an array of points.

vector pts;

add three points

for(int i=0; i<3; i++) {
pts.push_back(ofVec2f());
}

now move the first point to follow the mouse.

pts[0].set(mouseX, mouseY);

for the rest of the points update their position applying IK.

for(int i=1; i<pts.size(); i++) {
float dx = pts[i-1].x - pts[i].x;
float dy = pts[i-1].y - pts[i].y;
float angle = atan2(dy, dx);

pts[i].x = pts[i-1].x - cos(angle) * 10;
pts[i].y = pts[i-1].y - sin(angle) * 10;
}

now draw them out :slight_smile:
for(int i=1; i<pts.size(); i++) {
ofLine(pts[i-1], pts[i]);
}

This works great but what I am trying todo is limit the angle that each segment can move. For instance do not allow the segment to bend beyond -30, 30 degrees.

Any Suggestion would be very much appreciated

Todd

you can run this in a test app

  
#include "testApp.h"  
  
vector <ofVec2f> pts;  
  
//--------------------------------------------------------------  
void testApp::setup(){  
	ofBackground(90);  
  
	for (int i=0; i<3; i++) {  
		pts.push_back(ofVec2f());  
	}  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	  
	pts[0].set(ofGetMouseX(), ofGetMouseY());  
  
	for (int i=1; i<pts.size(); i++) {  
		float dx = pts[i-1].x - pts[i].x;  
		float dy = pts[i-1].y - pts[i].y;  
		float a  = atan2(dy, dx);  
		  
		pts[i].x = pts[i-1].x - cos(a) * 100;  
		pts[i].y = pts[i-1].y - sin(a) * 100;  
		  
		ofSetColor(200);  
		ofLine(pts[i-1], pts[i]);  
	}  
	  
}  
  

update trying to clamp but get a bad flip when I hit PI. The angles flip from PI to -PI.

  
vector <ofVec2f> pts;  
vector <float> prevAngles;  
  
//--------------------------------------------------------------  
void testApp::setup(){  
	ofBackground(90);  
	int nPts = 6;  
	for (int i=0; i<nPts; i++) {  
		pts.push_back(ofVec2f());  
		prevAngles.push_back(0);  
	}  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	  
	pts[0].set(ofGetMouseX(), ofGetMouseY());  
  
  
	for (int i=1; i<pts.size(); i++) {  
		  
		float dx = pts[i-1].x - pts[i].x;  
		float dy = pts[i-1].y - pts[i].y;  
		float a  = atan2(dy, dx);  
		float dis = 40;  
		  
		if(i == 1) {  
			pts[i].x = pts[i-1].x - cos(a) * dis;  
			pts[i].y = pts[i-1].y - sin(a) * dis;  
		}	  
		else {  
			float range = ofDegToRad(35);  
			float pa = prevAngles[i-1];  
			float c  = ofClamp(a, pa-range, pa+range);  
			  
			pts[i].x = pts[i-1].x - cos(c) * dis;  
			pts[i].y = pts[i-1].y - sin(c) * dis;  
		}  
		printf("a1:%f\n",ofRadToDeg(a));  
		  
		ofSetColor(255);  
		ofDrawBitmapString(ofToString(ofRadToDeg(a)), pts[i]);  
		prevAngles[i] = a;  
	}  
	  
	  
	  
	for (int i=1; i<pts.size(); i++) {  
		ofSetColor(200);  
		ofLine(pts[i-1], pts[i]);  
	}  
	  
}  

try substituting 32-37 with this : )

  
  
float range = ofDegToRad(35);  
float pa = prevAngles[i-1];  
  
float d = a - pa;  
float absA = fabs(d);  
float s = d>=0?1:-1;  
if (absA > PI) {  
	a = s * (2 * PI - fabs(a)) * -1;  
}  
  
float c  = ofClamp(a, pa-range, pa+range);  
  
pts[i].x = pts[i-1].x - cos(c) * dis;  
pts[i].y = pts[i-1].y - sin(c) * dis;  
  

EDIT: at some point the angle can become +/- too big to avoid it, line 43 to:

  
  
	while (a > to ) a-=PI*2;  
	while (a < from ) a+=PI*2;  
        prevAngles[i] = a;   
  

arturo amazing! the first suggestion is starting to work. The second suggestion on sure about, what is “to-from”

oops, yes, that’s just to wrap the angle between from:-PI and to:PI so the angles always stay in that range.

also, i just added a ofWrapRadians function to do that so you can just do

  
prevAngles[i] = ofWrapRadians(a);  

Arturo you did it again - thanks so much, it work so well!

here is the final source code if anyone wants to play around with it.
http://vanderlin.cc/OF/ChainAngleRange.zip

Ya!
http://vanderlin.cc/OF/media/Chain.mov

awesome! thanks for sharing arturo & todd!