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
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]);
}
}
arturo
July 8, 2011, 8:52pm
#3
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”
arturo
July 9, 2011, 12:54am
#5
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
roxlu
July 9, 2011, 2:00pm
#7
awesome! thanks for sharing arturo & todd!