+ * @param {Vec3} pivotA The point relative to the center of mass of bodyA which bodyA is constrained to.
+ * @param {Body} bodyB Body that will be constrained in a similar way to the same point as bodyA. We will therefore get a link between bodyA and bodyB. If not specified, bodyA will be constrained to a static point.
+ * @param {Vec3} pivotB See pivotA.
+ * @param {Number} maxForce The maximum force that should be applied to constrain the bodies.
+ *
+ * @example
+ * var bodyA = new Body({ mass: 1 });
+ * var bodyB = new Body({ mass: 1 });
+ * bodyA.position.set(-1, 0, 0);
+ * bodyB.position.set(1, 0, 0);
+ * bodyA.addShape(shapeA);
+ * bodyB.addShape(shapeB);
+ * world.addBody(bodyA);
+ * world.addBody(bodyB);
+ * var localPivotA = new Vec3(1, 0, 0);
+ * var localPivotB = new Vec3(-1, 0, 0);
+ * var constraint = new PointToPointConstraint(bodyA, localPivotA, bodyB, localPivotB);
+ * Friction for this material. If non-negative, it will be used instead of the friction given by ContactMaterials. If there's no matching ContactMaterial, the value from .defaultContactMaterial in the World will be used.
+ * Restitution for this material. If non-negative, it will be used instead of the restitution given by ContactMaterials. If there's no matching ContactMaterial, the value from .defaultContactMaterial in the World will be used.
+ * A Quaternion describes a rotation in 3D space. The Quaternion is mathematically defined as Q = x*i + y*j + z*k + w, where (i,j,k) are imaginary basis vectors. (x,y,z) can be seen as a vector related to the axis of rotation, while the real multiplier, w, is related to the amount of rotation.
+ * @class Quaternion
+ * @constructor
+ * @param {Number} x Multiplier of the imaginary basis vector i.
+ * @param {Number} y Multiplier of the imaginary basis vector j.
+ * @param {Number} z Multiplier of the imaginary basis vector k.
+ * @param {Number} w Multiplier of the real part.
+ * @see http://en.wikipedia.org/wiki/Quaternion
+ */
+function Quaternion(x,y,z,w){
+ /**
+ * @property {Number} x
+ */
+ this.x = x!==undefined ? x : 0;
+
+ /**
+ * @property {Number} y
+ */
+ this.y = y!==undefined ? y : 0;
+
+ /**
+ * @property {Number} z
+ */
+ this.z = z!==undefined ? z : 0;
+
+ /**
+ * The multiplier of the real quaternion basis vector.
+ * @property {Number} w
+ */
+ this.w = w!==undefined ? w : 1;
+}
+
+/**
+ * Set the value of the quaternion.
+ * @method set
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ * @param {Number} w
+ */
+Quaternion.prototype.set = function(x,y,z,w){
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+};
+
+/**
+ * Convert to a readable format
+ * @method toString
+ * @return string
+ */
+Quaternion.prototype.toString = function(){
+ return this.x+","+this.y+","+this.z+","+this.w;
+};
+
+/**
+ * Convert to an Array
+ * @method toArray
+ * @return Array
+ */
+Quaternion.prototype.toArray = function(){
+ return [this.x, this.y, this.z, this.w];
+};
+
+/**
+ * Set the quaternion components given an axis and an angle.
+ bank = Math.atan2(2*x*w - 2*y*z , 1 - 2*sqx - 2*sqz); // bank
+ }
+ break;
+ default:
+ throw new Error("Euler order "+order+" not supported yet.");
+ }
+
+ target.y = heading;
+ target.z = attitude;
+ target.x = bank;
+};
+
+/**
+ * See http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m
+ * @method setFromEuler
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ * @param {String} order The order to apply angles: 'XYZ' or 'YXZ' or any other combination
+ */
+Quaternion.prototype.setFromEuler = function ( x, y, z, order ) {
+ order = order || "XYZ";
+
+ var c1 = Math.cos( x / 2 );
+ var c2 = Math.cos( y / 2 );
+ var c3 = Math.cos( z / 2 );
+ var s1 = Math.sin( x / 2 );
+ var s2 = Math.sin( y / 2 );
+ var s3 = Math.sin( z / 2 );
+
+ if ( order === 'XYZ' ) {
+
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
+ this.z = c1 * c2 * s3 + s1 * s2 * c3;
+ this.w = c1 * c2 * c3 - s1 * s2 * s3;
+
+ } else if ( order === 'YXZ' ) {
+
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
+ this.z = c1 * c2 * s3 - s1 * s2 * c3;
+ this.w = c1 * c2 * c3 + s1 * s2 * s3;
+
+ } else if ( order === 'ZXY' ) {
+
+ this.x = s1 * c2 * c3 - c1 * s2 * s3;
+ this.y = c1 * s2 * c3 + s1 * c2 * s3;
+ this.z = c1 * c2 * s3 + s1 * s2 * c3;
+ this.w = c1 * c2 * c3 - s1 * s2 * s3;
+
+ } else if ( order === 'ZYX' ) {
+
+ this.x = s1 * c2 * c3 - c1 * s2 * s3;
+ this.y = c1 * s2 * c3 + s1 * c2 * s3;
+ this.z = c1 * c2 * s3 - s1 * s2 * c3;
+ this.w = c1 * c2 * c3 + s1 * s2 * s3;
+
+ } else if ( order === 'YZX' ) {
+
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
+ this.y = c1 * s2 * c3 + s1 * c2 * s3;
+ this.z = c1 * c2 * s3 - s1 * s2 * c3;
+ this.w = c1 * c2 * c3 - s1 * s2 * s3;
+
+ } else if ( order === 'XZY' ) {
+
+ this.x = s1 * c2 * c3 - c1 * s2 * s3;
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
+ this.z = c1 * c2 * s3 + s1 * s2 * c3;
+ this.w = c1 * c2 * c3 + s1 * s2 * s3;
+
+ }
+
+ return this;
+};
+
+/**
+ * @method clone
+ * @return {Quaternion}
+ */
+Quaternion.prototype.clone = function(){
+ return new Quaternion(this.x, this.y, this.z, this.w);
+};
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @method slerp
+ * @param {Quaternion} toQuat second operand
+ * @param {Number} t interpolation amount between the self quaternion and toQuat
+ * @param {Quaternion} [target] A quaternion to store the result in. If not provided, a new one will be created.
+ * @returns {Quaternion} The "target" object
+ */
+Quaternion.prototype.slerp = function (toQuat, t, target) {
+ target = target || new Quaternion();
+
+ var ax = this.x,
+ ay = this.y,
+ az = this.z,
+ aw = this.w,
+ bx = toQuat.x,
+ by = toQuat.y,
+ bz = toQuat.z,
+ bw = toQuat.w;
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+
+ // calculate final values
+ target.x = scale0 * ax + scale1 * bx;
+ target.y = scale0 * ay + scale1 * by;
+ target.z = scale0 * az + scale1 * bz;
+ target.w = scale0 * aw + scale1 * bw;
+
+ return target;
+};
+
+/**
+ * Rotate an absolute orientation quaternion given an angular velocity and a time step.
+ * Make the vector point in the opposite direction.
+ * @method negate
+ * @param {Vec3} target Optional target to save in
+ * @return {Vec3}
+ */
+Vec3.prototype.negate = function(target){
+ target = target || new Vec3();
+ target.x = -this.x;
+ target.y = -this.y;
+ target.z = -this.z;
+ return target;
+};
+
+/**
+ * Compute two artificial tangents to the vector
+ * @method tangents
+ * @param {Vec3} t1 Vector object to save the first tangent in
+ * @param {Vec3} t2 Vector object to save the second tangent in
+ */
+var Vec3_tangents_n = new Vec3();
+var Vec3_tangents_randVec = new Vec3();
+Vec3.prototype.tangents = function(t1,t2){
+ var norm = this.norm();
+ if(norm>0.0){
+ var n = Vec3_tangents_n;
+ var inorm = 1/norm;
+ n.set(this.x*inorm,this.y*inorm,this.z*inorm);
+ var randVec = Vec3_tangents_randVec;
+ if(Math.abs(n.x) < 0.9){
+ randVec.set(1,0,0);
+ n.cross(randVec,t1);
+ } else {
+ randVec.set(0,1,0);
+ n.cross(randVec,t1);
+ }
+ n.cross(t1,t2);
+ } else {
+ // The normal length is zero, make something up
+ t1.set(1, 0, 0);
+ t2.set(0, 1, 0);
+ }
+};
+
+/**
+ * Converts to a more readable format
+ * @method toString
+ * @return string
+ */
+Vec3.prototype.toString = function(){
+ return this.x+","+this.y+","+this.z;
+};
+
+/**
+ * Converts to an array
+ * @method toArray
+ * @return Array
+ */
+Vec3.prototype.toArray = function(){
+ return [this.x, this.y, this.z];
+};
+
+/**
+ * Copies value of source to this vector.
+ * @method copy
+ * @param {Vec3} source
+ * @return {Vec3} this
+ */
+Vec3.prototype.copy = function(source){
+ this.x = source.x;
+ this.y = source.y;
+ this.z = source.z;
+ return this;
+};
+
+
+/**
+ * Do a linear interpolation between two vectors
+ * @method lerp
+ * @param {Vec3} v
+ * @param {Number} t A number between 0 and 1. 0 will make this function return u, and 1 will make it return v. Numbers in between will generate a vector in between them.
+ * @param {Vec3} target
+ */
+Vec3.prototype.lerp = function(v,t,target){
+ var x=this.x, y=this.y, z=this.z;
+ target.x = x + (v.x-x)*t;
+ target.y = y + (v.y-y)*t;
+ target.z = z + (v.z-z)*t;
+};
+
+/**
+ * Check if a vector equals is almost equal to another one.
+ * Callback function that is used BEFORE stepping the system. Use it to apply forces, for example. Inside the function, "this" will refer to this Body object.
+ * @property preStep
+ * @type {Function}
+ * @deprecated Use World events instead
+ */
+ this.preStep = null;
+
+ /**
+ * Callback function that is used AFTER stepping the system. Inside the function, "this" will refer to this Body object.
+ * Indicates if the AABB needs to be updated before use.
+ * @property aabbNeedsUpdate
+ * @type {Boolean}
+ */
+ this.aabbNeedsUpdate = true;
+
+ this.wlambda = new Vec3();
+
+ if(options.shape){
+ this.addShape(options.shape);
+ }
+
+ this.updateMassProperties();
+}
+Body.prototype = new EventTarget();
+Body.prototype.constructor = Body;
+
+/**
+ * Dispatched after two bodies collide. This event is dispatched on each
+ * of the two bodies involved in the collision.
+ * @event collide
+ * @param {Body} body The body that was involved in the collision.
+ * @param {ContactEquation} contact The details of the collision.
+ */
+Body.COLLIDE_EVENT_NAME = "collide";
+
+/**
+ * A dynamic body is fully simulated. Can be moved manually by the user, but normally they move according to forces. A dynamic body can collide with all body types. A dynamic body always has finite, non-zero mass.
+ * @static
+ * @property DYNAMIC
+ * @type {Number}
+ */
+Body.DYNAMIC = 1;
+
+/**
+ * A static body does not move during simulation and behaves as if it has infinite mass. Static bodies can be moved manually by setting the position of the body. The velocity of a static body is always zero. Static bodies do not collide with other static or kinematic bodies.
+ * @static
+ * @property STATIC
+ * @type {Number}
+ */
+Body.STATIC = 2;
+
+/**
+ * A kinematic body moves under simulation according to its velocity. They do not respond to forces. They can be moved manually, but normally a kinematic body is moved by setting its velocity. A kinematic body behaves as if it has infinite mass. Kinematic bodies do not collide with other static or kinematic bodies.
+ * @static
+ * @property KINEMATIC
+ * @type {Number}
+ */
+Body.KINEMATIC = 4;
+
+
+
+/**
+ * @static
+ * @property AWAKE
+ * @type {number}
+ */
+Body.AWAKE = 0;
+
+/**
+ * @static
+ * @property SLEEPY
+ * @type {number}
+ */
+Body.SLEEPY = 1;
+
+/**
+ * @static
+ * @property SLEEPING
+ * @type {number}
+ */
+Body.SLEEPING = 2;
+
+Body.idCounter = 0;
+
+/**
+ * Dispatched after a sleeping body has woken up.
+ * @event wakeup
+ */
+Body.wakeupEvent = {
+ type: "wakeup"
+};
+
+/**
+ * Wake the body up.
+ * @method wakeUp
+ */
+Body.prototype.wakeUp = function(){
+ var s = this.sleepState;
+ this.sleepState = 0;
+ this._wakeUpAfterNarrowphase = false;
+ if(s === Body.SLEEPING){
+ this.dispatchEvent(Body.wakeupEvent);
+ }
+};
+
+/**
+ * Force body sleep
+ * @method sleep
+ */
+Body.prototype.sleep = function(){
+ this.sleepState = Body.SLEEPING;
+ this.velocity.set(0,0,0);
+ this.angularVelocity.set(0,0,0);
+ this._wakeUpAfterNarrowphase = false;
+};
+
+/**
+ * Dispatched after a body has gone in to the sleepy state.
+ * @event sleepy
+ */
+Body.sleepyEvent = {
+ type: "sleepy"
+};
+
+/**
+ * Dispatched after a body has fallen asleep.
+ * @event sleep
+ */
+Body.sleepEvent = {
+ type: "sleep"
+};
+
+/**
+ * Called every timestep to update internal sleep timer and change sleep state if needed.
+ * @method sleepTick
+ * @param {Number} time The world time in seconds
+ */
+Body.prototype.sleepTick = function(time){
+ if(this.allowSleep){
+ var sleepState = this.sleepState;
+ var speedSquared = this.velocity.norm2() + this.angularVelocity.norm2();
+ var speedLimitSquared = Math.pow(this.sleepSpeedLimit,2);
+ // In other words, we don't have to transform the inertia if all
+ // inertia diagonal entries are equal.
+ } else {
+ var m1 = uiw_m1,
+ m2 = uiw_m2,
+ m3 = uiw_m3;
+ m1.setRotationFromQuaternion(this.quaternion);
+ m1.transpose(m2);
+ m1.scale(I,m1);
+ m1.mmult(m2,this.invInertiaWorld);
+ }
+};
+
+/**
+ * Apply force to a world point. This could for example be a point on the Body surface. Applying force this way will add to Body.force and Body.torque.
+ * @method applyForce
+ * @param {Vec3} force The amount of force to add.
+ * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on.
+ * Apply impulse to a world point. This could for example be a point on the Body surface. An impulse is a force added to a body during a short period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity.
+ * @method applyImpulse
+ * @param {Vec3} impulse The amount of impulse to add.
+ * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on.
+ * Note when rendering wheels: during each step, wheel transforms are updated BEFORE the chassis; ie. their position becomes invalid after the step. Thus when you render wheels, you must update wheel transforms before rendering them. See raycastVehicle demo for an example.
+ * @method updateWheelTransform
+ * @param {integer} wheelIndex The wheel index to update.
+ // Scale the relative position in the up direction with rollInfluence.
+ // If rollInfluence is 1, the impulse will be applied on the hitPoint (easy to roll over), if it is zero it will be applied in the same plane as the center of mass (not easy to roll over).
+ throw new Error("Vertex "+this.faces[i][j]+" not found!");
+ }
+ }
+
+ var n = this.faceNormals[i] || new Vec3();
+ this.getFaceNormal(i,n);
+ n.negate(n);
+ this.faceNormals[i] = n;
+ var vertex = this.vertices[this.faces[i][0]];
+ if(n.dot(vertex) < 0){
+ console.error(".faceNormals[" + i + "] = Vec3("+n.toString()+") looks like it points into the shape? The vertices follow. Make sure they are ordered CCW around the normal, using the right hand rule.");
+ * @param {Array} worldVertsB1 An array of Vec3 with vertices in the world frame.
+ * @param {Number} minDist Distance clamping
+ * @param {Number} maxDist
+ * @param Array result Array to store resulting contact points in. Will be objects with properties: point, depth, normal. These are represented in world coordinates.
+ // console.log("--- did not find any closest face... ---");
+ return;
+ }
+ //console.log("closest A: ",closestFaceA);
+ // Get the face and construct connected faces
+ var polyA = hullA.faces[closestFaceA];
+ polyA.connectedFaces = [];
+ for(var i=0; i<hullA.faces.length; i++){
+ for(var j=0; j<hullA.faces[i].length; j++){
+ if(polyA.indexOf(hullA.faces[i][j])!==-1 /* Sharing a vertex*/ && i!==closestFaceA /* Not the one we are looking for connections from */ && polyA.connectedFaces.indexOf(i)===-1 /* Not already added */ ){
+ polyA.connectedFaces.push(i);
+ }
+ }
+ }
+ // Clip the polygon to the back of the planes of all faces of hull A, that are adjacent to the witness face
+ var numContacts = pVtxIn.length;
+ var numVerticesA = polyA.length;
+ var res = [];
+ for(var e0=0; e0<numVerticesA; e0++){
+ var a = hullA.vertices[polyA[e0]];
+ var b = hullA.vertices[polyA[(e0+1)%numVerticesA]];
+ * Checks whether p is inside the polyhedra. Must be in local coords. The point lies outside of the convex hull of the other points if and only if the direction of all the vectors from it to those other points are on less than one half of a sphere around it.
+ * @method pointIsInside
+ * @param {Vec3} p A point given in local coordinates
+ * @return {Boolean}
+ */
+var ConvexPolyhedron_pointIsInside = new Vec3();
+var ConvexPolyhedron_vToP = new Vec3();
+var ConvexPolyhedron_vToPointInside = new Vec3();
+ this.clearCachedConvexTrianglePillar(xi, yi - 1, true);
+ this.clearCachedConvexTrianglePillar(xi, yi - 1, false);
+ }
+ if(yi > 0 && xi > 0){
+ this.clearCachedConvexTrianglePillar(xi - 1, yi - 1, true);
+ }
+};
+
+/**
+ * Get max/min in a rectangle in the matrix data
+ * @method getRectMinMax
+ * @param {integer} iMinX
+ * @param {integer} iMinY
+ * @param {integer} iMaxX
+ * @param {integer} iMaxY
+ * @param {array} [result] An array to store the results in.
+ * @return {array} The result array, if it was passed in. Minimum will be at position 0 and max at 1.
+ */
+Heightfield.prototype.getRectMinMax = function (iMinX, iMinY, iMaxX, iMaxY, result) {
+ result = result || [];
+
+ // Get max and min of the data
+ var data = this.data,
+ max = this.minValue; // Set first value
+ for(var i = iMinX; i <= iMaxX; i++){
+ for(var j = iMinY; j <= iMaxY; j++){
+ var height = data[i][j];
+ if(height > max){
+ max = height;
+ }
+ }
+ }
+
+ result[0] = this.minValue;
+ result[1] = max;
+};
+
+
+
+/**
+ * Get the index of a local position on the heightfield. The indexes indicate the rectangles, so if your terrain is made of N x N height data points, you will have rectangle indexes ranging from 0 to N-1.
+ * @method getIndexOfPosition
+ * @param {number} x
+ * @param {number} y
+ * @param {array} result Two-element array
+ * @param {boolean} clamp If the position should be clamped to the heightfield edge.
+ * @return {boolean}
+ */
+Heightfield.prototype.getIndexOfPosition = function (x, y, result, clamp) {
+
+ // Get the index of the data points to test against
+ * A plane, facing in the Z direction. The plane has its surface at z=0 and everything below z=0 is assumed to be solid plane. To make the plane face in some other direction than z, you must put it inside a RigidBody and rotate that body. See the demos.
+ * The number of solver iterations determines quality of the constraints in the world. The more iterations, the more correct simulation. More iterations need more computations though. If you have a large gravity force in your world, you will need more iterations.
+ * @property iterations
+ * @type {Number}
+ * @todo write more about solver and iterations in the wiki
+ */
+ this.iterations = 10;
+
+ /**
+ * When tolerance is reached, the system is assumed to be converged.
+ * @property tolerance
+ * @type {Number}
+ */
+ this.tolerance = 1e-7;
+}
+GSSolver.prototype = new Solver();
+
+var GSSolver_solve_lambda = []; // Just temporary number holders that we want to reuse each solve.
+var GSSolver_solve_invCs = [];
+var GSSolver_solve_Bs = [];
+GSSolver.prototype.solve = function(dt,world){
+ var iter = 0,
+ maxIter = this.iterations,
+ tolSquared = this.tolerance*this.tolerance,
+ equations = this.equations,
+ Neq = equations.length,
+ bodies = world.bodies,
+ Nbodies = bodies.length,
+ h = dt,
+ q, B, invC, deltalambda, deltalambdaTot, GWlambda, lambdaj;
+
+ // Update solve mass
+ if(Neq !== 0){
+ for(var i=0; i!==Nbodies; i++){
+ bodies[i].updateSolveMassProperties();
+ }
+ }
+
+ // Things that does not change during iteration can be computed once
+ var invCs = GSSolver_solve_invCs,
+ Bs = GSSolver_solve_Bs,
+ lambda = GSSolver_solve_lambda;
+ invCs.length = Neq;
+ Bs.length = Neq;
+ lambda.length = Neq;
+ for(var i=0; i!==Neq; i++){
+ var c = equations[i];
+ lambda[i] = 0.0;
+ Bs[i] = c.computeB(h);
+ invCs[i] = 1.0 / c.computeC();
+ }
+
+ if(Neq !== 0){
+
+ // Reset vlambda
+ for(var i=0; i!==Nbodies; i++){
+ var b=bodies[i],
+ vlambda=b.vlambda,
+ wlambda=b.wlambda;
+ vlambda.set(0,0,0);
+ wlambda.set(0,0,0);
+ }
+
+ // Iterate over equations
+ for(iter=0; iter!==maxIter; iter++){
+
+ // Accumulate the total error for each iteration.
+ * Currently / last used timestep. Is set to -1 if not available. This value is updated before each internal step, which means that it is "fresh" inside event callbacks.
+ * @property {Number} dt
+ */
+ this.dt = -1;
+
+ /**
+ * Makes bodies go to sleep when they've been inactive
+ * @property allowSleep
+ * @type {Boolean}
+ * @default false
+ */
+ this.allowSleep = !!options.allowSleep;
+
+ /**
+ * All the current contacts (instances of ContactEquation) in the world.
+ * @property contacts
+ * @type {Array}
+ */
+ this.contacts = [];
+ this.frictionEquations = [];
+
+ /**
+ * How often to normalize quaternions. Set to 0 for every step, 1 for every second etc.. A larger value increases performance. If bodies tend to explode, set to a smaller value (zero to be sure nothing can go wrong).
+ if (performance.timing && performance.timing.navigationStart){
+ nowOffset = performance.timing.navigationStart;
+ }
+ performance.now = function(){
+ return Date.now() - nowOffset;
+ };
+}
+
+var step_tmp1 = new Vec3();
+
+/**
+ * Step the physics world forward in time.
+ *
+ * There are two modes. The simple mode is fixed timestepping without interpolation. In this case you only use the first argument. The second case uses interpolation. In that you also provide the time since the function was last used, as well as the maximum fixed timesteps to take.
+ *
+ * @method step
+ * @param {Number} dt The fixed time step size to use.
+ * @param {Number} [timeSinceLastCalled] The time elapsed since the function was last called.
+ * @param {Number} [maxSubSteps=10] Maximum number of fixed steps to take per function call.
+ // Determine Perimeter - Creates a bounded horizon
+
+ // 1. Pick an edge A out of all possible edges
+ // 2. Check if A is shared by any other face. a->b === b->a
+ // 2.1 for each edge in each triangle, isShared = ( f1.a == f2.a && f1.b == f2.b ) || ( f1.a == f2.b && f1.b == f2.a )
+ // 3. If not shared, then add to convex horizon set,
+ //pick an end point (N) of the current edge A and choose a new edge NA connected to A.
+ //Restart from 1.
+ // 4. If A is shared, it is not an horizon edge, therefore flag both faces that share this edge as candidates for culling
+ // 5. If candidate geometry is a degenrate triangle (ie. the tangent space normal cannot be computed) then remove that triangle from all further processing
+
+
+ var j = i = visibleFaces.length;
+ var isDistinct = false,
+ hasOneVisibleFace = i === 1,
+ cull = [],
+ perimeter = [],
+ edgeIndex = 0, compareFace, nextIndex,
+ a, b;
+
+ var allPoints = [];
+ var originFace = [visibleFaces[0][0], visibleFaces[0][1], visibleFaces[0][1], visibleFaces[0][2], visibleFaces[0][2], visibleFaces[0][0]];
+ if (this.scoreFunction(element) < this.scoreFunction(parent)) {
+ // Swap the elements if the parent is greater.
+ this.content[parentN] = element;
+ this.content[n] = parent;
+ // Update 'n' to continue at the new position.
+ n = parentN;
+ } else {
+ // Found a parent that is less, no need to sink any further.
+ break;
}
}
+ }
- var index, neighbouringIndex, vertex;
-
- // Determine Perimeter - Creates a bounded horizon
-
- // 1. Pick an edge A out of all possible edges
- // 2. Check if A is shared by any other face. a->b === b->a
- // 2.1 for each edge in each triangle, isShared = ( f1.a == f2.a && f1.b == f2.b ) || ( f1.a == f2.b && f1.b == f2.a )
- // 3. If not shared, then add to convex horizon set,
- //pick an end point (N) of the current edge A and choose a new edge NA connected to A.
- //Restart from 1.
- // 4. If A is shared, it is not an horizon edge, therefore flag both faces that share this edge as candidates for culling
- // 5. If candidate geometry is a degenrate triangle (ie. the tangent space normal cannot be computed) then remove that triangle from all further processing
-
-
- var j = i = visibleFaces.length;
- var isDistinct = false,
- hasOneVisibleFace = i === 1,
- cull = [],
- perimeter = [],
- edgeIndex = 0, compareFace, nextIndex,
- a, b;
-
- var allPoints = [];
- var originFace = [visibleFaces[0][0], visibleFaces[0][1], visibleFaces[0][1], visibleFaces[0][2], visibleFaces[0][2], visibleFaces[0][0]];
-
+ bubbleUp (n) {
+ // Look up the target element and its score.
+ const length = this.content.length,
+ element = this.content[n],
+ elemScore = this.scoreFunction(element);
- if( visibleFaces.length === 1 ){
- currentFace = visibleFaces[0];
+ while (true) {
+ // Compute the indices of the child elements.
+ const child2N = (n + 1) << 1,
+ child1N = child2N - 1;
+ // This is used to store the new position of the element,
+ // if any.
+ let swap = null;
+ let child1Score;
+ // If the first child exists (is inside the array)...
+ // Determine Perimeter - Creates a bounded horizon
+
+ // 1. Pick an edge A out of all possible edges
+ // 2. Check if A is shared by any other face. a->b === b->a
+ // 2.1 for each edge in each triangle, isShared = ( f1.a == f2.a && f1.b == f2.b ) || ( f1.a == f2.b && f1.b == f2.a )
+ // 3. If not shared, then add to convex horizon set,
+ //pick an end point (N) of the current edge A and choose a new edge NA connected to A.
+ //Restart from 1.
+ // 4. If A is shared, it is not an horizon edge, therefore flag both faces that share this edge as candidates for culling
+ // 5. If candidate geometry is a degenrate triangle (ie. the tangent space normal cannot be computed) then remove that triangle from all further processing
- update: function () {
- var self = this;
- var el = this.el;
- var src = this.data;
- if (!src) { return; }
+ var j = i = visibleFaces.length;
+ var isDistinct = false,
+ hasOneVisibleFace = i === 1,
+ cull = [],
+ perimeter = [],
+ edgeIndex = 0, compareFace, nextIndex,
+ a, b;
- this.remove();
+ var allPoints = [];
+ var originFace = [visibleFaces[0][0], visibleFaces[0][1], visibleFaces[0][1], visibleFaces[0][2], visibleFaces[0][2], visibleFaces[0][0]];
- this.loaderPromise.then(function () {
- this.loader.load(src, function gltfLoaded (gltfModel) {