Revision control
Copy as Markdown
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qsphericaljoint_p.h"
#include "physxnode/qphysxactorbody_p.h"
#include "qabstractphysicsnode_p.h"
#include "qstaticphysxobjects_p.h"
#include <extensions/PxSphericalJoint.h>
QT_BEGIN_NAMESPACE
/*!
\qmltype SphericalJoint
\inqmlmodule QtQuick3D.Physics
\since 6.12
\inherits FlexibleJoint
\brief A spherical joint.
A spherical joint, also known as a ball-and-socket joint, keeps the origins
together, but allows the orientations to vary freely.
\sa {DistanceJoint}
\sa {FixedJoint}
\sa {PrismaticJoint}
\sa {RevoluteJoint}
\sa {D6Joint}
*/
/*!
\qmlproperty real SphericalJoint::coneLimitY
\since 6.12
\default pi/2
The y limit (in radians) of the joint's cone constraint.
Range: \c{(0, pi)}
\sa coneLimitZ
*/
/*!
\qmlproperty real SphericalJoint::coneLimitZ
\since 6.12
\default pi/2
The z limit (in radians) of the joint's cone constraint.
Range: \c{(0, pi)}
\sa coneLimitY
*/
/*!
\qmlproperty bool SphericalJoint::enableConeLimit
\since 6.12
\default false
Enable the cone limit constraint for the joint.
*/
float QSphericalJoint::coneLimitY() const
{
return m_coneLimitY;
}
void QSphericalJoint::setConeLimitY(float newConeLimitY)
{
// PxJointLimitCone::isValid() requires yAngle strictly within (0, PxPi),
// so the margin keeps the clamped value off both boundaries.
newConeLimitY = qBound(1e-4f, newConeLimitY, physx::PxPi - 1e-4f);
if (qFuzzyCompare(m_coneLimitY, newConeLimitY))
return;
m_coneLimitY = newConeLimitY;
m_dirtyProperties = true;
emit coneLimitYChanged();
}
float QSphericalJoint::coneLimitZ() const
{
return m_coneLimitZ;
}
void QSphericalJoint::setConeLimitZ(float newConeLimitZ)
{
// PxJointLimitCone::isValid() requires zAngle strictly within (0, PxPi),
// so the margin keeps the clamped value off both boundaries.
newConeLimitZ = qBound(1e-4f, newConeLimitZ, physx::PxPi - 1e-4f);
if (qFuzzyCompare(m_coneLimitZ, newConeLimitZ))
return;
m_coneLimitZ = newConeLimitZ;
m_dirtyProperties = true;
emit coneLimitZChanged();
}
bool QSphericalJoint::enableConeLimit() const
{
return m_enableConeLimit;
}
void QSphericalJoint::setEnableConeLimit(bool newEnableConeLimit)
{
if (m_enableConeLimit == newEnableConeLimit)
return;
m_enableConeLimit = newEnableConeLimit;
m_dirtyProperties = true;
emit enableConeLimitChanged();
}
physx::PxJoint *QSphericalJoint::createPhysxJoint(physx::PxRigidActor *actorA,
physx::PxRigidActor *actorB,
const physx::PxTransform &trfA,
const physx::PxTransform &trfB)
{
return physx::PxSphericalJointCreate(*StaticPhysXObjects::getReference().physics, actorA, trfA,
actorB, trfB);
}
void QSphericalJoint::setJointProperties()
{
physx::PxSphericalJoint *joint = static_cast<physx::PxSphericalJoint *>(m_joint);
physx::PxJointLimitCone limit(m_coneLimitY, m_coneLimitZ);
limit.stiffness = m_stiffness;
limit.damping = m_damping;
joint->setLimitCone(limit);
joint->setSphericalJointFlag(physx::PxSphericalJointFlag::eLIMIT_ENABLED, m_enableConeLimit);
}
QT_END_NAMESPACE