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.cpDampedRotarySpring; 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 32 alias cpDampedRotarySpringTorqueFunc = cpFloat function(cpConstraint* spring, cpFloat relativeAngle); 33 34 //~ const cpConstraintClass* cpDampedRotarySpringGetClass(); 35 36 /// @private 37 struct cpDampedRotarySpring 38 { 39 cpConstraint constraint; 40 cpFloat restAngle = 0; 41 cpFloat stiffness = 0; 42 cpFloat damping = 0; 43 cpDampedRotarySpringTorqueFunc springTorqueFunc; 44 45 cpFloat target_wrn = 0; 46 cpFloat w_coef = 0; 47 48 cpFloat iSum = 0; 49 cpFloat jAcc = 0; 50 } 51 52 /// Allocate a damped rotary spring. 53 cpDampedRotarySpring* cpDampedRotarySpringAlloc(); 54 55 /// Initialize a damped rotary spring. 56 cpDampedRotarySpring* cpDampedRotarySpringInit(cpDampedRotarySpring* joint, cpBody* a, cpBody* b, cpFloat restAngle, cpFloat stiffness, cpFloat damping); 57 58 /// Allocate and initialize a damped rotary spring. 59 cpConstraint* cpDampedRotarySpringNew(cpBody* a, cpBody* b, cpFloat restAngle, cpFloat stiffness, cpFloat damping); 60 61 mixin CP_DefineConstraintProperty!("cpDampedRotarySpring", cpFloat, "restAngle", "RestAngle"); 62 mixin CP_DefineConstraintProperty!("cpDampedRotarySpring", cpFloat, "stiffness", "Stiffness"); 63 mixin CP_DefineConstraintProperty!("cpDampedRotarySpring", cpFloat, "damping", "Damping"); 64 mixin CP_DefineConstraintProperty!("cpDampedRotarySpring", cpDampedRotarySpringTorqueFunc, "springTorqueFunc", "SpringTorqueFunc"); 65 66 cpFloat defaultSpringTorque(cpDampedRotarySpring* spring, cpFloat relativeAngle) 67 { 68 return (relativeAngle - spring.restAngle) * spring.stiffness; 69 } 70 71 void preStep(cpDampedRotarySpring* spring, cpFloat dt) 72 { 73 cpBody* a = spring.constraint.a; 74 cpBody* b = spring.constraint.b; 75 76 cpFloat moment = a.i_inv + b.i_inv; 77 cpAssertSoft(moment != 0.0, "Unsolvable spring."); 78 spring.iSum = 1.0f / moment; 79 80 spring.w_coef = 1.0f - cpfexp(-spring.damping * dt * moment); 81 spring.target_wrn = 0.0f; 82 83 // apply spring torque 84 cpFloat j_spring = spring.springTorqueFunc(cast(cpConstraint*)spring, a.a - b.a) * dt; 85 spring.jAcc = j_spring; 86 87 a.w -= j_spring * a.i_inv; 88 b.w += j_spring * b.i_inv; 89 } 90 91 void applyCachedImpulse(cpDampedRotarySpring* spring, cpFloat dt_coef) 92 { 93 } 94 95 void applyImpulse(cpDampedRotarySpring* spring, cpFloat dt) 96 { 97 cpBody* a = spring.constraint.a; 98 cpBody* b = spring.constraint.b; 99 100 // compute relative velocity 101 cpFloat wrn = a.w - b.w; //normal_relative_velocity(a, b, r1, r2, n) - spring.target_vrn; 102 103 // compute velocity loss from drag 104 // not 100% certain this is derived correctly, though it makes sense 105 cpFloat w_damp = (spring.target_wrn - wrn) * spring.w_coef; 106 spring.target_wrn = wrn + w_damp; 107 108 //apply_impulses(a, b, spring.r1, spring.r2, cpvmult(spring.n, v_damp*spring.nMass)); 109 cpFloat j_damp = w_damp * spring.iSum; 110 spring.jAcc += j_damp; 111 112 a.w += j_damp * a.i_inv; 113 b.w -= j_damp * b.i_inv; 114 } 115 116 cpFloat getImpulse(cpDampedRotarySpring* spring) 117 { 118 return spring.jAcc; 119 } 120 121 __gshared cpConstraintClass klass; 122 123 void _initModuleCtor_cpDampedRotarySpring() 124 { 125 klass = cpConstraintClass( 126 cast(cpConstraintPreStepImpl)&preStep, 127 cast(cpConstraintApplyCachedImpulseImpl)&applyCachedImpulse, 128 cast(cpConstraintApplyImpulseImpl)&applyImpulse, 129 cast(cpConstraintGetImpulseImpl)&getImpulse, 130 ); 131 }; 132 133 const(cpConstraintClass *) cpDampedRotarySpringGetClass() 134 { 135 return cast(cpConstraintClass*)&klass; 136 } 137 138 cpDampedRotarySpring * 139 cpDampedRotarySpringAlloc() 140 { 141 return cast(cpDampedRotarySpring*)cpcalloc(1, cpDampedRotarySpring.sizeof); 142 } 143 144 cpDampedRotarySpring* cpDampedRotarySpringInit(cpDampedRotarySpring* spring, cpBody* a, cpBody* b, cpFloat restAngle, cpFloat stiffness, cpFloat damping) 145 { 146 cpConstraintInit(cast(cpConstraint*)spring, &klass, a, b); 147 148 spring.restAngle = restAngle; 149 spring.stiffness = stiffness; 150 spring.damping = damping; 151 spring.springTorqueFunc = cast(cpDampedRotarySpringTorqueFunc)&defaultSpringTorque; 152 153 spring.jAcc = 0.0f; 154 155 return spring; 156 } 157 158 cpConstraint* cpDampedRotarySpringNew(cpBody* a, cpBody* b, cpFloat restAngle, cpFloat stiffness, cpFloat damping) 159 { 160 return cast(cpConstraint*)cpDampedRotarySpringInit(cpDampedRotarySpringAlloc(), a, b, restAngle, stiffness, damping); 161 }