TwistLimit

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
-=Magic=-
Posts: 41
Joined: Thu Jun 30, 2011 11:32 am

TwistLimit

Post by -=Magic=- »

I think that BEPUphysics.Constraints.TwoEntity.JointLimits.TwistLimit constraint class, doesn't have some properties (like other Joints have).

You can set the axis only using the constructor, since there are no LocalAxisA, LocalAxisB, WorldAxisA, WorldAxisB properties.

is it correct?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: TwistLimit

Post by Norbo »

The TwistLimit can be configured directly using the BasisA and BasisB properties. There's also the JointLimit.SetupJointTransforms function, which is what the constructor uses. SetupJointTransforms just fills out the test and measurement axes required by the bases.
-=Magic=-
Posts: 41
Joined: Thu Jun 30, 2011 11:32 am

Re: TwistLimit

Post by -=Magic=- »

Ok, but the constructor takes this parameters:

Code: Select all

        public TwistLimit(Entity connectionA, Entity connectionB, Vector3 axisA, Vector3 axisB, float minimumAngle, float maximumAngle)
        {
            ConnectionA = connectionA;
            ConnectionB = connectionB;
            SetupJointTransforms(axisA, axisB);
            MinimumAngle = minimumAngle;
            MaximumAngle = maximumAngle;
        }
as you can see, axisA and axisB are never stored inside the class.

Later, if I want to change one axis (example axisA), I have to "know" how the class works, and so call SetupJointTransforms(axisA, axisB); but also I have to remember outisde the class, which argument I used as axisB.

Since all the other classes store internally the values, and expose the Properties in order to update every single value, without knowing how the class works... it would be nice to have the same beahviour on this class too, so have internal field where store axisA and axisB, and two properties which enable the update of a single axis, leaving the other one as the one used in the constructor.

something like this:

Code: Select all

Vector3 _axisA, _axisB;

public TwistLimit(Entity connectionA, Entity connectionB, Vector3 axisA, Vector3 axisB, float minimumAngle, float maximumAngle)
{
	 ConnectionA = connectionA;
	 ConnectionB = connectionB;
	 _axisA = axisA;
	 _axisB = axisB;
	 SetupJointTransforms(axisA, axisB);
	 MinimumAngle = minimumAngle;
	 MaximumAngle = maximumAngle;
}

public Vector3 AxisA
{
	get { return _axisA; }
	set { 
		if (_axisA == value)
			return;
		_axisA = value;
		SetupJointTransforms(_axisA, axisB);
	}
} 
 
public Vector3 AxisB
{
	get { return _axisB; }
	set { 
		if (_axisB == value)
			return;
		_axisB = value;
		SetupJointTransforms(_axisA, _axisB);
	}
} 



IMHO
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: TwistLimit

Post by Norbo »

as you can see, axisA and axisB are never stored inside the class.
The SetupJointTransforms function called by the constructor configures BasisA and BasisB. The bases store the axes.

The axes can be retrieved later by accessing, for example, twistLimit.BasisA.PrimaryAxis, which would be the world space twist axis. The documentation on the BasisA and BasisB properties describes the interpretation of the axes in the bases.
Since all the other classes store internally the values, and expose the Properties in order to update every single value, without knowing how the class works... it would be nice to have the same beahviour on this class too, so have internal field where store axisA and axisB, and two properties which enable the update of a single axis, leaving the other one as the one used in the constructor.
Joints which permit the mutation of individual properties do so because the properties are independent, or because the dependency doesn't affect intended behavior. A couple of examples:
1) Changing a BallSocketJoint's OffsetA only changes the offset associated with A and has no other effect. It is independent.
2) Changing RevoluteAngularJoint.WorldFreeAxisA changes other internal measurement axes, and so is not completely independent. However, as far as the user is concerned, the only mutable state that matters is how the free axis is attached to the bodies, so it behaves like the properties are independent.

Unfortunately, limits and motors are more complicated beasts. Not only do they need the same baseline axes used by the non-limits, they also require a precise definition of a measurement basis. Without that extra explicitly defined information, the constraint can't know how to behave. That information is what Basis properties of the TwistLimit contain. The values stored in the bases are not independent at all; changing one requires a change in the others. However, changing a single axis does not provide enough information to derive unique values for the whole basis. To guarantee uniqueness, the basis only permits changing the whole thing at once.

This is why the nontrivial JointLimits (RevoluteLimit, TwistLimit, EllipseSwingLimit) and Motors (SingleEntityAngularMotor, AngularMotor, RevoluteMotor, TwistMotor) have some kind of Basis properties, and why others don't.

So, the constructor and SetupJointTransforms function are actually deceptive. They imply the joint is simple and can be uniquely defined with very little information, when in reality, it's just guessing arbitrarily at the rest. In practice, even moderately complicated structures almost always require explicitly redefining the bases. You can see this in the BEPUphysicsDemos in most demos where limits or motors are involved. The only reasons the 'convenience' functions/constructors exist are legacy and for ostensible semi-equivalency with the other non-limit constraints. If I did it all over, I would eliminate any customization option which doesn't lead to a unique configuration, since the user can't truly ignore these details.
Post Reply