With a hinge joint, one usually wants to do the following things:
- apply angle limits
- get current angle
- make it move to a desired angle (optionally set maximum force applied to get there)
- apply torque
- get the speed at which the joint is turning
- brake the rotation of the hinge (optionally set the maximum force)
These are exactly what I needed and instead of making another custom joint, I modified the one in JointLibrary. I am not sure whether I implemented these correctly, but here is the source:
CustomHinge.h
- Code: Select all
/* Copyright (c) <2009> <Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely
*/
// CustomHinge.h: interface for the CustomHinge class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_CUSTOMHINGE_H__B631F556_468B_4331_B7D7_F85ECF3E9ADE__INCLUDED_)
#define AFX_CUSTOMHINGE_H__B631F556_468B_4331_B7D7_F85ECF3E9ADE__INCLUDED_
#include "NewtonCustomJoint.h"
class JOINTLIBRARY_API CustomHinge: public NewtonCustomJoint
{
public:
CustomHinge (const dMatrix& pinsAndPivoFrame, const NewtonBody* child, const NewtonBody* parent = NULL);
virtual ~CustomHinge();
void EnableLimits(bool state);
void SetLimis(dFloat minAngle, dFloat maxAngle);
//! Try to move to this angle, has effect for single frame
void ApplyDesiredAngle(dFloat angle, dFloat minFriction = 0, dFloat maxFriction = 0);
//! Apply given torque for one frame
void ApplyTorque(dFloat torque);
//! Apply brake for one frame
// -1: brake with infinite force
// 0: no brake
// > 0: brake with limited force
void ApplyBrake(dFloat maxForce = -1);
dFloat getCurrentAngle();
dFloat getVelocity();
protected:
virtual void GetInfo (NewtonJointRecord* info) const;
virtual void SubmitConstraints (dFloat timestep, int threadIndex);
dMatrix m_localMatrix0;
dMatrix m_localMatrix1;
bool m_limitsOn;
dFloat m_minAngle;
dFloat m_maxAngle;
bool m_motorOn;
dFloat m_desiredAngle;
dFloat m_motorMinFriction;
dFloat m_motorMaxFriction;
dFloat m_torque;
dFloat m_brake;
AngularIntegration m_curJointAngle;
};
#endif // !defined(AFX_CUSTOMHINGE_H__B631F556_468B_4331_B7D7_F85ECF3E9ADE__INCLUDED_)
CustomHinge.cpp
- Code: Select all
/* Copyright (c) <2009> <Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely
*/
// CustomHinge.cpp: implementation of the CustomHinge class.
//
//////////////////////////////////////////////////////////////////////
#include "CustomJointLibraryStdAfx.h"
#include "CustomHinge.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define MIN_JOINT_PIN_LENGTH 50.0f
CustomHinge::CustomHinge (const dMatrix& pinAndPivotFrame, const NewtonBody* child, const NewtonBody* parent)
:NewtonCustomJoint(6, child, parent), m_curJointAngle()
{
m_limitsOn = false;
m_minAngle = -45.0f * 3.141592f / 180.0f;
m_maxAngle = 45.0f * 3.141592f / 180.0f;
m_motorOn = false;
m_desiredAngle = 0;
m_motorMinFriction = 0;
m_motorMaxFriction = 0;
m_torque = 0;
m_brake = 0;
// calculate the two local matrix of the pivot point
CalculateLocalMatrix (pinAndPivotFrame, m_localMatrix0, m_localMatrix1);
}
CustomHinge::~CustomHinge()
{
}
void CustomHinge::EnableLimits(bool state)
{
m_limitsOn = state;
}
void CustomHinge::SetLimis(dFloat minAngle, dFloat maxAngle)
{
//_ASSERTE (minAngle < 0.0f);
//_ASSERTE (maxAngle > 0.0f);
m_minAngle = minAngle;
m_maxAngle = maxAngle;
m_limitsOn = true;
}
void CustomHinge::ApplyDesiredAngle(dFloat angle, dFloat minFriction, dFloat maxFriction)
{
m_desiredAngle = angle;
m_motorMinFriction = minFriction;
m_motorMaxFriction = maxFriction;
m_motorOn = true;
}
void CustomHinge::ApplyTorque(dFloat torque)
{
m_torque = torque;
}
void CustomHinge::ApplyBrake(dFloat maxForce)
{
m_brake = maxForce;
}
void CustomHinge::SubmitConstraints (dFloat timestep, int threadIndex)
{
dMatrix matrix0;
dMatrix matrix1;
// calculate the position of the pivot point and the Jacobian direction vectors, in global space.
CalculateGlobalMatrix (m_localMatrix0, m_localMatrix1, matrix0, matrix1);
// Restrict the movement on the pivot point along all tree orthonormal direction
NewtonUserJointAddLinearRow (m_joint, &matrix0.m_posit[0], &matrix1.m_posit[0], &matrix0.m_front[0]);
NewtonUserJointAddLinearRow (m_joint, &matrix0.m_posit[0], &matrix1.m_posit[0], &matrix0.m_up[0]);
NewtonUserJointAddLinearRow (m_joint, &matrix0.m_posit[0], &matrix1.m_posit[0], &matrix0.m_right[0]);
// get a point along the pin axis at some reasonable large distance from the pivot
dVector q0 (matrix0.m_posit + matrix0.m_front.Scale(MIN_JOINT_PIN_LENGTH));
dVector q1 (matrix1.m_posit + matrix1.m_front.Scale(MIN_JOINT_PIN_LENGTH));
// two constraints row perpendicular to the pin vector
NewtonUserJointAddLinearRow (m_joint, &q0[0], &q1[0], &matrix0.m_up[0]);
NewtonUserJointAddLinearRow (m_joint, &q0[0], &q1[0], &matrix0.m_right[0]);
// if limit or motor are enabled ...
if (m_limitsOn || m_motorOn || m_torque != 0 || m_brake != 0) {
dFloat angle;
dFloat sinAngle;
dFloat cosAngle;
// the joint angle can be determine by getting the angle between any two non parallel vectors
sinAngle = (matrix0.m_up * matrix1.m_up) % matrix0.m_front;
cosAngle = matrix0.m_up % matrix1.m_up;
angle = m_curJointAngle.CalculateJointAngle (cosAngle, sinAngle);
if (m_limitsOn && angle < m_minAngle) {
dFloat relAngle;
relAngle = angle - m_minAngle;
// the angle was clipped save the new clip limit
m_curJointAngle.m_angle = m_minAngle;
// tell joint error will minimize the exceeded angle error
NewtonUserJointAddAngularRow (m_joint, relAngle, &matrix0.m_front[0]);
// need high stiffness here
NewtonUserJointSetRowStiffness (m_joint, 1.0f);
// allow the joint to move back freely
NewtonUserJointSetRowMaximumFriction (m_joint, 0.0f);
} else if (m_limitsOn && angle > m_maxAngle) {
dFloat relAngle;
relAngle = angle - m_maxAngle;
// the angle was clipped save the new clip limit
m_curJointAngle.m_angle = m_maxAngle;
// tell joint error will minimize the exceeded angle error
NewtonUserJointAddAngularRow (m_joint, relAngle, &matrix0.m_front[0]);
// need high stiffness here
NewtonUserJointSetRowStiffness (m_joint, 1.0f);
// allow the joint to move back freely
NewtonUserJointSetRowMinimumFriction (m_joint, 0.0f);
} else if (m_motorOn) {
// find relative angle
dFloat relAngle = angle - m_desiredAngle;
// the angle was clipped save the new clip limit
m_curJointAngle.m_angle = m_desiredAngle;
// tell joint error will minimize the exceeded angle error
NewtonUserJointAddAngularRow (m_joint, relAngle, &matrix0.m_front[0]);
// need high stiffness here
NewtonUserJointSetRowStiffness (m_joint, 1.0f);
// set minimum friction if available
if (m_motorMinFriction < 0) {
NewtonUserJointSetRowMinimumFriction (m_joint, m_motorMinFriction);
}
// set maximum friction if available
if (m_motorMaxFriction > 0) {
NewtonUserJointSetRowMaximumFriction (m_joint, m_motorMaxFriction);
}
m_motorOn = false;
} else if (m_brake != 0) {
// the angle was clipped save the new clip limit
m_curJointAngle.m_angle = angle;
// tell joint error will minimize the exceeded angle error
NewtonUserJointAddAngularRow (m_joint, 0, &matrix0.m_front[0]);
// need high stiffness here
NewtonUserJointSetRowStiffness (m_joint, 1.0f);
// set brake friction if available
if (m_brake > 0) {
NewtonUserJointSetRowMinimumFriction (m_joint, -m_brake);
NewtonUserJointSetRowMaximumFriction (m_joint, m_brake);
}
m_brake = 0;
} else if (m_torque != 0) {
// add some torque directly to child body
// not sure if this is correct or the best way
dVector childTorqueVector = matrix0.m_front.Scale(m_torque);
NewtonBodyAddTorque (m_body0, &childTorqueVector[0]);
/* Would this be correct?
if (m_body1)
{
dVector parentTorqueVector = matrix1.m_front.Scale(-m_torque);
NewtonBodyAddTorque (m_body1, &parentTorqueVector[0]);
}
*/
m_torque = 0;
}
}
}
dFloat CustomHinge::getCurrentAngle()
{
dMatrix matrix0;
dMatrix matrix1;
// calculate the position of the pivot point and the Jacobian direction vectors, in global space.
CalculateGlobalMatrix (m_localMatrix0, m_localMatrix1, matrix0, matrix1);
// the joint angle can be determine by getting the angle between any two non parallel vectors
dFloat sinAngle = (matrix0.m_up * matrix1.m_up) % matrix0.m_front;
dFloat cosAngle = matrix0.m_up % matrix1.m_up;
return m_curJointAngle.CalculateJointAngle (cosAngle, sinAngle);
}
dFloat CustomHinge::getVelocity()
{
dMatrix matrix0;
dMatrix matrix1;
// calculate the position of the pivot point and the Jacobian direction vectors, in global space.
CalculateGlobalMatrix (m_localMatrix0, m_localMatrix1, matrix0, matrix1);
dVector omega;
NewtonBodyGetOmega(m_body0, &omega[0]);
return omega % matrix0.m_front;
}
void CustomHinge::GetInfo (NewtonJointRecord* info) const
{
strcpy (info->m_descriptionType, "hinge");
info->m_attachBody_0 = m_body0;
info->m_attachBody_1 = m_body1;
info->m_minLinearDof[0] = 0.0f;
info->m_maxLinearDof[0] = 0.0f;
info->m_minLinearDof[1] = 0.0f;
info->m_maxLinearDof[1] = 0.0f;;
info->m_minLinearDof[2] = 0.0f;
info->m_maxLinearDof[2] = 0.0f;
// the joint angle can be determine by getting the angle between any two non parallel vectors
if (m_limitsOn) {
dFloat angle;
dFloat sinAngle;
dFloat cosAngle;
dMatrix matrix0;
dMatrix matrix1;
// calculate the position of the pivot point and the Jacobian direction vectors, in global space.
CalculateGlobalMatrix (m_localMatrix0, m_localMatrix1, matrix0, matrix1);
sinAngle = (matrix0.m_up * matrix1.m_up) % matrix0.m_front;
cosAngle = matrix0.m_up % matrix1.m_up;
angle = dAtan2 (sinAngle, cosAngle);
info->m_minAngularDof[0] = (m_minAngle - angle) * 180.0f / 3.141592f ;
info->m_maxAngularDof[0] = (m_maxAngle - angle) * 180.0f / 3.141592f ;
} else {
info->m_minAngularDof[0] = -FLT_MAX ;
info->m_maxAngularDof[0] = FLT_MAX ;
}
info->m_minAngularDof[1] = 0.0f;
info->m_maxAngularDof[1] = 0.0f;
info->m_minAngularDof[2] = 0.0f;
info->m_maxAngularDof[2] = 0.0f;
memcpy (info->m_attachmenMatrix_0, &m_localMatrix0, sizeof (dMatrix));
memcpy (info->m_attachmenMatrix_1, &m_localMatrix1, sizeof (dMatrix));
}
Julio, could you please verify that what I am doing is correct (it probably is not entirely, I'm still a beginner

