1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2010 Erwin Coumans  http://continuousphysics.com/Bullet/
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 
16 #ifndef B3_TYPED_CONSTRAINT_H
17 #define B3_TYPED_CONSTRAINT_H
18 
19 #include "Bullet3Common/b3Scalar.h"
20 #include "b3SolverConstraint.h"
21 
22 class b3Serializer;
23 
24 //Don't change any of the existing enum values, so add enum types at the end for serialization compatibility
25 enum b3TypedConstraintType
26 {
27 	B3_POINT2POINT_CONSTRAINT_TYPE = 3,
28 	B3_HINGE_CONSTRAINT_TYPE,
29 	B3_CONETWIST_CONSTRAINT_TYPE,
30 	B3_D6_CONSTRAINT_TYPE,
31 	B3_SLIDER_CONSTRAINT_TYPE,
32 	B3_CONTACT_CONSTRAINT_TYPE,
33 	B3_D6_SPRING_CONSTRAINT_TYPE,
34 	B3_GEAR_CONSTRAINT_TYPE,
35 	B3_FIXED_CONSTRAINT_TYPE,
36 	B3_MAX_CONSTRAINT_TYPE
37 };
38 
39 enum b3ConstraintParams
40 {
41 	B3_CONSTRAINT_ERP = 1,
42 	B3_CONSTRAINT_STOP_ERP,
43 	B3_CONSTRAINT_CFM,
44 	B3_CONSTRAINT_STOP_CFM
45 };
46 
47 #if 1
48 #define b3AssertConstrParams(_par) b3Assert(_par)
49 #else
50 #define b3AssertConstrParams(_par)
51 #endif
52 
B3_ATTRIBUTE_ALIGNED16(struct)53 B3_ATTRIBUTE_ALIGNED16(struct)
54 b3JointFeedback
55 {
56 	b3Vector3 m_appliedForceBodyA;
57 	b3Vector3 m_appliedTorqueBodyA;
58 	b3Vector3 m_appliedForceBodyB;
59 	b3Vector3 m_appliedTorqueBodyB;
60 };
61 
62 struct b3RigidBodyData;
63 
64 ///TypedConstraint is the baseclass for Bullet constraints and vehicles
B3_ATTRIBUTE_ALIGNED16(class)65 B3_ATTRIBUTE_ALIGNED16(class)
66 b3TypedConstraint : public b3TypedObject
67 {
68 	int m_userConstraintType;
69 
70 	union {
71 		int m_userConstraintId;
72 		void* m_userConstraintPtr;
73 	};
74 
75 	b3Scalar m_breakingImpulseThreshold;
76 	bool m_isEnabled;
77 	bool m_needsFeedback;
78 	int m_overrideNumSolverIterations;
79 
80 	b3TypedConstraint& operator=(b3TypedConstraint& other)
81 	{
82 		b3Assert(0);
83 		(void)other;
84 		return *this;
85 	}
86 
87 protected:
88 	int m_rbA;
89 	int m_rbB;
90 	b3Scalar m_appliedImpulse;
91 	b3Scalar m_dbgDrawSize;
92 	b3JointFeedback* m_jointFeedback;
93 
94 	///internal method used by the constraint solver, don't use them directly
95 	b3Scalar getMotorFactor(b3Scalar pos, b3Scalar lowLim, b3Scalar uppLim, b3Scalar vel, b3Scalar timeFact);
96 
97 public:
98 	B3_DECLARE_ALIGNED_ALLOCATOR();
99 
100 	virtual ~b3TypedConstraint(){};
101 	b3TypedConstraint(b3TypedConstraintType type, int bodyA, int bodyB);
102 
103 	struct b3ConstraintInfo1
104 	{
105 		int m_numConstraintRows, nub;
106 	};
107 
108 	struct b3ConstraintInfo2
109 	{
110 		// integrator parameters: frames per second (1/stepsize), default error
111 		// reduction parameter (0..1).
112 		b3Scalar fps, erp;
113 
114 		// for the first and second body, pointers to two (linear and angular)
115 		// n*3 jacobian sub matrices, stored by rows. these matrices will have
116 		// been initialized to 0 on entry. if the second body is zero then the
117 		// J2xx pointers may be 0.
118 		b3Scalar *m_J1linearAxis, *m_J1angularAxis, *m_J2linearAxis, *m_J2angularAxis;
119 
120 		// elements to jump from one row to the next in J's
121 		int rowskip;
122 
123 		// right hand sides of the equation J*v = c + cfm * lambda. cfm is the
124 		// "constraint force mixing" vector. c is set to zero on entry, cfm is
125 		// set to a constant value (typically very small or zero) value on entry.
126 		b3Scalar *m_constraintError, *cfm;
127 
128 		// lo and hi limits for variables (set to -/+ infinity on entry).
129 		b3Scalar *m_lowerLimit, *m_upperLimit;
130 
131 		// findex vector for variables. see the LCP solver interface for a
132 		// description of what this does. this is set to -1 on entry.
133 		// note that the returned indexes are relative to the first index of
134 		// the constraint.
135 		int* findex;
136 		// number of solver iterations
137 		int m_numIterations;
138 
139 		//damping of the velocity
140 		b3Scalar m_damping;
141 	};
142 
143 	int getOverrideNumSolverIterations() const
144 	{
145 		return m_overrideNumSolverIterations;
146 	}
147 
148 	///override the number of constraint solver iterations used to solve this constraint
149 	///-1 will use the default number of iterations, as specified in SolverInfo.m_numIterations
150 	void setOverrideNumSolverIterations(int overideNumIterations)
151 	{
152 		m_overrideNumSolverIterations = overideNumIterations;
153 	}
154 
155 	///internal method used by the constraint solver, don't use them directly
156 	virtual void setupSolverConstraint(b3ConstraintArray & ca, int solverBodyA, int solverBodyB, b3Scalar timeStep)
157 	{
158 		(void)ca;
159 		(void)solverBodyA;
160 		(void)solverBodyB;
161 		(void)timeStep;
162 	}
163 
164 	///internal method used by the constraint solver, don't use them directly
165 	virtual void getInfo1(b3ConstraintInfo1 * info, const b3RigidBodyData* bodies) = 0;
166 
167 	///internal method used by the constraint solver, don't use them directly
168 	virtual void getInfo2(b3ConstraintInfo2 * info, const b3RigidBodyData* bodies) = 0;
169 
170 	///internal method used by the constraint solver, don't use them directly
171 	void internalSetAppliedImpulse(b3Scalar appliedImpulse)
172 	{
173 		m_appliedImpulse = appliedImpulse;
174 	}
175 	///internal method used by the constraint solver, don't use them directly
176 	b3Scalar internalGetAppliedImpulse()
177 	{
178 		return m_appliedImpulse;
179 	}
180 
181 	b3Scalar getBreakingImpulseThreshold() const
182 	{
183 		return m_breakingImpulseThreshold;
184 	}
185 
186 	void setBreakingImpulseThreshold(b3Scalar threshold)
187 	{
188 		m_breakingImpulseThreshold = threshold;
189 	}
190 
191 	bool isEnabled() const
192 	{
193 		return m_isEnabled;
194 	}
195 
196 	void setEnabled(bool enabled)
197 	{
198 		m_isEnabled = enabled;
199 	}
200 
201 	///internal method used by the constraint solver, don't use them directly
202 	virtual void solveConstraintObsolete(b3SolverBody& /*bodyA*/, b3SolverBody& /*bodyB*/, b3Scalar /*timeStep*/){};
203 
204 	int getRigidBodyA() const
205 	{
206 		return m_rbA;
207 	}
208 	int getRigidBodyB() const
209 	{
210 		return m_rbB;
211 	}
212 
213 	int getRigidBodyA()
214 	{
215 		return m_rbA;
216 	}
217 	int getRigidBodyB()
218 	{
219 		return m_rbB;
220 	}
221 
222 	int getUserConstraintType() const
223 	{
224 		return m_userConstraintType;
225 	}
226 
227 	void setUserConstraintType(int userConstraintType)
228 	{
229 		m_userConstraintType = userConstraintType;
230 	};
231 
232 	void setUserConstraintId(int uid)
233 	{
234 		m_userConstraintId = uid;
235 	}
236 
237 	int getUserConstraintId() const
238 	{
239 		return m_userConstraintId;
240 	}
241 
242 	void setUserConstraintPtr(void* ptr)
243 	{
244 		m_userConstraintPtr = ptr;
245 	}
246 
247 	void* getUserConstraintPtr()
248 	{
249 		return m_userConstraintPtr;
250 	}
251 
252 	void setJointFeedback(b3JointFeedback * jointFeedback)
253 	{
254 		m_jointFeedback = jointFeedback;
255 	}
256 
257 	const b3JointFeedback* getJointFeedback() const
258 	{
259 		return m_jointFeedback;
260 	}
261 
262 	b3JointFeedback* getJointFeedback()
263 	{
264 		return m_jointFeedback;
265 	}
266 
267 	int getUid() const
268 	{
269 		return m_userConstraintId;
270 	}
271 
272 	bool needsFeedback() const
273 	{
274 		return m_needsFeedback;
275 	}
276 
277 	///enableFeedback will allow to read the applied linear and angular impulse
278 	///use getAppliedImpulse, getAppliedLinearImpulse and getAppliedAngularImpulse to read feedback information
279 	void enableFeedback(bool needsFeedback)
280 	{
281 		m_needsFeedback = needsFeedback;
282 	}
283 
284 	///getAppliedImpulse is an estimated total applied impulse.
285 	///This feedback could be used to determine breaking constraints or playing sounds.
286 	b3Scalar getAppliedImpulse() const
287 	{
288 		b3Assert(m_needsFeedback);
289 		return m_appliedImpulse;
290 	}
291 
292 	b3TypedConstraintType getConstraintType() const
293 	{
294 		return b3TypedConstraintType(m_objectType);
295 	}
296 
297 	void setDbgDrawSize(b3Scalar dbgDrawSize)
298 	{
299 		m_dbgDrawSize = dbgDrawSize;
300 	}
301 	b3Scalar getDbgDrawSize()
302 	{
303 		return m_dbgDrawSize;
304 	}
305 
306 	///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
307 	///If no axis is provided, it uses the default axis for this constraint.
308 	virtual void setParam(int num, b3Scalar value, int axis = -1) = 0;
309 
310 	///return the local value of parameter
311 	virtual b3Scalar getParam(int num, int axis = -1) const = 0;
312 
313 	//	virtual	int	calculateSerializeBufferSize() const;
314 
315 	///fills the dataBuffer and returns the struct name (and 0 on failure)
316 	//virtual	const char*	serialize(void* dataBuffer, b3Serializer* serializer) const;
317 };
318 
319 // returns angle in range [-B3_2_PI, B3_2_PI], closest to one of the limits
320 // all arguments should be normalized angles (i.e. in range [-B3_PI, B3_PI])
b3AdjustAngleToLimits(b3Scalar angleInRadians,b3Scalar angleLowerLimitInRadians,b3Scalar angleUpperLimitInRadians)321 B3_FORCE_INLINE b3Scalar b3AdjustAngleToLimits(b3Scalar angleInRadians, b3Scalar angleLowerLimitInRadians, b3Scalar angleUpperLimitInRadians)
322 {
323 	if (angleLowerLimitInRadians >= angleUpperLimitInRadians)
324 	{
325 		return angleInRadians;
326 	}
327 	else if (angleInRadians < angleLowerLimitInRadians)
328 	{
329 		b3Scalar diffLo = b3Fabs(b3NormalizeAngle(angleLowerLimitInRadians - angleInRadians));
330 		b3Scalar diffHi = b3Fabs(b3NormalizeAngle(angleUpperLimitInRadians - angleInRadians));
331 		return (diffLo < diffHi) ? angleInRadians : (angleInRadians + B3_2_PI);
332 	}
333 	else if (angleInRadians > angleUpperLimitInRadians)
334 	{
335 		b3Scalar diffHi = b3Fabs(b3NormalizeAngle(angleInRadians - angleUpperLimitInRadians));
336 		b3Scalar diffLo = b3Fabs(b3NormalizeAngle(angleInRadians - angleLowerLimitInRadians));
337 		return (diffLo < diffHi) ? (angleInRadians - B3_2_PI) : angleInRadians;
338 	}
339 	else
340 	{
341 		return angleInRadians;
342 	}
343 }
344 
345 // clang-format off
346 ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64
347 struct	b3TypedConstraintData
348 {
349 	int		m_bodyA;
350 	int		m_bodyB;
351 	char	*m_name;
352 
353 	int	m_objectType;
354 	int	m_userConstraintType;
355 	int	m_userConstraintId;
356 	int	m_needsFeedback;
357 
358 	float	m_appliedImpulse;
359 	float	m_dbgDrawSize;
360 
361 	int	m_disableCollisionsBetweenLinkedBodies;
362 	int	m_overrideNumSolverIterations;
363 
364 	float	m_breakingImpulseThreshold;
365 	int		m_isEnabled;
366 
367 };
368 
369 // clang-format on
370 
371 /*B3_FORCE_INLINE	int	b3TypedConstraint::calculateSerializeBufferSize() const
372 {
373 	return sizeof(b3TypedConstraintData);
374 }
375 */
376 
377 class b3AngularLimit
378 {
379 private:
380 	b3Scalar
381 		m_center,
382 		m_halfRange,
383 		m_softness,
384 		m_biasFactor,
385 		m_relaxationFactor,
386 		m_correction,
387 		m_sign;
388 
389 	bool
390 		m_solveLimit;
391 
392 public:
393 	/// Default constructor initializes limit as inactive, allowing free constraint movement
b3AngularLimit()394 	b3AngularLimit()
395 		: m_center(0.0f),
396 		  m_halfRange(-1.0f),
397 		  m_softness(0.9f),
398 		  m_biasFactor(0.3f),
399 		  m_relaxationFactor(1.0f),
400 		  m_correction(0.0f),
401 		  m_sign(0.0f),
402 		  m_solveLimit(false)
403 	{
404 	}
405 
406 	/// Sets all limit's parameters.
407 	/// When low > high limit becomes inactive.
408 	/// When high - low > 2PI limit is ineffective too becouse no angle can exceed the limit
409 	void set(b3Scalar low, b3Scalar high, b3Scalar _softness = 0.9f, b3Scalar _biasFactor = 0.3f, b3Scalar _relaxationFactor = 1.0f);
410 
411 	/// Checks conastaint angle against limit. If limit is active and the angle violates the limit
412 	/// correction is calculated.
413 	void test(const b3Scalar angle);
414 
415 	/// Returns limit's softness
getSoftness()416 	inline b3Scalar getSoftness() const
417 	{
418 		return m_softness;
419 	}
420 
421 	/// Returns limit's bias factor
getBiasFactor()422 	inline b3Scalar getBiasFactor() const
423 	{
424 		return m_biasFactor;
425 	}
426 
427 	/// Returns limit's relaxation factor
getRelaxationFactor()428 	inline b3Scalar getRelaxationFactor() const
429 	{
430 		return m_relaxationFactor;
431 	}
432 
433 	/// Returns correction value evaluated when test() was invoked
getCorrection()434 	inline b3Scalar getCorrection() const
435 	{
436 		return m_correction;
437 	}
438 
439 	/// Returns sign value evaluated when test() was invoked
getSign()440 	inline b3Scalar getSign() const
441 	{
442 		return m_sign;
443 	}
444 
445 	/// Gives half of the distance between min and max limit angle
getHalfRange()446 	inline b3Scalar getHalfRange() const
447 	{
448 		return m_halfRange;
449 	}
450 
451 	/// Returns true when the last test() invocation recognized limit violation
isLimit()452 	inline bool isLimit() const
453 	{
454 		return m_solveLimit;
455 	}
456 
457 	/// Checks given angle against limit. If limit is active and angle doesn't fit it, the angle
458 	/// returned is modified so it equals to the limit closest to given angle.
459 	void fit(b3Scalar& angle) const;
460 
461 	/// Returns correction value multiplied by sign value
462 	b3Scalar getError() const;
463 
464 	b3Scalar getLow() const;
465 
466 	b3Scalar getHigh() const;
467 };
468 
469 #endif  //B3_TYPED_CONSTRAINT_H
470