1 /*
2  * Copyright (c) 2007-2013 Scott Lembcke and Howling Moon Software
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 module dchip.cpPivotJoint;
23 
24 import std.string;
25 
26 import dchip.constraints_util;
27 import dchip.chipmunk;
28 import dchip.cpBody;
29 import dchip.cpConstraint;
30 import dchip.chipmunk_types;
31 import dchip.cpVect;
32 
33 //~ const cpConstraintClass* cpPivotJointGetClass();
34 
35 /// @private
36 struct cpPivotJoint
37 {
38     cpConstraint constraint;
39     cpVect anchr1, anchr2;
40 
41     cpVect r1, r2;
42     cpMat2x2 k;
43 
44     cpVect jAcc;
45     cpVect bias;
46 }
47 
48 mixin CP_DefineConstraintProperty!("cpPivotJoint", cpVect, "anchr1", "Anchr1");
49 mixin CP_DefineConstraintProperty!("cpPivotJoint", cpVect, "anchr2", "Anchr2");
50 
51 void preStep(cpPivotJoint* joint, cpFloat dt)
52 {
53     cpBody* a = joint.constraint.a;
54     cpBody* b = joint.constraint.b;
55 
56     joint.r1 = cpvrotate(joint.anchr1, a.rot);
57     joint.r2 = cpvrotate(joint.anchr2, b.rot);
58 
59     // Calculate mass tensor
60     joint.k = k_tensor(a, b, joint.r1, joint.r2);
61 
62     // calculate bias velocity
63     cpVect delta = cpvsub(cpvadd(b.p, joint.r2), cpvadd(a.p, joint.r1));
64     joint.bias = cpvclamp(cpvmult(delta, -bias_coef(joint.constraint.errorBias, dt) / dt), joint.constraint.maxBias);
65 }
66 
67 void applyCachedImpulse(cpPivotJoint* joint, cpFloat dt_coef)
68 {
69     cpBody* a = joint.constraint.a;
70     cpBody* b = joint.constraint.b;
71 
72     apply_impulses(a, b, joint.r1, joint.r2, cpvmult(joint.jAcc, dt_coef));
73 }
74 
75 void applyImpulse(cpPivotJoint* joint, cpFloat dt)
76 {
77     cpBody* a = joint.constraint.a;
78     cpBody* b = joint.constraint.b;
79 
80     cpVect r1 = joint.r1;
81     cpVect r2 = joint.r2;
82 
83     // compute relative velocity
84     cpVect vr = relative_velocity(a, b, r1, r2);
85 
86     // compute normal impulse
87     cpVect j    = cpMat2x2Transform(joint.k, cpvsub(joint.bias, vr));
88     cpVect jOld = joint.jAcc;
89     joint.jAcc = cpvclamp(cpvadd(joint.jAcc, j), joint.constraint.maxForce * dt);
90     j = cpvsub(joint.jAcc, jOld);
91 
92     // apply impulse
93     apply_impulses(a, b, joint.r1, joint.r2, j);
94 }
95 
96 cpFloat getImpulse(cpConstraint* joint)
97 {
98     return cpvlength((cast(cpPivotJoint*)joint).jAcc);
99 }
100 
101 __gshared cpConstraintClass klass;
102 
103 void _initModuleCtor_cpPivotJoint()
104 {
105     klass = cpConstraintClass(
106         cast(cpConstraintPreStepImpl)&preStep,
107         cast(cpConstraintApplyCachedImpulseImpl)&applyCachedImpulse,
108         cast(cpConstraintApplyImpulseImpl)&applyImpulse,
109         cast(cpConstraintGetImpulseImpl)&getImpulse,
110     );
111 };
112 
113 const(cpConstraintClass *) cpPivotJointGetClass()
114 {
115     return cast(cpConstraintClass*)&klass;
116 }
117 
118 cpPivotJoint *
119 cpPivotJointAlloc()
120 {
121     return cast(cpPivotJoint*)cpcalloc(1, cpPivotJoint.sizeof);
122 }
123 
124 cpPivotJoint* cpPivotJointInit(cpPivotJoint* joint, cpBody* a, cpBody* b, cpVect anchr1, cpVect anchr2)
125 {
126     cpConstraintInit(cast(cpConstraint*)joint, &klass, a, b);
127 
128     joint.anchr1 = anchr1;
129     joint.anchr2 = anchr2;
130 
131     joint.jAcc = cpvzero;
132 
133     return joint;
134 }
135 
136 cpConstraint* cpPivotJointNew2(cpBody* a, cpBody* b, cpVect anchr1, cpVect anchr2)
137 {
138     return cast(cpConstraint*)cpPivotJointInit(cpPivotJointAlloc(), a, b, anchr1, anchr2);
139 }
140 
141 cpConstraint* cpPivotJointNew(cpBody* a, cpBody* b, cpVect pivot)
142 {
143     cpVect anchr1 = (a ? cpBodyWorld2Local(a, pivot) : pivot);
144     cpVect anchr2 = (b ? cpBodyWorld2Local(b, pivot) : pivot);
145     return cpPivotJointNew2(a, b, anchr1, anchr2);
146 }