# What are "frame A" and "frame B" in btGeneric6DofConstraint's constructor for?

I have a very simple (and maybe too primitive to post here but I’ll try anyway :P) question about Bullet constraints. What are arguments const btTransform &frameInA, const btTransform &frameInB, bool useLinearReferenceFrameA of Bullet’s btGeneric6DofConstraint? Documentation doesn’t say anything about them.

I think (but am not entirely sure) that the first two are Pivot Point Transformations relative to mass-center of two rigid bodies (in their own coordinate systems). And thus they should always point to the same point in world-space. Is that true?

Also, what is Linear Reference Frame?

Looking on the Bullet Physics forums I found a comment from Erwin (the author):

FrameA and FrameB are constraint frames in local spaces A and B respectively Limits give the allowable range of movement if frameB in frameA space (or vice versa if useLinearReferenceFrameA == false)

He then supplies some sample code to try:

{ // create a generic 6DOF constraint with spring that has rest length 10
// and connected to dynamic body at point (-5, 0, 0)
btScalar springRestLen(10.f);
btScalar pivotOffset(-5.f);
btScalar springRange(7.f); // allowed oscillation range
btTransform tr;
tr.setIdentity();
tr.setOrigin(btVector3(btScalar(0.), btScalar(0.), btScalar(0.)));
tr.getBasis().setEulerZYX(0,0,0);
btRigidBody* pBodyA = localCreateRigidBody( 0.0, tr, shape); // static body
pBodyA->setActivationState(DISABLE_DEACTIVATION);

btTransform frameInA;
frameInA = btTransform::getIdentity();
frameInA.setOrigin(btVector3(btScalar(0.), btScalar(0.), btScalar(0.))); // in A coordinate systam

tr.setIdentity();
tr.setOrigin(btVector3(btScalar(springRestLen - pivotOffset), btScalar(0.), btScalar(0.))); // this is (15, 0, 0)
tr.getBasis().setEulerZYX(0,0,0);
btRigidBody* pBodyB = localCreateRigidBody(1.0, tr, shape); // dynamic body
pBodyB->setActivationState(DISABLE_DEACTIVATION);

btTransform frameInB;
frameInB = btTransform::getIdentity();
frameInB.setOrigin(btVector3(pivotOffset, btScalar(0.), btScalar(0.))); // in B coordinate systam

btGeneric6DofSpringConstraint* pGen6DOFSpring = new btGeneric6DofSpringConstraint(*pBodyA, *pBodyB, frameInA, frameInB, true);
// in WCS we should have offset between origin of frameB and frameA.
// It should be equal to springRestLen, so we should set proper limits
// we set useLinearReferenceFrameA to true, so limits wil be in A coordinate system
pGen6DOFSpring->setLinearUpperLimit(btVector3(springRestLen + springRange, 0., 0.));
pGen6DOFSpring->setLinearLowerLimit(btVector3(springRestLen - springRange, 0., 0.));
// lock all rorations
pGen6DOFSpring->setAngularLowerLimit(btVector3(0.f, 0.f, 0.f));
pGen6DOFSpring->setAngularUpperLimit(btVector3(0.f, 0.f, 0.f));