Пример #1
0
void C4X4Matrix::rotateAroundZ(float angle)
{
    C4X4Matrix rot;
    rot.setIdentity();
    rot.M.buildZRotation(angle);
    (*this)=rot*(*this);
}
Пример #2
0
void C4X4Matrix::rotateAroundY(extIkReal angle)
{
	C4X4Matrix rot;
	rot.setIdentity();
	rot.M.buildYRotation(angle);
	(*this)=rot*(*this);
}
Пример #3
0
int CCuttingRoutine::cutEntity(int millID,int entityID,int& cutObject,float& cutSurface,float& cutVolume,bool justForInitialization,bool overrideCuttableFlagIfNonCollection)
{ // entityID==-1 --> checks all objects in the scene. Return value is the number of cut objects
	int cutCount=0;
	cutObject=-1;
	cutSurface=0.0f;
	cutVolume=0.0f;
	C3DObject* object=App::ct->objCont->getObject(entityID);
	CMill* sens=App::ct->objCont->getMill(millID);
	if (sens==NULL)
		return(0); // should never happen!
	App::ct->infoDisplay->millSimulationStart();

	C3Vector minV,maxV;
	sens->getMillingVolumeBoundingBox(minV,maxV);
	C4X4Matrix millingVolumeBox;
	millingVolumeBox.setIdentity();
	millingVolumeBox.X=(maxV+minV)*0.5f;
	C3Vector millingVolumeSize(maxV-minV);

	if (object==NULL)
		cutCount=_cutGroup(millID,entityID,cutObject,cutSurface,cutVolume,justForInitialization);
	else
	{ // Cutting objects:
		if (object->getObjectType()==sim_object_shape_type)
		{
			if (_cutShape(millID,entityID,cutSurface,justForInitialization,overrideCuttableFlagIfNonCollection))
			{
				cutObject=entityID;
				cutCount++;
			}
		}
		if (object->getObjectType()==sim_object_volume_type)
		{
			if (_cutVolumeObject(millID,entityID,cutVolume,justForInitialization,overrideCuttableFlagIfNonCollection))
			{
				cutObject=entityID;
				cutCount++;
			}
		}
	}
	App::ct->infoDisplay->millSimulationEnd(cutSurface,cutVolume);
	return(cutCount);
}
Пример #4
0
void robot::createJoints(bool hideJoints,bool positionCtrl)
{
	std::string txt("There are "+boost::lexical_cast<std::string>(vJoints.size())+" joints.");
	printToConsole(txt.c_str());

	//Set parents and childs for all the links
	for(size_t i = 0; i < vJoints.size() ; i++)
	{
		vLinks.at(getLinkPosition(vJoints.at(i)->parentLink))->child = vJoints.at(i)->name;
		vLinks.at(getLinkPosition(vJoints.at(i)->childLink))->parent = vJoints.at(i)->name;
	}

	//Create the joints
	for(size_t i = 0; i < vJoints.size() ; i++)
	{
		//Move the joints to the positions specifieds by the urdf file
		C7Vector tmp;
		tmp.setIdentity();
		tmp.X.set(vJoints.at(i)->origin_xyz);
		tmp.Q=getQuaternionFromRpy(vJoints.at(i)->origin_rpy);
		vJoints.at(i)->jointBaseFrame=vJoints.at(i)->jointBaseFrame*tmp;

		//Set name jointParent to each joint
		int nParentLink = getLinkPosition(vJoints.at(i)->parentLink);
		vJoints.at(i)->parentJoint = vLinks.at(nParentLink)->parent;

		//Create the joint/forceSensor/dummy:
		if (vJoints.at(i)->jointType==-1)
			vJoints.at(i)->nJoint = simCreateDummy(0.02f,NULL); // when joint type was not recognized
		if (vJoints.at(i)->jointType==0)
			vJoints.at(i)->nJoint = simCreateJoint(sim_joint_revolute_subtype,sim_jointmode_force,2,NULL,NULL,NULL);
		if (vJoints.at(i)->jointType==1)
			vJoints.at(i)->nJoint = simCreateJoint(sim_joint_prismatic_subtype,sim_jointmode_force,2,NULL,NULL,NULL);
		if (vJoints.at(i)->jointType==2)
			vJoints.at(i)->nJoint = simCreateJoint(sim_joint_spherical_subtype,sim_jointmode_force,2,NULL,NULL,NULL);
		if (vJoints.at(i)->jointType==3)
			vJoints.at(i)->nJoint = simCreateJoint(sim_joint_revolute_subtype,sim_jointmode_force,2,NULL,NULL,NULL);
		if (vJoints.at(i)->jointType==4)
		{ // when joint type is "fixed"
			int intParams[5]={1,4,4,0,0};
			float floatParams[5]={0.02f,1.0f,1.0f,0.0f,0.0f};
			vJoints.at(i)->nJoint = simCreateForceSensor(0,intParams,floatParams,NULL);
		}

		if ( (vJoints.at(i)->jointType==0)||(vJoints.at(i)->jointType==1) )
		{
			float interval[2]={vJoints.at(i)->lowerLimit,vJoints.at(i)->upperLimit-vJoints.at(i)->lowerLimit};
			simSetJointInterval(vJoints.at(i)->nJoint,0,interval);
			if (vJoints.at(i)->jointType==0)
			{ // revolute
				simSetJointForce(vJoints.at(i)->nJoint,vJoints.at(i)->effortLimitAngular);
				simSetObjectFloatParameter(vJoints.at(i)->nJoint,2017,vJoints.at(i)->velocityLimitAngular);
			}
			else
			{ // prismatic
				simSetJointForce(vJoints.at(i)->nJoint,vJoints.at(i)->effortLimitLinear);
				simSetObjectFloatParameter(vJoints.at(i)->nJoint,2017,vJoints.at(i)->velocityLimitLinear);
			}
			// We turn the position control on:
			if (positionCtrl)
			{
				simSetObjectIntParameter(vJoints.at(i)->nJoint,2000,1);
				simSetObjectIntParameter(vJoints.at(i)->nJoint,2001,1);
			}
		}

		//Set the name:
		setVrepObjectName(vJoints.at(i)->nJoint,vJoints.at(i)->name.c_str());
		if (hideJoints)
			simSetObjectIntParameter(vJoints.at(i)->nJoint,10,512); // layer 10
	}

	//Set positions to joints from the 4x4matrix
	for(size_t i = 0; i < vJoints.size() ; i++)
	{
		simSetObjectPosition(vJoints.at(i)->nJoint,-1,vJoints.at(i)->jointBaseFrame.X.data);
		simSetObjectOrientation(vJoints.at(i)->nJoint,-1 ,vJoints.at(i)->jointBaseFrame.Q.getEulerAngles().data);
	}

	//Set joint parentship between them (thes parentship will be remove before adding the joints)
	for(size_t i = 0; i < vJoints.size() ; i++)
	{   
		int parentJointIndex=getJointPosition(vJoints.at(i)->parentJoint);
		if ( parentJointIndex!= -1)
		{
			simInt nParentJoint = vJoints.at(parentJointIndex)->nJoint;
			simInt nJoint = vJoints.at(i)->nJoint;
			simSetObjectParent(nJoint,nParentJoint,false);
		}	
	}

	//Delete all the partnership without moving the joints but after doing that update the transform matrix
	for(size_t i = 0; i < vJoints.size() ; i++)
	{ 
		C4X4Matrix tmp;  
		simGetObjectPosition(vJoints.at(i)->nJoint,-1,tmp.X.data);
		C3Vector euler;
		simGetObjectOrientation(vJoints.at(i)->nJoint,-1,euler.data);
		tmp.M.setEulerAngles(euler);
		vJoints.at(i)->jointBaseFrame = tmp;

		simInt nJoint = vJoints.at(i)->nJoint;
		simSetObjectParent(nJoint,-1,true);
	}

	for(size_t i = 0; i < vJoints.size() ; i++)
	{
		C4X4Matrix jointAxisMatrix;
		jointAxisMatrix.setIdentity();
		C3Vector axis(vJoints.at(i)->axis);
		C3Vector rotAxis;
		float rotAngle=0.0f;
		if (axis(2)<1.0f)
		{
			if (axis(2)<=-1.0f)
				rotAngle=3.14159265359f;
			else
				rotAngle=acosf(axis(2));
			rotAxis(0)=-axis(1);
			rotAxis(1)=axis(0);
			rotAxis(2)=0.0f;
			rotAxis.normalize();
			C7Vector m(jointAxisMatrix);
			float alpha=-atan2(rotAxis(1),rotAxis(0));
			float beta=atan2(-sqrt(rotAxis(0)*rotAxis(0)+rotAxis(1)*rotAxis(1)),rotAxis(2));
			C7Vector r;
			r.X.clear();
			r.Q.setEulerAngles(0.0f,0.0f,alpha);
			m=r*m;
			r.Q.setEulerAngles(0.0f,beta,0.0f);
			m=r*m;
			r.Q.setEulerAngles(0.0f,0.0f,rotAngle);
			m=r*m;
			r.Q.setEulerAngles(0.0f,-beta,0.0f);
			m=r*m;
			r.Q.setEulerAngles(0.0f,0.0f,-alpha);
			m=r*m;
			jointAxisMatrix=m.getMatrix();
		}
		C4Vector q((vJoints.at(i)->jointBaseFrame*jointAxisMatrix).Q);
		simSetObjectOrientation(vJoints.at(i)->nJoint,-1,q.getEulerAngles().data);
	}
}
Пример #5
0
void CikEl::prepareIkEquations(extIkReal interpolFact)
{	// Before calling this function, make sure that joint's temp. param. are initialized!
	// Make also sure the tooltip is built on a joint before 'base' and that base
	// is parent of 'tooltip'.
	// interpolFact is the interpolation factor we use to compute the target pose:
	// interpolPose=tooltipPose*(1-interpolFact)+targetPose*interpolFact

	// We first take care of dummies linked to path objects in a "sliding" manner (not fixed but assigned to the path):
	// Case 1. Target is the free sliding dummy:
	CDummy* dummyObj=Ct::ct->objCont->getDummy(getTarget());
	CDummy* tipObj=Ct::ct->objCont->getDummy(tooltip);

	// We get the jacobian and the rowJointIDs:
	rowJointIDs=new std::vector<int>;
	rowJointStages=new std::vector<int>;
	C4X4Matrix oldMatr;
	CMatrix* Ja=CIkRoutine::getJacobian(this,oldMatr,rowJointIDs,rowJointStages);

	// oldMatr now contains the cumulative transf. matr. of tooltip relative to base
	C4X4Matrix oldMatrInv(oldMatr.getInverse());
	int doF=Ja->cols;
	int equationNumber=0;

	C4X4Matrix dummyCumul;
	C4X4Matrix m;
	if (dummyObj!=NULL)
	{
		C3DObject* baseObj=Ct::ct->objCont->getObject(base);
		C4X4Matrix baseCumul;
		baseCumul.setIdentity();
		if (baseObj!=NULL)
			baseCumul=baseObj->getCumulativeTransformation(true).getMatrix();

		baseObj=Ct::ct->objCont->getObject(alternativeBaseForConstraints);
		if (baseObj!=NULL)
			baseCumul=baseObj->getCumulativeTransformation(true).getMatrix();

		baseCumul.inverse();

		dummyCumul=dummyObj->getCumulativeTransformationPart1(true).getMatrix();
		dummyCumul=baseCumul*dummyCumul; // target is relative to the base (or the alternative base)!
		C7Vector tr;
		tr.buildInterpolation(oldMatr.getTransformation(),dummyCumul.getTransformation(),interpolFact);
		m=tr;

		// We prepare matrix and errorVector and their respective sizes:
		if (constraints&sim_ik_x_constraint)
			equationNumber++;
		if (constraints&sim_ik_y_constraint)
			equationNumber++;
		if (constraints&sim_ik_z_constraint)
			equationNumber++;
		if (constraints&sim_ik_alpha_beta_constraint)
			equationNumber+=2;
		if (constraints&sim_ik_gamma_constraint)
			equationNumber++;
	}

	matrix=new CMatrix(equationNumber,doF);
	matrix_correctJacobian=new CMatrix(equationNumber,doF);
	errorVector=new CMatrix(equationNumber,1);
	if (dummyObj!=NULL)
	{
		// We set up the position/orientation errorVector and the matrix:
		int pos=0;
		if (constraints&sim_ik_x_constraint)
		{
			for (int i=0;i<doF;i++)
			{
				(*matrix)(pos,i)=(*Ja)(0,i);
				(*matrix_correctJacobian)(pos,i)=(*Ja)(0,i);
			}
			(*errorVector)(pos,0)=(m.X(0)-oldMatr.X(0))*positionWeight;
			pos++;
		}
		if (constraints&sim_ik_y_constraint)
		{
			for (int i=0;i<doF;i++)
			{
				(*matrix)(pos,i)=(*Ja)(1,i);
				(*matrix_correctJacobian)(pos,i)=(*Ja)(1,i);
			}
			(*errorVector)(pos,0)=(m.X(1)-oldMatr.X(1))*positionWeight;
			pos++;
		}
		if (constraints&sim_ik_z_constraint)
		{
			for (int i=0;i<doF;i++)
			{
				(*matrix)(pos,i)=(*Ja)(2,i);
				(*matrix_correctJacobian)(pos,i)=(*Ja)(2,i);
			}
			(*errorVector)(pos,0)=(m.X(2)-oldMatr.X(2))*positionWeight;
			pos++;
		}
		if ( (constraints&sim_ik_alpha_beta_constraint)&&(constraints&sim_ik_gamma_constraint) )
		{
			for (int i=0;i<doF;i++)
			{
				(*matrix)(pos,i)=(*Ja)(3,i);
				(*matrix)(pos+1,i)=(*Ja)(4,i);
				(*matrix)(pos+2,i)=(*Ja)(5,i);
				(*matrix_correctJacobian)(pos,i)=(*Ja)(3,i)*IK_DIVISION_FACTOR;
				(*matrix_correctJacobian)(pos+1,i)=(*Ja)(4,i)*IK_DIVISION_FACTOR;
				(*matrix_correctJacobian)(pos+2,i)=(*Ja)(5,i)*IK_DIVISION_FACTOR;
			}
			C4X4Matrix diff(oldMatrInv*m);
			C3Vector euler(diff.M.getEulerAngles());
			(*errorVector)(pos,0)=euler(0)*orientationWeight/IK_DIVISION_FACTOR;
			(*errorVector)(pos+1,0)=euler(1)*orientationWeight/IK_DIVISION_FACTOR;
			(*errorVector)(pos+2,0)=euler(2)*orientationWeight/IK_DIVISION_FACTOR;
			pos=pos+3;
		}
		else
		{
			if (constraints&sim_ik_alpha_beta_constraint)
			{
				for (int i=0;i<doF;i++)
				{
					(*matrix)(pos,i)=(*Ja)(3,i);
					(*matrix)(pos+1,i)=(*Ja)(4,i);
					(*matrix_correctJacobian)(pos,i)=(*Ja)(3,i)*IK_DIVISION_FACTOR;
					(*matrix_correctJacobian)(pos+1,i)=(*Ja)(4,i)*IK_DIVISION_FACTOR;
				}
				C4X4Matrix diff(oldMatrInv*m);
				C3Vector euler(diff.M.getEulerAngles());
				(*errorVector)(pos,0)=euler(0)*orientationWeight/IK_DIVISION_FACTOR;
				(*errorVector)(pos+1,0)=euler(1)*orientationWeight/IK_DIVISION_FACTOR;
				pos=pos+2;
			}
			if (constraints&sim_ik_gamma_constraint)
			{ // sim_gamma_constraint can't exist without sim_alpha_beta_constraint!
				for (int i=0;i<doF;i++)
				{
					(*matrix)(pos,i)=(*Ja)(5,i);
					(*matrix_correctJacobian)(pos,i)=(*Ja)(5,i)*IK_DIVISION_FACTOR;
				}
				C4X4Matrix diff(oldMatrInv*m);
				C3Vector euler(diff.M.getEulerAngles());
				(*errorVector)(pos,0)=euler(2)*orientationWeight/IK_DIVISION_FACTOR;
				pos++;
			}
		}
	}
	delete Ja; // We delete the jacobian!
}
bool CGeometricConstraintSolver::solve(CIKGraphObjCont& graphContainer,SGeomConstrSolverParam& parameters)
{
	if (graphContainer.identifyElements()==0)
		return(false); // Nothing to solve (no active joint in the mechanism)
	graphContainer.putElementsInPlace();

// We create a branched tree, where each extremity has a tip dummy
// (which will later be constrained to its respective target dummy)
	
	CIKGraphObject* baseIKGraphObject=graphContainer.getBaseObject();
	CIKGraphNode* graphIterator=baseIKGraphObject;
	CIKGraphNode* previousPosition=NULL;
	CIKGraphNode* nextPosition=NULL;
	C7Vector localTransformation;
	localTransformation.setIdentity();
	CIKObjCont ikObjs;
	CIKJoint* lastJoint=NULL;
	CIKJoint* treeHandle=NULL;

// Some precalculations of some fixed rotations:
	C4X4Matrix tmpRot;
	tmpRot.setIdentity();
	tmpRot.M(0,0)=-1.0f;
	tmpRot.M(2,2)=-1.0f;
	C7Vector rotY180(tmpRot.getTransformation());
	tmpRot.M.clear();
	tmpRot.M(0,0)=1.0f;
	tmpRot.M(2,1)=1.0f;
	tmpRot.M(1,2)=-1.0f;
	C7Vector rotX90(tmpRot.getTransformation().Q,C3Vector(0.0f,0.0f,0.0f));
	tmpRot.M.clear();
	tmpRot.M(2,0)=-1.0f;
	tmpRot.M(1,1)=1.0f;
	tmpRot.M(0,2)=1.0f;
	C7Vector rotY90(tmpRot.getTransformation().Q,C3Vector(0.0f,0.0f,0.0f));
	tmpRot.M.clear();
	tmpRot.M(1,0)=1.0f;
	tmpRot.M(0,1)=-1.0f;
	tmpRot.M(2,2)=1.0f;
	C7Vector rotZ90(tmpRot.getTransformation().Q,C3Vector(0.0f,0.0f,0.0f));
	

	std::vector<CIKGraphNode*> graphObjectsToBeExplored;
	graphObjectsToBeExplored.push_back(baseIKGraphObject);
	std::vector<CIKJoint*> lastJoints;
	lastJoints.push_back(NULL);
	std::vector<CIKGraphNode*> previousPositions;
	previousPositions.push_back(NULL);
	std::vector<C7Vector> localTransformations;
	localTransformations.push_back(localTransformation);

	int explorationID=0;
	while (graphObjectsToBeExplored.size()!=0)
	{
		graphIterator=graphObjectsToBeExplored.back();
		graphObjectsToBeExplored.pop_back();
		lastJoint=lastJoints.back();
		lastJoints.pop_back();
		previousPosition=previousPositions.back();
		previousPositions.pop_back();
		localTransformation=localTransformations.back();
		localTransformations.pop_back();
		bool doIt=(graphIterator->explorationID==-1);
		bool goingDown=false;
		bool closeComplexLoop=false;
		while (doIt)
		{
			if (graphIterator->explorationID==-1)
				graphIterator->explorationID=explorationID;
			explorationID++;
			C7Vector previousCT;
			if (previousPosition!=NULL)
			{
				if (previousPosition->type==IK_GRAPH_JOINT_TYPE)
					previousCT=((CIKGraphObject*)graphIterator)->cumulativeTransformation;
				else
					previousCT=((CIKGraphObject*)previousPosition)->cumulativeTransformation;
			}
			else
			{
				previousCT=baseIKGraphObject->cumulativeTransformation;
				localTransformation=previousCT;
			}

			if (graphIterator->type==IK_GRAPH_JOINT_TYPE)
			{ // Joint: we have to introduce a joint
				CIKGraphJoint* graphJoint=(CIKGraphJoint*)graphIterator;

				if (!graphJoint->disabled)
				{
					C7Vector sphTr;
					sphTr.setIdentity();
					sphTr.Q=graphJoint->sphericalTransformation;
					CIKJoint* newIKJoint;
					if (graphJoint->jointType==IK_GRAPH_SPHERICAL_JOINT_TYPE)
					{
						int dataValueBase=10*graphJoint->nodeID;
						CIKJoint* avatarParent;
						if (graphJoint->topObject==(CIKGraphObject*)previousPosition)
						{ // From tip to base
							C7Vector rel(localTransformation*rotY180);
							newIKJoint=new CIKJoint(graphJoint,rel,false,false);
							if (lastJoint==NULL)
							{
								treeHandle=newIKJoint;
								lastJoint=treeHandle;
								ikObjs.addRoot(lastJoint);
							}
							else
							{
								ikObjs.addChild(lastJoint,newIKJoint);
								lastJoint=newIKJoint;
							}
							avatarParent=ikObjs.getJointWithData(dataValueBase+3);
							if (avatarParent!=NULL) // This joint is used twice (going up and going down)
								avatarParent->addAvatar(lastJoint);
							lastJoint->data=dataValueBase+3;
						
							rel=rotX90;
							newIKJoint=new CIKJoint(graphJoint,rel,false,false);
							ikObjs.addChild(lastJoint,newIKJoint);
							lastJoint=newIKJoint;
							avatarParent=ikObjs.getJointWithData(dataValueBase+2);
							if (avatarParent!=NULL) // This joint is used twice (going up and going down)
								avatarParent->addAvatar(lastJoint);
							lastJoint->data=dataValueBase+2;	

							rel=rotY90;
							newIKJoint=new CIKJoint(graphJoint,rel,false,false);
							ikObjs.addChild(lastJoint,newIKJoint);
							lastJoint=newIKJoint;
							avatarParent=ikObjs.getJointWithData(dataValueBase+1);
							if (avatarParent!=NULL) // This joint is used twice (going up and going down)
								avatarParent->addAvatar(lastJoint);
							lastJoint->data=dataValueBase+1;
							
								rel=rotX90*rotZ90.getInverse()*sphTr.getInverse()*rotY180;
								newIKJoint=new CIKJoint(graphJoint,rel,true,false);
								lastJoint->topJoint=newIKJoint; // This is mainly needed by the joint-limitation part!
								ikObjs.addChild(lastJoint,newIKJoint);
								lastJoint=newIKJoint;
								lastJoint->active=false; // Inactive for now (we can activate it later)
								avatarParent=ikObjs.getJointWithData(dataValueBase+0);
								if (avatarParent!=NULL) // This joint is used twice (going up and going down)
									avatarParent->addAvatar(lastJoint);
								lastJoint->data=dataValueBase+0;
								localTransformation=rotY180;
						}
						else
						{ // From base to tip
							C7Vector rel(localTransformation);
							newIKJoint=new CIKJoint(graphJoint,rel,false,true);
							if (lastJoint==NULL)
							{
								treeHandle=newIKJoint;
								lastJoint=treeHandle;
								ikObjs.addRoot(lastJoint);
							}
							else
							{
								ikObjs.addChild(lastJoint,newIKJoint);
								lastJoint=newIKJoint;
							}
							lastJoint->active=false; // Inactive for now (we can activate it later)
							avatarParent=ikObjs.getJointWithData(dataValueBase+0);
							if (avatarParent!=NULL) // This joint is used twice (going up and going down)
								avatarParent->addAvatar(lastJoint);
							lastJoint->data=dataValueBase+0;

							rel=sphTr*rotY90;
							newIKJoint=new CIKJoint(graphJoint,rel,false,true);
							ikObjs.addChild(lastJoint,newIKJoint);
							lastJoint=newIKJoint;
							avatarParent=ikObjs.getJointWithData(dataValueBase+1);
							if (avatarParent!=NULL) // This joint is used twice (going up and going down)
								avatarParent->addAvatar(lastJoint);
							lastJoint->data=dataValueBase+1;
							
							rel=rotX90.getInverse();
							newIKJoint=new CIKJoint(graphJoint,rel,false,true);
							ikObjs.addChild(lastJoint,newIKJoint);
							lastJoint=newIKJoint;
							avatarParent=ikObjs.getJointWithData(dataValueBase+2);
							if (avatarParent!=NULL) // This joint is used twice (going up and going down)
								avatarParent->addAvatar(lastJoint);
							lastJoint->data=dataValueBase+2;

							rel=rotY90.getInverse()*rotZ90.getInverse();
							newIKJoint=new CIKJoint(graphJoint,rel,true,true);
							newIKJoint->topJoint=newIKJoint; // Top-joint is itself!
							ikObjs.addChild(lastJoint,newIKJoint);
							lastJoint=newIKJoint;
							avatarParent=ikObjs.getJointWithData(dataValueBase+3);
							if (avatarParent!=NULL) // This joint is used twice (going up and going down)
								avatarParent->addAvatar(lastJoint);
							lastJoint->data=dataValueBase+3;

							localTransformation.setIdentity();
						}
					}
					else
					{
						if (graphJoint->topObject==(CIKGraphObject*)previousPosition)
						{ // From tip to base
							C7Vector rel(localTransformation*rotY180);
							newIKJoint=new CIKJoint(graphJoint,rel,false,false);
							localTransformation=rotY180;
						}
						else
						{ // From base to tip
							C7Vector rel(localTransformation);
							newIKJoint=new CIKJoint(graphJoint,rel,false,false);
							localTransformation.setIdentity();
						}
						if (lastJoint==NULL)
						{
							treeHandle=newIKJoint;
							lastJoint=treeHandle;
							ikObjs.addRoot(lastJoint);
						}
						else
						{
							ikObjs.addChild(lastJoint,newIKJoint);
							lastJoint=newIKJoint;
						}
						int dataValue=10*graphJoint->nodeID+0;
						CIKJoint* avatarParent=ikObjs.getJointWithData(dataValue);
						if (avatarParent!=NULL) // This joint is used twice (going up and going down)
							avatarParent->addAvatar(lastJoint);
						lastJoint->data=dataValue;
					}
				}
				else
				{ // In case a graph-joint is disabled: 
					if (graphJoint->topObject==(CIKGraphObject*)previousPosition)
					{ // From tip to base
						localTransformation=localTransformation*graphJoint->getDownToTopTransformation().getInverse();
					}
					else
					{ // From base to tip
						localTransformation=localTransformation*graphJoint->getDownToTopTransformation();
					}
				}
			}
			else
			{
				CIKGraphObject* theObject=(CIKGraphObject*)graphIterator;
				if (theObject->objectType==IK_GRAPH_LINK_OBJECT_TYPE)
				{ // Link
					if (previousPosition!=NULL)
					{
						if (theObject->linkPartner!=previousPosition)
							localTransformation=localTransformation*previousCT.getInverse()*theObject->cumulativeTransformation;
						// If (theObject->linkPartner==previousPosition) then we don't do anything!
					}
				}
				else
				{ // Here we have a dummy we have to assign to a configuration or a passive object
					// We treat all cases first as passive objects:
					if (previousPosition!=NULL)
					{
						localTransformation=localTransformation*previousCT.getInverse()*theObject->cumulativeTransformation;
						if ( (theObject->objectType==IK_GRAPH_TIP_OBJECT_TYPE)&&(lastJoint!=NULL) )
						{ // This is a valid dummy-tip!
							CIKDummy* newIKDummy=new CIKDummy(localTransformation,theObject->targetCumulativeTransformation);
							ikObjs.addChild(lastJoint,newIKDummy);
							newIKDummy->constraints=(IK_X_CONSTRAINT|IK_Y_CONSTRAINT|IK_Z_CONSTRAINT);
							newIKDummy->dampingFactor=1.0f;
							newIKDummy->loopClosureDummy=false;
							if (graphIterator->getConnectionNumber()==1)
								break;
						}
					}
				}
			}
			int unexploredSize=graphIterator->getNumberOfUnexplored();
			if ( (unexploredSize==0)||goingDown||closeComplexLoop )
			{
				if ( (graphIterator->getConnectionNumber()==1)&&(!closeComplexLoop) )
					break; // This is a rare case where we have an endpoint without a tip-dummy mobile-part
				if (closeComplexLoop)
				{
					CIKDummy* tipDummy=new CIKDummy(localTransformation,baseIKGraphObject->cumulativeTransformation);
					ikObjs.addChild(lastJoint,tipDummy);
					break;
				}
				nextPosition=graphIterator->getExploredWithSmallestExplorationID();
				if ( (nextPosition->explorationID==0)&&(!goingDown) )
				{ // The loop can now be closed (simple loop with each joint present at most once)
					previousCT=((CIKGraphObject*)graphIterator)->cumulativeTransformation;
					localTransformation=localTransformation*previousCT.getInverse()*((CIKGraphObject*)nextPosition)->cumulativeTransformation;
					CIKDummy* tipDummy=new CIKDummy(localTransformation,baseIKGraphObject->cumulativeTransformation);
					ikObjs.addChild(lastJoint,tipDummy);
					break;
				}
				if ( (nextPosition->explorationID==0)&&goingDown )
					closeComplexLoop=true;
				goingDown=true;
			}
			else if ((graphIterator->getNeighbourWithExplorationID(0)!=NULL)&&(!goingDown)&&(previousPosition->explorationID!=0))
			{ // Here we have to close the loop too!
				// We first put unexplored paths onto the stack:
				for (int i=0;i<unexploredSize;i++)
				{ // We throw unexplored nodes onto the exploration stack:
					graphObjectsToBeExplored.push_back(graphIterator->getUnexplored(i));
					lastJoints.push_back(lastJoint);
					previousPositions.push_back(graphIterator);
					localTransformations.push_back(localTransformation);
				}
				nextPosition=graphIterator->getExploredWithSmallestExplorationID();
				previousCT=((CIKGraphObject*)previousPosition)->cumulativeTransformation;
				localTransformation=localTransformation*previousCT.getInverse()*((CIKGraphObject*)nextPosition)->cumulativeTransformation;
				CIKDummy* tipDummy=new CIKDummy(localTransformation,baseIKGraphObject->cumulativeTransformation);
				ikObjs.addChild(lastJoint,tipDummy);
				break;
			}
			else
			{
				if (previousPosition==NULL)
				{ // This is the start.	We should always explore first two links which belong together
					// or the 3 objects making up a joint!
					nextPosition=NULL;
					for (int i=0;i<unexploredSize;i++)
					{
						CIKGraphNode* nextPositionTmp=graphIterator->getUnexplored(i);
						if ( (((CIKGraphObject*)graphIterator)->linkPartner==nextPositionTmp)||
							(nextPositionTmp->type==IK_GRAPH_JOINT_TYPE) )
							nextPosition=nextPositionTmp;
						else
						{
							graphObjectsToBeExplored.push_back(graphIterator->getUnexplored(i));
							lastJoints.push_back(lastJoint);
							previousPositions.push_back(graphIterator);
							localTransformations.push_back(localTransformation);
							if (nextPosition==NULL)
								nextPosition=graphIterator->getUnexplored(i);
						}
					}
				}
				else
				{	
					nextPosition=graphIterator->getUnexplored(0);
					for (int i=1;i<unexploredSize;i++)
					{ // We throw unexplored nodes onto the exploration stack:
						graphObjectsToBeExplored.push_back(graphIterator->getUnexplored(i));
						lastJoints.push_back(lastJoint);
						previousPositions.push_back(graphIterator);
						localTransformations.push_back(localTransformation);
					}
				}
			}
			previousPosition=graphIterator;
			graphIterator=nextPosition;
		}

	}

	solveHierarchy(&ikObjs,parameters);

	for (int i=0;i<int(ikObjs.allObjects.size());i++)
	{
		CIKObject* it=ikObjs.allObjects[i];
		if (it->objectType==IK_JOINT_TYPE)
		{
			CIKJoint* theJoint=(CIKJoint*)it;
			if (theJoint->avatarParent==NULL)
			{
				if (theJoint->spherical)
				{
					if (theJoint->topSpherical)
					{
						float a0=theJoint->parameter;
						float a1=((CIKJoint*)theJoint->parent)->parameter;
						float a2=((CIKJoint*)theJoint->parent->parent)->parameter;
						float a3=((CIKJoint*)theJoint->parent->parent->parent)->parameter;
						if (theJoint->sphericalUp)
						{
							theJoint->graphJoint->sphericalTransformation=C4Vector(a3,C3Vector(0.0f,0.0f,1.0f))*theJoint->graphJoint->sphericalTransformation*C4Vector(C3Vector(a2,a1,a0));
						}
						else
						{
							theJoint->graphJoint->sphericalTransformation=C4Vector(a0,C3Vector(0.0f,0.0f,1.0f))*theJoint->graphJoint->sphericalTransformation*C4Vector(C3Vector(a1,a2,a3));
						}
					}
				}
				else
					theJoint->graphJoint->parameter=theJoint->parameter;
			}
		}
	}
	graphContainer.actualizeAllTransformations();
	graphContainer.putElementsInPlace();
	return(true);
}