CJ 2D Joint no rotation

From Newton Wiki
Jump to: navigation, search

This final version of the 2D joint removes the planar rotation so that no rotations are allowed. All that is allowed is translation along the two axes of the plane. It uses NewtonUserJointAddAngularRow to remove this last rotation.

Construction

The construction code is the same as before. The plane vector can be anything you want and does not have to be normalised.

Joint2D::Joint2D(NewtonBody* kpBody0, dVector kPlaneNormal)
{
	mpBody0=kpBody0;
	mPlaneNormal=kPlaneNormal;

	dMatrix matrix0;
	NewtonBodyGetMatrix(mpBody0, &matrix0[0][0]);
	mPlaneOrigin=matrix0.m_posit;

	mpJoint=NewtonConstraintCreateUserJoint(mspWorld, 6, SubmitConstraints, mpBody0, 0);
	NewtonJointSetUserData (mpJoint, (void*) this);
}

SubmitConstraints

The constraint code begins the same but we add another an angular constraint. The error angle is extracted from the object transformation matrix.

Example C++ code:

void Joint2D::LocalSubmitConstraints(const NewtonJoint* kpJoint)
{
	dMatrix matrix0;
	NewtonBodyGetMatrix(mpBody0, &matrix0[0][0]);

	// this line clamps the origin to the plane
	NewtonUserJointAddLinearRow (mpJoint, &matrix0.m_posit[0], &mPlaneOrigin[0], &mPlaneNormal[0]);

	// we can prevent rotation that takes any points out of the plane by clamping a point on the
	// object that is on the line through the origin of the object with the same vector as the
	// plane normal.  The clamp is to another plane that is parallel to the first, offset by the
	// plane normal vector.  Rotations around either of the axes orthogonal to the plane normal
	// will be prevented because they take the object point off that parallel plane.

	dVector object_point;
	dVector world_point;

	object_point=matrix0.TransformVector(mPlaneNormal);
	world_point=mPlaneOrigin+mPlaneNormal;
	NewtonUserJointAddLinearRow (mpJoint, &object_point[0], &world_point[0], &mPlaneNormal[0]);

	// that just leaves rotations around the plane's normal
	// we can do this by equating matrix0 with a rotation matrix generated by an angle around the
	// plane normal.  The equations can be solved for the angle which can then be fed into
	// NewtonUserJointAddAngularRow
	// For an example of this matrix, see http://en.wikipedia.org/wiki/Rotation_matrix and look
	// at the M(v,theta) matrix

	dFloat temp;

	// solving for the [0,0] matrix element gives the angle via arccos
	dFloat x2=mPlaneNormal[0]*mPlaneNormal[0];
	temp=(matrix0.m_front[0]-x2)/(1.0-x2);
	// correct any numerical error
	if (temp<-1.0)
		temp=-1.0;
	if (temp>1.0)
		temp=1.0;
	// end correct any numerical error
	dFloat ac=acos(temp);

	// we don't know the sign so we have to solve the [0,1] element as well
	temp=(matrix0.m_front[1]-(1.0-cos(ac))*mPlaneNormal[0]*mPlaneNormal[1])/mPlaneNormal[2];
	// correct any numerical error
	if (temp<-1.0)
		temp=-1.0;
	if (temp>1.0)
		temp=1.0;
	// end correct any numerical error
	dFloat as=asin(temp);

	if (as>0.0)
		ac*=-1.0;
	dFloat angle=ac;

	NewtonUserJointAddAngularRow(mpJoint,angle,&mPlaneNormal[0]);
}

Usage

Again simply supply a plane normal vector. For example, say you want to limit to the 2D plane defined by the x and y axes (i.e. no movement along the z axis) you could use (0,0,1). Any plane is possible by defining the correct normal vector. The vector does not need to be normalised.

Graphics tip: you might want your programme to only use the translation part of the object's matrix for graphical output. This is because small angle errors are driven to zero quickly but can still be seen as a slight shake in certain circumstances.

Links