import { Equation } from '../equations/Equation' import { Vec3 } from '../math/Vec3' import type { Body } from '../objects/Body' /** * Contact/non-penetration constraint equation */ export class ContactEquation extends Equation { /** * "bounciness": u1 = -e*u0 */ restitution: number /** * World-oriented vector that goes from the center of bi to the contact point. */ ri: Vec3 /** * World-oriented vector that starts in body j position and goes to the contact point. */ rj: Vec3 /** * Contact normal, pointing out of body i. */ ni: Vec3 constructor(bodyA: Body, bodyB: Body, maxForce = 1e6) { super(bodyA, bodyB, 0, maxForce) this.restitution = 0.0 this.ri = new Vec3() this.rj = new Vec3() this.ni = new Vec3() } computeB(h: number): number { const a = this.a const b = this.b const bi = this.bi const bj = this.bj const ri = this.ri const rj = this.rj const rixn = ContactEquation_computeB_temp1 const rjxn = ContactEquation_computeB_temp2 const vi = bi.velocity const wi = bi.angularVelocity const fi = bi.force const taui = bi.torque const vj = bj.velocity const wj = bj.angularVelocity const fj = bj.force const tauj = bj.torque const penetrationVec = ContactEquation_computeB_temp3 const GA = this.jacobianElementA const GB = this.jacobianElementB const n = this.ni // Caluclate cross products ri.cross(n, rixn) rj.cross(n, rjxn) // g = xj+rj -(xi+ri) // G = [ -ni -rixn ni rjxn ] n.negate(GA.spatial) rixn.negate(GA.rotational) GB.spatial.copy(n) GB.rotational.copy(rjxn) // Calculate the penetration vector penetrationVec.copy(bj.position) penetrationVec.vadd(rj, penetrationVec) penetrationVec.vsub(bi.position, penetrationVec) penetrationVec.vsub(ri, penetrationVec) const g = n.dot(penetrationVec) // Compute iteration const ePlusOne = this.restitution + 1 const GW = ePlusOne * vj.dot(n) - ePlusOne * vi.dot(n) + wj.dot(rjxn) - wi.dot(rixn) const GiMf = this.computeGiMf() const B = -g * a - GW * b - h * GiMf return B } /** * Get the current relative velocity in the contact point. */ getImpactVelocityAlongNormal(): number { const vi = ContactEquation_getImpactVelocityAlongNormal_vi const vj = ContactEquation_getImpactVelocityAlongNormal_vj const xi = ContactEquation_getImpactVelocityAlongNormal_xi const xj = ContactEquation_getImpactVelocityAlongNormal_xj const relVel = ContactEquation_getImpactVelocityAlongNormal_relVel this.bi.position.vadd(this.ri, xi) this.bj.position.vadd(this.rj, xj) this.bi.getVelocityAtWorldPoint(xi, vi) this.bj.getVelocityAtWorldPoint(xj, vj) vi.vsub(vj, relVel) return this.ni.dot(relVel) } } const ContactEquation_computeB_temp1 = new Vec3() // Temp vectors const ContactEquation_computeB_temp2 = new Vec3() const ContactEquation_computeB_temp3 = new Vec3() const ContactEquation_getImpactVelocityAlongNormal_vi = new Vec3() const ContactEquation_getImpactVelocityAlongNormal_vj = new Vec3() const ContactEquation_getImpactVelocityAlongNormal_xi = new Vec3() const ContactEquation_getImpactVelocityAlongNormal_xj = new Vec3() const ContactEquation_getImpactVelocityAlongNormal_relVel = new Vec3()