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.cpRatchetJoint; 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* cpRatchetJointGetClass(); 34 35 /// @private 36 struct cpRatchetJoint 37 { 38 cpConstraint constraint; 39 cpFloat angle = 0, phase = 0, ratchet = 0; 40 41 cpFloat iSum = 0; 42 43 cpFloat bias = 0; 44 cpFloat jAcc = 0; 45 } 46 47 mixin CP_DefineConstraintProperty!("cpRatchetJoint", cpFloat, "angle", "Angle"); 48 mixin CP_DefineConstraintProperty!("cpRatchetJoint", cpFloat, "phase", "Phase"); 49 mixin CP_DefineConstraintProperty!("cpRatchetJoint", cpFloat, "ratchet", "Ratchet"); 50 51 void preStep(cpRatchetJoint* joint, cpFloat dt) 52 { 53 cpBody* a = joint.constraint.a; 54 cpBody* b = joint.constraint.b; 55 56 cpFloat angle = joint.angle; 57 cpFloat phase = joint.phase; 58 cpFloat ratchet = joint.ratchet; 59 60 cpFloat delta = b.a - a.a; 61 cpFloat diff = angle - delta; 62 cpFloat pdist = 0.0f; 63 64 if (diff * ratchet > 0.0f) 65 { 66 pdist = diff; 67 } 68 else 69 { 70 joint.angle = cpffloor((delta - phase) / ratchet) * ratchet + phase; 71 } 72 73 // calculate moment of inertia coefficient. 74 joint.iSum = 1.0f / (a.i_inv + b.i_inv); 75 76 // calculate bias velocity 77 cpFloat maxBias = joint.constraint.maxBias; 78 joint.bias = cpfclamp(-bias_coef(joint.constraint.errorBias, dt) * pdist / dt, -maxBias, maxBias); 79 80 // If the bias is 0, the joint is not at a limit. Reset the impulse. 81 if (!joint.bias) 82 joint.jAcc = 0.0f; 83 } 84 85 void applyCachedImpulse(cpRatchetJoint* joint, cpFloat dt_coef) 86 { 87 cpBody* a = joint.constraint.a; 88 cpBody* b = joint.constraint.b; 89 90 cpFloat j = joint.jAcc * dt_coef; 91 a.w -= j * a.i_inv; 92 b.w += j * b.i_inv; 93 } 94 95 void applyImpulse(cpRatchetJoint* joint, cpFloat dt) 96 { 97 if (!joint.bias) 98 return; // early exit 99 100 cpBody* a = joint.constraint.a; 101 cpBody* b = joint.constraint.b; 102 103 // compute relative rotational velocity 104 cpFloat wr = b.w - a.w; 105 cpFloat ratchet = joint.ratchet; 106 107 cpFloat jMax = joint.constraint.maxForce * dt; 108 109 // compute normal impulse 110 cpFloat j = -(joint.bias + wr) * joint.iSum; 111 cpFloat jOld = joint.jAcc; 112 joint.jAcc = cpfclamp((jOld + j) * ratchet, 0.0f, jMax * cpfabs(ratchet)) / ratchet; 113 j = joint.jAcc - jOld; 114 115 // apply impulse 116 a.w -= j * a.i_inv; 117 b.w += j * b.i_inv; 118 } 119 120 cpFloat getImpulse(cpRatchetJoint* joint) 121 { 122 return cpfabs(joint.jAcc); 123 } 124 125 __gshared cpConstraintClass klass; 126 127 void _initModuleCtor_cpRatchetJoint() 128 { 129 klass = cpConstraintClass( 130 cast(cpConstraintPreStepImpl)&preStep, 131 cast(cpConstraintApplyCachedImpulseImpl)&applyCachedImpulse, 132 cast(cpConstraintApplyImpulseImpl)&applyImpulse, 133 cast(cpConstraintGetImpulseImpl)&getImpulse, 134 ); 135 } 136 137 const(cpConstraintClass *) cpRatchetJointGetClass() 138 { 139 return cast(cpConstraintClass*)&klass; 140 } 141 142 cpRatchetJoint * 143 cpRatchetJointAlloc() 144 { 145 return cast(cpRatchetJoint*)cpcalloc(1, cpRatchetJoint.sizeof); 146 } 147 148 cpRatchetJoint* cpRatchetJointInit(cpRatchetJoint* joint, cpBody* a, cpBody* b, cpFloat phase, cpFloat ratchet) 149 { 150 cpConstraintInit(cast(cpConstraint*)joint, &klass, a, b); 151 152 joint.angle = 0.0f; 153 joint.phase = phase; 154 joint.ratchet = ratchet; 155 156 // STATIC_BODY_CHECK 157 joint.angle = (b ? b.a : 0.0f) - (a ? a.a : 0.0f); 158 159 return joint; 160 } 161 162 cpConstraint* cpRatchetJointNew(cpBody* a, cpBody* b, cpFloat phase, cpFloat ratchet) 163 { 164 return cast(cpConstraint*)cpRatchetJointInit(cpRatchetJointAlloc(), a, b, phase, ratchet); 165 }