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