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.cpSlideJoint; 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* cpSlideJointGetClass(); 34 35 /// @private 36 struct cpSlideJoint 37 { 38 cpConstraint constraint; 39 cpVect anchr1, anchr2; 40 cpFloat min = 0, max = 0; 41 42 cpVect r1, r2; 43 cpVect n; 44 cpFloat nMass = 0; 45 46 cpFloat jnAcc = 0; 47 cpFloat bias = 0; 48 } 49 50 mixin CP_DefineConstraintProperty!("cpSlideJoint", cpVect, "anchr1", "Anchr1"); 51 mixin CP_DefineConstraintProperty!("cpSlideJoint", cpVect, "anchr2", "Anchr2"); 52 mixin CP_DefineConstraintProperty!("cpSlideJoint", cpFloat, "min", "Min"); 53 mixin CP_DefineConstraintProperty!("cpSlideJoint", cpFloat, "max", "Max"); 54 55 void preStep(cpSlideJoint* joint, cpFloat dt) 56 { 57 cpBody* a = joint.constraint.a; 58 cpBody* b = joint.constraint.b; 59 60 joint.r1 = cpvrotate(joint.anchr1, a.rot); 61 joint.r2 = cpvrotate(joint.anchr2, b.rot); 62 63 cpVect delta = cpvsub(cpvadd(b.p, joint.r2), cpvadd(a.p, joint.r1)); 64 cpFloat dist = cpvlength(delta); 65 cpFloat pdist = 0.0f; 66 67 if (dist > joint.max) 68 { 69 pdist = dist - joint.max; 70 joint.n = cpvnormalize_safe(delta); 71 } 72 else if (dist < joint.min) 73 { 74 pdist = joint.min - dist; 75 joint.n = cpvneg(cpvnormalize_safe(delta)); 76 } 77 else 78 { 79 joint.n = cpvzero; 80 joint.jnAcc = 0.0f; 81 } 82 83 // calculate mass normal 84 joint.nMass = 1.0f / k_scalar(a, b, joint.r1, joint.r2, joint.n); 85 86 // calculate bias velocity 87 cpFloat maxBias = joint.constraint.maxBias; 88 joint.bias = cpfclamp(-bias_coef(joint.constraint.errorBias, dt) * pdist / dt, -maxBias, maxBias); 89 } 90 91 void applyCachedImpulse(cpSlideJoint* joint, cpFloat dt_coef) 92 { 93 cpBody* a = joint.constraint.a; 94 cpBody* b = joint.constraint.b; 95 96 cpVect j = cpvmult(joint.n, joint.jnAcc * dt_coef); 97 apply_impulses(a, b, joint.r1, joint.r2, j); 98 } 99 100 void applyImpulse(cpSlideJoint* joint, cpFloat dt) 101 { 102 if (cpveql(joint.n, cpvzero)) 103 return; // early exit 104 105 cpBody* a = joint.constraint.a; 106 cpBody* b = joint.constraint.b; 107 108 cpVect n = joint.n; 109 cpVect r1 = joint.r1; 110 cpVect r2 = joint.r2; 111 112 // compute relative velocity 113 cpVect vr = relative_velocity(a, b, r1, r2); 114 cpFloat vrn = cpvdot(vr, n); 115 116 // compute normal impulse 117 cpFloat jn = (joint.bias - vrn) * joint.nMass; 118 cpFloat jnOld = joint.jnAcc; 119 joint.jnAcc = cpfclamp(jnOld + jn, -joint.constraint.maxForce * dt, 0.0f); 120 jn = joint.jnAcc - jnOld; 121 122 // apply impulse 123 apply_impulses(a, b, joint.r1, joint.r2, cpvmult(n, jn)); 124 } 125 126 cpFloat getImpulse(cpConstraint* joint) 127 { 128 return cpfabs((cast(cpSlideJoint*)joint).jnAcc); 129 } 130 131 __gshared cpConstraintClass klass; 132 133 void _initModuleCtor_cpSlideJoint() 134 { 135 klass = cpConstraintClass( 136 cast(cpConstraintPreStepImpl)&preStep, 137 cast(cpConstraintApplyCachedImpulseImpl)&applyCachedImpulse, 138 cast(cpConstraintApplyImpulseImpl)&applyImpulse, 139 cast(cpConstraintGetImpulseImpl)&getImpulse, 140 ); 141 } 142 143 const(cpConstraintClass *) cpSlideJointGetClass() 144 { 145 return cast(cpConstraintClass*)&klass; 146 } 147 148 cpSlideJoint * 149 cpSlideJointAlloc() 150 { 151 return cast(cpSlideJoint*)cpcalloc(1, cpSlideJoint.sizeof); 152 } 153 154 cpSlideJoint* cpSlideJointInit(cpSlideJoint* joint, cpBody* a, cpBody* b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max) 155 { 156 cpConstraintInit(cast(cpConstraint*)joint, &klass, a, b); 157 158 joint.anchr1 = anchr1; 159 joint.anchr2 = anchr2; 160 joint.min = min; 161 joint.max = max; 162 163 joint.jnAcc = 0.0f; 164 165 return joint; 166 } 167 168 cpConstraint* cpSlideJointNew(cpBody* a, cpBody* b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max) 169 { 170 return cast(cpConstraint*)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchr1, anchr2, min, max); 171 }