1 /*
2  * box2drevolutejoint.cpp
3  * Copyright (c) 2011 Joonas Erkinheimo <joonas.erkinheimo@nokia.com>
4  * Copyright (c) 2011 Markus Kivioja <markus.kivioja@digia.com>
5  *
6  * This file is part of the Box2D QML plugin.
7  *
8  * This software is provided 'as-is', without any express or implied warranty.
9  * In no event will the authors be held liable for any damages arising from
10  * the use of this software.
11  *
12  * Permission is granted to anyone to use this software for any purpose,
13  * including commercial applications, and to alter it and redistribute it
14  * freely, subject to the following restrictions:
15  *
16  * 1. The origin of this software must not be misrepresented; you must not
17  *    claim that you wrote the original software. If you use this software in
18  *    a product, an acknowledgment in the product documentation would be
19  *    appreciated but is not required.
20  *
21  * 2. Altered source versions must be plainly marked as such, and must not be
22  *    misrepresented as being the original software.
23  *
24  * 3. This notice may not be removed or altered from any source distribution.
25  */
26 
27 #include "box2drevolutejoint.h"
28 
29 #include "box2dworld.h"
30 #include "box2dbody.h"
31 
Box2DRevoluteJoint(QObject * parent)32 Box2DRevoluteJoint::Box2DRevoluteJoint(QObject *parent)
33     : Box2DJoint(RevoluteJoint, parent)
34     , m_referenceAngle(0.0f)
35     , m_enableLimit(false)
36     , m_lowerAngle(0.0f)
37     , m_upperAngle(0.0f)
38     , m_enableMotor(false)
39     , m_motorSpeed(0.0f)
40     , m_maxMotorTorque(0.0f)
41     , m_defaultLocalAnchorA(true)
42     , m_defaultLocalAnchorB(true)
43     , m_defaultReferenceAngle(true)
44 {
45 }
46 
setLocalAnchorA(const QPointF & localAnchorA)47 void Box2DRevoluteJoint::setLocalAnchorA(const QPointF &localAnchorA)
48 {
49     m_defaultLocalAnchorA = false;
50 
51     if (m_localAnchorA == localAnchorA)
52         return;
53 
54     m_localAnchorA = localAnchorA;
55     emit localAnchorAChanged();
56 }
57 
setLocalAnchorB(const QPointF & localAnchorB)58 void Box2DRevoluteJoint::setLocalAnchorB(const QPointF &localAnchorB)
59 {
60     m_defaultLocalAnchorB = false;
61 
62     if (m_localAnchorB == localAnchorB)
63         return;
64 
65     m_localAnchorB = localAnchorB;
66     emit localAnchorBChanged();
67 }
68 
setReferenceAngle(float referenceAngle)69 void Box2DRevoluteJoint::setReferenceAngle(float referenceAngle)
70 {
71     m_defaultReferenceAngle = false;
72 
73     if (m_referenceAngle == referenceAngle)
74         return;
75 
76     m_referenceAngle = referenceAngle;
77     emit referenceAngleChanged();
78 }
79 
setEnableLimit(bool enableLimit)80 void Box2DRevoluteJoint::setEnableLimit(bool enableLimit)
81 {
82     if (m_enableLimit == enableLimit)
83         return;
84 
85     m_enableLimit = enableLimit;
86     if (revoluteJoint())
87         revoluteJoint()->EnableLimit(enableLimit);
88     emit enableLimitChanged();
89 }
90 
setLowerAngle(float lowerAngle)91 void Box2DRevoluteJoint::setLowerAngle(float lowerAngle)
92 {
93     if (m_lowerAngle == lowerAngle)
94         return;
95 
96     m_lowerAngle = lowerAngle;
97     if (revoluteJoint())
98         revoluteJoint()->SetLimits(toRadians(lowerAngle),
99                                    toRadians(m_upperAngle));
100     emit lowerAngleChanged();
101 }
102 
setUpperAngle(float upperAngle)103 void Box2DRevoluteJoint::setUpperAngle(float upperAngle)
104 {
105     if (m_upperAngle == upperAngle)
106         return;
107 
108     m_upperAngle = upperAngle;
109     if (revoluteJoint())
110         revoluteJoint()->SetLimits(toRadians(m_lowerAngle),
111                                    toRadians(upperAngle));
112     emit upperAngleChanged();
113 }
114 
setEnableMotor(bool enableMotor)115 void Box2DRevoluteJoint::setEnableMotor(bool enableMotor)
116 {
117     if (m_enableMotor == enableMotor)
118         return;
119 
120     m_enableMotor = enableMotor;
121     if (revoluteJoint())
122         revoluteJoint()->EnableMotor(enableMotor);
123     emit enableMotorChanged();
124 }
125 
setMotorSpeed(float motorSpeed)126 void Box2DRevoluteJoint::setMotorSpeed(float motorSpeed)
127 {
128     if (m_motorSpeed == motorSpeed)
129         return;
130 
131     m_motorSpeed = motorSpeed;
132     if (revoluteJoint())
133         revoluteJoint()->SetMotorSpeed(toRadians(motorSpeed));
134     emit motorSpeedChanged();
135 }
136 
setMaxMotorTorque(float maxMotorTorque)137 void Box2DRevoluteJoint::setMaxMotorTorque(float maxMotorTorque)
138 {
139     if (m_maxMotorTorque == maxMotorTorque)
140         return;
141 
142     m_maxMotorTorque = maxMotorTorque;
143     if (revoluteJoint())
144         revoluteJoint()->SetMaxMotorTorque(maxMotorTorque);
145     emit maxMotorTorqueChanged();
146 }
147 
createJoint()148 b2Joint *Box2DRevoluteJoint::createJoint()
149 {
150     b2RevoluteJointDef jointDef;
151     initializeJointDef(jointDef);
152 
153     // Default localAnchorA to bodyA center
154     if (m_defaultLocalAnchorA)
155         jointDef.localAnchorA = jointDef.bodyA->GetLocalCenter();
156     else
157         jointDef.localAnchorA = world()->toMeters(m_localAnchorA);
158 
159     // Default localAnchorB to the same world position as localAnchorA
160     if (m_defaultLocalAnchorB) {
161         b2Vec2 anchorA = jointDef.bodyA->GetWorldPoint(jointDef.localAnchorA);
162         jointDef.localAnchorB = jointDef.bodyB->GetLocalPoint(anchorA);
163     } else {
164         jointDef.localAnchorB = world()->toMeters(m_localAnchorB);
165     }
166 
167     if (m_defaultReferenceAngle) {
168         float32 angleA = jointDef.bodyA->GetAngle();
169         float32 angleB = jointDef.bodyB->GetAngle();
170         jointDef.referenceAngle = angleB - angleA;
171     } else {
172         jointDef.referenceAngle = toRadians(m_referenceAngle);
173     }
174 
175     jointDef.enableLimit = m_enableLimit;
176     jointDef.lowerAngle = toRadians(m_lowerAngle);
177     jointDef.upperAngle = toRadians(m_upperAngle);
178     jointDef.enableMotor = m_enableMotor;
179     jointDef.motorSpeed = toRadians(m_motorSpeed);
180     jointDef.maxMotorTorque = m_maxMotorTorque;
181 
182     return world()->world().CreateJoint(&jointDef);
183 }
184 
getJointAngle() const185 float Box2DRevoluteJoint::getJointAngle() const
186 {
187     if (revoluteJoint())
188         return toDegrees(revoluteJoint()->GetJointAngle());
189     return 0.0;
190 }
191 
getJointSpeed() const192 float Box2DRevoluteJoint::getJointSpeed() const
193 {
194     if (revoluteJoint())
195         return revoluteJoint()->GetJointSpeed();
196     return 0.0;
197 }
198