text: import { Logger } from "../Misc/logger";
  import { ArrayTools } from "../Misc/arrayTools";
  import { Vector3, Quaternion } from "../Maths/math.vector";
  import { AbstractMesh } from "../Meshes/abstractMesh";
  import { Mesh } from "../Meshes/mesh";
  import { PhysicsJoint } from "./physicsJoint";
  import { Space } from "../Maths/math.axis";
  Mesh._PhysicsImpostorParser = function (scene, physicObject, jsonObject) {
      return new PhysicsImpostor(physicObject, jsonObject.physicsImpostor, {
          mass: jsonObject.physicsMass,
          friction: jsonObject.physicsFriction,
          restitution: jsonObject.physicsRestitution,
      }, scene);
  };
  /**
   * Represents a physics imposter
   * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
   */
  var PhysicsImpostor = /** @class */ (function () {
      /**
       * Initializes the physics imposter
       * @param object The physics-enabled object used as the physics imposter
       * @param type The type of the physics imposter
       * @param _options The options for the physics imposter
       * @param _scene The Babylon scene
       */
      function PhysicsImpostor(
      /**
       * The physics-enabled object used as the physics imposter
       */
      object, 
      /**
       * The type of the physics imposter
       */
      type, _options, _scene) {
          var _this = this;
          if (_options === void 0) { _options = { mass: 0 }; }
          this.object = object;
          this.type = type;
          this._options = _options;
          this._scene = _scene;
          /** @hidden */
          this._pluginData = {};
          this._bodyUpdateRequired = false;
          this._onBeforePhysicsStepCallbacks = new Array();
          this._onAfterPhysicsStepCallbacks = new Array();
          /** @hidden */
          this._onPhysicsCollideCallbacks = [];
          this._deltaPosition = Vector3.Zero();
          this._isDisposed = false;
          /**
           * @hidden
           */
          this.soft = false;
          /**
           * @hidden
           */
          this.segments = 0;
          //temp variables for parent rotation calculations
          //private _mats: Array<Matrix> = [new Matrix(), new Matrix()];
          this._tmpQuat = new Quaternion();
          this._tmpQuat2 = new Quaternion();
          /**
           * this function is executed by the physics engine.
           */
          this.beforeStep = function () {
              if (!_this._physicsEngine) {
                  return;
              }
              _this.object.translate(_this._deltaPosition, -1);
              _this._deltaRotationConjugated && _this.object.rotationQuaternion && _this.object.rotationQuaternion.multiplyToRef(_this._deltaRotationConjugated, _this.object.rotationQuaternion);
              _this.object.computeWorldMatrix(false);
              if (_this.object.parent && _this.object.rotationQuaternion) {
                  _this.getParentsRotation();
                  _this._tmpQuat.multiplyToRef(_this.object.rotationQuaternion, _this._tmpQuat);
              }
              else {
                  _this._tmpQuat.copyFrom(_this.object.rotationQuaternion || new Quaternion());
              }
              if (!_this._options.disableBidirectionalTransformation) {
                  _this.object.rotationQuaternion && _this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(_this, /*bInfo.boundingBox.centerWorld*/ _this.object.getAbsolutePosition(), _this._tmpQuat);
              }
              _this._onBeforePhysicsStepCallbacks.forEach(function (func) {
                  func(_this);
              });
          };
          /**
           * this function is executed by the physics engine
           */
          this.afterStep = function () {
              if (!_this._physicsEngine) {
                  return;
              }
              _this._onAfterPhysicsStepCallbacks.forEach(function (func) {
                  func(_this);
              });
              _this._physicsEngine.getPhysicsPlugin().setTransformationFromPhysicsBody(_this);
              // object has now its world rotation. needs to be converted to local.
              if (_this.object.parent && _this.object.rotationQuaternion) {
                  _this.getParentsRotation();
                  _this._tmpQuat.conjugateInPlace();
                  _this._tmpQuat.multiplyToRef(_this.object.rotationQuaternion, _this.object.rotationQuaternion);
              }
              // take the position set and make it the absolute position of this object.
              _this.object.setAbsolutePosition(_this.object.position);
              _this._deltaRotation && _this.object.rotationQuaternion && _this.object.rotationQuaternion.multiplyToRef(_this._deltaRotation, _this.object.rotationQuaternion);
              _this.object.translate(_this._deltaPosition, 1);
          };
          /**
           * Legacy collision detection event support
           */
          this.onCollideEvent = null;
          /**
           * event and body object due to cannon's event-based architecture.
           */
          this.onCollide = function (e) {
              if (!_this._onPhysicsCollideCallbacks.length && !_this.onCollideEvent) {
                  return;
              }
              if (!_this._physicsEngine) {
                  return;
              }
              var otherImpostor = _this._physicsEngine.getImpostorWithPhysicsBody(e.body);
              if (otherImpostor) {
                  // Legacy collision detection event support
                  if (_this.onCollideEvent) {
                      _this.onCollideEvent(_this, otherImpostor);
                  }
                  _this._onPhysicsCollideCallbacks
                      .filter(function (obj) {
                      return obj.otherImpostors.indexOf(otherImpostor) !== -1;
                  })
                      .forEach(function (obj) {
                      obj.callback(_this, otherImpostor, e.point);
                  });
              }
          };
          //sanity check!
          if (!this.object) {
              Logger.Error("No object was provided. A physics object is obligatory");
              return;
          }
          if (this.object.parent && _options.mass !== 0) {
              Logger.Warn("A physics impostor has been created for an object which has a parent. Babylon physics currently works in local space so unexpected issues may occur.");
          }
          // Legacy support for old syntax.
          if (!this._scene && object.getScene) {
              this._scene = object.getScene();
          }
          if (!this._scene) {
              return;
          }
          if (this.type > 100) {
              this.soft = true;
          }
          this._physicsEngine = this._scene.getPhysicsEngine();
          if (!this._physicsEngine) {
              Logger.Error("Physics not enabled. Please use scene.enablePhysics(...) before creating impostors.");
          }
          else {
              //set the object's quaternion, if not set
              if (!this.object.rotationQuaternion) {
                  if (this.object.rotation) {
                      this.object.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.object.rotation.y, this.object.rotation.x, this.object.rotation.z);
                  }
                  else {
                      this.object.rotationQuaternion = new Quaternion();
                  }
              }
              //default options params
              this._options.mass = _options.mass === void 0 ? 0 : _options.mass;
              this._options.friction = _options.friction === void 0 ? 0.2 : _options.friction;
              this._options.restitution = _options.restitution === void 0 ? 0.2 : _options.restitution;
              if (this.soft) {
                  //softbody mass must be above 0;
                  this._options.mass = this._options.mass > 0 ? this._options.mass : 1;
                  this._options.pressure = _options.pressure === void 0 ? 200 : _options.pressure;
                  this._options.stiffness = _options.stiffness === void 0 ? 1 : _options.stiffness;
                  this._options.velocityIterations = _options.velocityIterations === void 0 ? 20 : _options.velocityIterations;
                  this._options.positionIterations = _options.positionIterations === void 0 ? 20 : _options.positionIterations;
                  this._options.fixedPoints = _options.fixedPoints === void 0 ? 0 : _options.fixedPoints;
                  this._options.margin = _options.margin === void 0 ? 0 : _options.margin;
                  this._options.damping = _options.damping === void 0 ? 0 : _options.damping;
                  this._options.path = _options.path === void 0 ? null : _options.path;
                  this._options.shape = _options.shape === void 0 ? null : _options.shape;
              }
              this._joints = [];
              //If the mesh has a parent, don't initialize the physicsBody. Instead wait for the parent to do that.
              if (!this.object.parent || this._options.ignoreParent) {
                  this._init();
              }
              else if (this.object.parent.physicsImpostor) {
                  Logger.Warn("You must affect impostors to children before affecting impostor to parent.");
              }
          }
      }
      Object.defineProperty(PhysicsImpostor.prototype, "isDisposed", {
          /**
           * Specifies if the physics imposter is disposed
           */
          get: function () {
              return this._isDisposed;
          },
          enumerable: false,
          configurable: true
      });
      Object.defineProperty(PhysicsImpostor.prototype, "mass", {
          /**
           * Gets the mass of the physics imposter
           */
          get: function () {
              return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getBodyMass(this) : 0;
          },
          set: function (value) {
              this.setMass(value);
          },
          enumerable: false,
          configurable: true
      });
      Object.defineProperty(PhysicsImpostor.prototype, "friction", {
          /**
           * Gets the coefficient of friction
           */
          get: function () {
              return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getBodyFriction(this) : 0;
          },
          /**
           * Sets the coefficient of friction
           */
          set: function (value) {
              if (!this._physicsEngine) {
                  return;
              }
              this._physicsEngine.getPhysicsPlugin().setBodyFriction(this, value);
          },
          enumerable: false,
          configurable: true
      });
      Object.defineProperty(PhysicsImpostor.prototype, "restitution", {
          /**
           * Gets the coefficient of restitution
           */
          get: function () {
              return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getBodyRestitution(this) : 0;
          },
          /**
           * Sets the coefficient of restitution
           */
          set: function (value) {
              if (!this._physicsEngine) {
                  return;
              }
              this._physicsEngine.getPhysicsPlugin().setBodyRestitution(this, value);
          },
          enumerable: false,
          configurable: true
      });
      Object.defineProperty(PhysicsImpostor.prototype, "pressure", {
          /**
           * Gets the pressure of a soft body; only supported by the AmmoJSPlugin
           */
          get: function () {
              if (!this._physicsEngine) {
                  return 0;
              }
              var plugin = this._physicsEngine.getPhysicsPlugin();
              if (!plugin.setBodyPressure) {
                  return 0;
              }
              return plugin.getBodyPressure(this);
          },
          /**
           * Sets the pressure of a soft body; only supported by the AmmoJSPlugin
           */
          set: function (value) {
              if (!this._physicsEngine) {
                  return;
              }
              var plugin = this._physicsEngine.getPhysicsPlugin();
              if (!plugin.setBodyPressure) {
                  return;
              }
              plugin.setBodyPressure(this, value);
          },
          enumerable: false,
          configurable: true
      });
      Object.defineProperty(PhysicsImpostor.prototype, "stiffness", {
          /**
           * Gets the stiffness of a soft body; only supported by the AmmoJSPlugin
           */
          get: function () {
              if (!this._physicsEngine) {
                  return 0;
              }
              var plugin = this._physicsEngine.getPhysicsPlugin();
              if (!plugin.getBodyStiffness) {
                  return 0;
              }
              return plugin.getBodyStiffness(this);
          },
          /**
           * Sets the stiffness of a soft body; only supported by the AmmoJSPlugin
           */
          set: function (value) {
              if (!this._physicsEngine) {
                  return;
              }
              var plugin = this._physicsEngine.getPhysicsPlugin();
              if (!plugin.setBodyStiffness) {
                  return;
              }
              plugin.setBodyStiffness(this, value);
          },
          enumerable: false,
          configurable: true
      });
      Object.defineProperty(PhysicsImpostor.prototype, "velocityIterations", {
          /**
           * Gets the velocityIterations of a soft body; only supported by the AmmoJSPlugin
           */
          get: function () {
              if (!this._physicsEngine) {
                  return 0;
              }
              var plugin = this._physicsEngine.getPhysicsPlugin();
              if (!plugin.getBodyVelocityIterations) {
                  return 0;
              }
              return plugin.getBodyVelocityIterations(this);
          },
          /**
           * Sets the velocityIterations of a soft body; only supported by the AmmoJSPlugin
           */
          set: function (value) {
              if (!this._physicsEngine) {
                  return;
              }
              var plugin = this._physicsEngine.getPhysicsPlugin();
              if (!plugin.setBodyVelocityIterations) {
                  return;
              }
              plugin.setBodyVelocityIterations(this, value);
          },
          enumerable: false,
          configurable: true
      });
      Object.defineProperty(PhysicsImpostor.prototype, "positionIterations", {
          /**
           * Gets the positionIterations of a soft body; only supported by the AmmoJSPlugin
           */
          get: function () {
              if (!this._physicsEngine) {
                  return 0;
              }
              var plugin = this._physicsEngine.getPhysicsPlugin();
              if (!plugin.getBodyPositionIterations) {
                  return 0;
              }
              return plugin.getBodyPositionIterations(this);
          },
          /**
           * Sets the positionIterations of a soft body; only supported by the AmmoJSPlugin
           */
          set: function (value) {
              if (!this._physicsEngine) {
                  return;
              }
              var plugin = this._physicsEngine.getPhysicsPlugin();
              if (!plugin.setBodyPositionIterations) {
                  return;
              }
              plugin.setBodyPositionIterations(this, value);
          },
          enumerable: false,
          configurable: true
      });
      /**
       * This function will completly initialize this impostor.
       * It will create a new body - but only if this mesh has no parent.
       * If it has, this impostor will not be used other than to define the impostor
       * of the child mesh.
       * @hidden
       */
      PhysicsImpostor.prototype._init = function () {
          if (!this._physicsEngine) {
              return;
          }
          this._physicsEngine.removeImpostor(this);
          this.physicsBody = null;
          this._parent = this._parent || this._getPhysicsParent();
          if (!this._isDisposed && (!this.parent || this._options.ignoreParent)) {
              this._physicsEngine.addImpostor(this);
          }
      };
      PhysicsImpostor.prototype._getPhysicsParent = function () {
          if (this.object.parent instanceof AbstractMesh) {
              var parentMesh = this.object.parent;
              return parentMesh.physicsImpostor;
          }
          return null;
      };
      /**
       * Should a new body be generated.
       * @returns boolean specifying if body initialization is required
       */
      PhysicsImpostor.prototype.isBodyInitRequired = function () {
          return this._bodyUpdateRequired || (!this._physicsBody && !this._parent);
      };
      /**
       * Sets the updated scaling
       * @param updated Specifies if the scaling is updated
       */
      PhysicsImpostor.prototype.setScalingUpdated = function () {
          this.forceUpdate();
      };
      /**
       * Force a regeneration of this or the parent's impostor's body.
       * Use under cautious - This will remove all joints already implemented.
       */
      PhysicsImpostor.prototype.forceUpdate = function () {
          this._init();
          if (this.parent && !this._options.ignoreParent) {
              this.parent.forceUpdate();
          }
      };
      Object.defineProperty(PhysicsImpostor.prototype, "physicsBody", {
          /*public get mesh(): AbstractMesh {
              return this._mesh;
          }*/
          /**
           * Gets the body that holds this impostor. Either its own, or its parent.
           */
          get: function () {
              return this._parent && !this._options.ignoreParent ? this._parent.physicsBody : this._physicsBody;
          },
          /**
           * Set the physics body. Used mainly by the physics engine/plugin
           */
          set: function (physicsBody) {
              if (this._physicsBody && this._physicsEngine) {
                  this._physicsEngine.getPhysicsPlugin().removePhysicsBody(this);
              }
              this._physicsBody = physicsBody;
              this.resetUpdateFlags();
          },
          enumerable: false,
          configurable: true
      });
      Object.defineProperty(PhysicsImpostor.prototype, "parent", {
          /**
           * Get the parent of the physics imposter
           * @returns Physics imposter or null
           */
          get: function () {
              return !this._options.ignoreParent && this._parent ? this._parent : null;
          },
          /**
           * Sets the parent of the physics imposter
           */
          set: function (value) {
              this._parent = value;
          },
          enumerable: false,
          configurable: true
      });
      /**
       * Resets the update flags
       */
      PhysicsImpostor.prototype.resetUpdateFlags = function () {
          this._bodyUpdateRequired = false;
      };
      /**
       * Gets the object extend size
       * @returns the object extend size
       */
      PhysicsImpostor.prototype.getObjectExtendSize = function () {
          if (this.object.getBoundingInfo) {
              var q = this.object.rotationQuaternion;
              var scaling = this.object.scaling.clone();
              //reset rotation
              this.object.rotationQuaternion = PhysicsImpostor.IDENTITY_QUATERNION;
              //calculate the world matrix with no rotation
              var worldMatrix = this.object.computeWorldMatrix && this.object.computeWorldMatrix(true);
              if (worldMatrix) {
                  worldMatrix.decompose(scaling, undefined, undefined);
              }
              var boundingInfo = this.object.getBoundingInfo();
              // get the global scaling of the object
              var size = boundingInfo.boundingBox.extendSize.scale(2).multiplyInPlace(scaling);
              //bring back the rotation
              this.object.rotationQuaternion = q;
              //calculate the world matrix with the new rotation
              this.object.computeWorldMatrix && this.object.computeWorldMatrix(true);
              return size;
          }
          else {
              return PhysicsImpostor.DEFAULT_OBJECT_SIZE;
          }
      };
      /**
       * Gets the object center
       * @returns The object center
       */
      PhysicsImpostor.prototype.getObjectCenter = function () {
          if (this.object.getBoundingInfo) {
              var boundingInfo = this.object.getBoundingInfo();
              return boundingInfo.boundingBox.centerWorld;
          }
          else {
              return this.object.position;
          }
      };
      /**
       * Get a specific parameter from the options parameters
       * @param paramName The object parameter name
       * @returns The object parameter
       */
      PhysicsImpostor.prototype.getParam = function (paramName) {
          return this._options[paramName];
      };
      /**
       * Sets a specific parameter in the options given to the physics plugin
       * @param paramName The parameter name
       * @param value The value of the parameter
       */
      PhysicsImpostor.prototype.setParam = function (paramName, value) {
          this._options[paramName] = value;
          this._bodyUpdateRequired = true;
      };
      /**
       * Specifically change the body's mass option. Won't recreate the physics body object
       * @param mass The mass of the physics imposter
       */
      PhysicsImpostor.prototype.setMass = function (mass) {
          if (this.getParam("mass") !== mass) {
              this.setParam("mass", mass);
          }
          if (this._physicsEngine) {
              this._physicsEngine.getPhysicsPlugin().setBodyMass(this, mass);
          }
      };
      /**
       * Gets the linear velocity
       * @returns  linear velocity or null
       */
      PhysicsImpostor.prototype.getLinearVelocity = function () {
          return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getLinearVelocity(this) : Vector3.Zero();
      };
      /**
       * Sets the linear velocity
       * @param velocity  linear velocity or null
       */
      PhysicsImpostor.prototype.setLinearVelocity = function (velocity) {
          if (this._physicsEngine) {
              this._physicsEngine.getPhysicsPlugin().setLinearVelocity(this, velocity);
          }
      };
      /**
       * Gets the angular velocity
       * @returns angular velocity or null
       */
      PhysicsImpostor.prototype.getAngularVelocity = function () {
          return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getAngularVelocity(this) : Vector3.Zero();
      };
      /**
       * Sets the angular velocity
       * @param velocity The velocity or null
       */
      PhysicsImpostor.prototype.setAngularVelocity = function (velocity) {
          if (this._physicsEngine) {
              this._physicsEngine.getPhysicsPlugin().setAngularVelocity(this, velocity);
          }
      };
      /**
       * Execute a function with the physics plugin native code
       * Provide a function the will have two variables - the world object and the physics body object
       * @param func The function to execute with the physics plugin native code
       */
      PhysicsImpostor.prototype.executeNativeFunction = function (func) {
          if (this._physicsEngine) {
              func(this._physicsEngine.getPhysicsPlugin().world, this.physicsBody);
          }
      };
      /**
       * Register a function that will be executed before the physics world is stepping forward
       * @param func The function to execute before the physics world is stepped forward
       */
      PhysicsImpostor.prototype.registerBeforePhysicsStep = function (func) {
          this._onBeforePhysicsStepCallbacks.push(func);
      };
      /**
       * Unregister a function that will be executed before the physics world is stepping forward
       * @param func The function to execute before the physics world is stepped forward
       */
      PhysicsImpostor.prototype.unregisterBeforePhysicsStep = function (func) {
          var index = this._onBeforePhysicsStepCallbacks.indexOf(func);
          if (index > -1) {
              this._onBeforePhysicsStepCallbacks.splice(index, 1);
          }
          else {
              Logger.Warn("Function to remove was not found");
          }
      };
      /**
       * Register a function that will be executed after the physics step
       * @param func The function to execute after physics step
       */
      PhysicsImpostor.prototype.registerAfterPhysicsStep = function (func) {
          this._onAfterPhysicsStepCallbacks.push(func);
      };
      /**
       * Unregisters a function that will be executed after the physics step
       * @param func The function to execute after physics step
       */
      PhysicsImpostor.prototype.unregisterAfterPhysicsStep = function (func) {
          var index = this._onAfterPhysicsStepCallbacks.indexOf(func);
          if (index > -1) {
              this._onAfterPhysicsStepCallbacks.splice(index, 1);
          }
          else {
              Logger.Warn("Function to remove was not found");
          }
      };
      /**
       * register a function that will be executed when this impostor collides against a different body
       * @param collideAgainst Physics imposter, or array of physics imposters to collide against
       * @param func Callback that is executed on collision
       */
      PhysicsImpostor.prototype.registerOnPhysicsCollide = function (collideAgainst, func) {
          var collidedAgainstList = collideAgainst instanceof Array ? collideAgainst : [collideAgainst];
          this._onPhysicsCollideCallbacks.push({ callback: func, otherImpostors: collidedAgainstList });
      };
      /**
       * Unregisters the physics imposter on contact
       * @param collideAgainst The physics object to collide against
       * @param func Callback to execute on collision
       */
      PhysicsImpostor.prototype.unregisterOnPhysicsCollide = function (collideAgainst, func) {
          var collidedAgainstList = collideAgainst instanceof Array ? collideAgainst : [collideAgainst];
          var index = -1;
          var found = this._onPhysicsCollideCallbacks.some(function (cbDef, idx) {
              if (cbDef.callback === func && cbDef.otherImpostors.length === collidedAgainstList.length) {
                  // chcek the arrays match
                  var sameList = cbDef.otherImpostors.every(function (impostor) {
                      return collidedAgainstList.indexOf(impostor) > -1;
                  });
                  if (sameList) {
                      index = idx;
                  }
                  return sameList;
              }
              return false;
          });
          if (found) {
              this._onPhysicsCollideCallbacks.splice(index, 1);
          }
          else {
              Logger.Warn("Function to remove was not found");
          }
      };
      /**
       * Get the parent rotation
       * @returns The parent rotation
       */
      PhysicsImpostor.prototype.getParentsRotation = function () {
          var parent = this.object.parent;
          this._tmpQuat.copyFromFloats(0, 0, 0, 1);
          while (parent) {
              if (parent.rotationQuaternion) {
                  this._tmpQuat2.copyFrom(parent.rotationQuaternion);
              }
              else {
                  Quaternion.RotationYawPitchRollToRef(parent.rotation.y, parent.rotation.x, parent.rotation.z, this._tmpQuat2);
              }
              this._tmpQuat.multiplyToRef(this._tmpQuat2, this._tmpQuat);
              parent = parent.parent;
          }
          return this._tmpQuat;
      };
      /**
       * Apply a force
       * @param force The force to apply
       * @param contactPoint The contact point for the force
       * @returns The physics imposter
       */
      PhysicsImpostor.prototype.applyForce = function (force, contactPoint) {
          if (this._physicsEngine) {
              this._physicsEngine.getPhysicsPlugin().applyForce(this, force, contactPoint);
          }
          return this;
      };
      /**
       * Apply an impulse
       * @param force The impulse force
       * @param contactPoint The contact point for the impulse force
       * @returns The physics imposter
       */
      PhysicsImpostor.prototype.applyImpulse = function (force, contactPoint) {
          if (this._physicsEngine) {
              this._physicsEngine.getPhysicsPlugin().applyImpulse(this, force, contactPoint);
          }
          return this;
      };
      /**
       * A help function to create a joint
       * @param otherImpostor A physics imposter used to create a joint
       * @param jointType The type of joint
       * @param jointData The data for the joint
       * @returns The physics imposter
       */
      PhysicsImpostor.prototype.createJoint = function (otherImpostor, jointType, jointData) {
          var joint = new PhysicsJoint(jointType, jointData);
          this.addJoint(otherImpostor, joint);
          return this;
      };
      /**
       * Add a joint to this impostor with a different impostor
       * @param otherImpostor A physics imposter used to add a joint
       * @param joint The joint to add
       * @returns The physics imposter
       */
      PhysicsImpostor.prototype.addJoint = function (otherImpostor, joint) {
          this._joints.push({
              otherImpostor: otherImpostor,
              joint: joint,
          });
          if (this._physicsEngine) {
              this._physicsEngine.addJoint(this, otherImpostor, joint);
          }
          return this;
      };
      /**
       * Add an anchor to a cloth impostor
       * @param otherImpostor rigid impostor to anchor to
       * @param width ratio across width from 0 to 1
       * @param height ratio up height from 0 to 1
       * @param influence the elasticity between cloth impostor and anchor from 0, very stretchy to 1, little strech
       * @param noCollisionBetweenLinkedBodies when true collisions between cloth impostor and anchor are ignored; default false
       * @returns impostor the soft imposter
       */
      PhysicsImpostor.prototype.addAnchor = function (otherImpostor, width, height, influence, noCollisionBetweenLinkedBodies) {
          if (!this._physicsEngine) {
              return this;
          }
          var plugin = this._physicsEngine.getPhysicsPlugin();
          if (!plugin.appendAnchor) {
              return this;
          }
          if (this._physicsEngine) {
              plugin.appendAnchor(this, otherImpostor, width, height, influence, noCollisionBetweenLinkedBodies);
          }
          return this;
      };
      /**
       * Add a hook to a rope impostor
       * @param otherImpostor rigid impostor to anchor to
       * @param length ratio across rope from 0 to 1
       * @param influence the elasticity between rope impostor and anchor from 0, very stretchy to 1, little strech
       * @param noCollisionBetweenLinkedBodies when true collisions between soft impostor and anchor are ignored; default false
       * @returns impostor the rope imposter
       */
      PhysicsImpostor.prototype.addHook = function (otherImpostor, length, influence, noCollisionBetweenLinkedBodies) {
          if (!this._physicsEngine) {
              return this;
          }
          var plugin = this._physicsEngine.getPhysicsPlugin();
          if (!plugin.appendAnchor) {
              return this;
          }
          if (this._physicsEngine) {
              plugin.appendHook(this, otherImpostor, length, influence, noCollisionBetweenLinkedBodies);
          }
          return this;
      };
      /**
       * Will keep this body still, in a sleep mode.
       * @returns the physics imposter
       */
      PhysicsImpostor.prototype.sleep = function () {
          if (this._physicsEngine) {
              this._physicsEngine.getPhysicsPlugin().sleepBody(this);
          }
          return this;
      };
      /**
       * Wake the body up.
       * @returns The physics imposter
       */
      PhysicsImpostor.prototype.wakeUp = function () {
          if (this._physicsEngine) {
              this._physicsEngine.getPhysicsPlugin().wakeUpBody(this);
          }
          return this;
      };
      /**
       * Clones the physics imposter
       * @param newObject The physics imposter clones to this physics-enabled object
       * @returns A nullable physics imposter
       */
      PhysicsImpostor.prototype.clone = function (newObject) {
          if (!newObject) {
              return null;
          }
          return new PhysicsImpostor(newObject, this.type, this._options, this._scene);
      };
      /**
       * Disposes the physics imposter
       */
      PhysicsImpostor.prototype.dispose = function ( /*disposeChildren: boolean = true*/) {
          var _this = this;
          //no dispose if no physics engine is available.
          if (!this._physicsEngine) {
              return;
          }
          this._joints.forEach(function (j) {
              if (_this._physicsEngine) {
                  _this._physicsEngine.removeJoint(_this, j.otherImpostor, j.joint);
              }
          });
          //dispose the physics body
          this._physicsEngine.removeImpostor(this);
          if (this.parent) {
              this.parent.forceUpdate();
          }
          else {
              /*this._object.getChildMeshes().forEach(function(mesh) {
                  if (mesh.physicsImpostor) {
                      if (disposeChildren) {
                          mesh.physicsImpostor.dispose();
                          mesh.physicsImpostor = null;
                      }
                  }
              })*/
          }
          this._isDisposed = true;
      };
      /**
       * Sets the delta position
       * @param position The delta position amount
       */
      PhysicsImpostor.prototype.setDeltaPosition = function (position) {
          this._deltaPosition.copyFrom(position);
      };
      /**
       * Sets the delta rotation
       * @param rotation The delta rotation amount
       */
      PhysicsImpostor.prototype.setDeltaRotation = function (rotation) {
          if (!this._deltaRotation) {
              this._deltaRotation = new Quaternion();
          }
          this._deltaRotation.copyFrom(rotation);
          this._deltaRotationConjugated = this._deltaRotation.conjugate();
      };
      /**
       * Gets the box size of the physics imposter and stores the result in the input parameter
       * @param result Stores the box size
       * @returns The physics imposter
       */
      PhysicsImpostor.prototype.getBoxSizeToRef = function (result) {
          if (this._physicsEngine) {
              this._physicsEngine.getPhysicsPlugin().getBoxSizeToRef(this, result);
          }
          return this;
      };
      /**
       * Gets the radius of the physics imposter
       * @returns Radius of the physics imposter
       */
      PhysicsImpostor.prototype.getRadius = function () {
          return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getRadius(this) : 0;
      };
      /**
       * Sync a bone with this impostor
       * @param bone The bone to sync to the impostor.
       * @param boneMesh The mesh that the bone is influencing.
       * @param jointPivot The pivot of the joint / bone in local space.
       * @param distToJoint Optional distance from the impostor to the joint.
       * @param adjustRotation Optional quaternion for adjusting the local rotation of the bone.
       */
      PhysicsImpostor.prototype.syncBoneWithImpostor = function (bone, boneMesh, jointPivot, distToJoint, adjustRotation) {
          var tempVec = PhysicsImpostor._tmpVecs[0];
          var mesh = this.object;
          if (mesh.rotationQuaternion) {
              if (adjustRotation) {
                  var tempQuat = PhysicsImpostor._tmpQuat;
                  mesh.rotationQuaternion.multiplyToRef(adjustRotation, tempQuat);
                  bone.setRotationQuaternion(tempQuat, Space.WORLD, boneMesh);
              }
              else {
                  bone.setRotationQuaternion(mesh.rotationQuaternion, Space.WORLD, boneMesh);
              }
          }
          tempVec.x = 0;
          tempVec.y = 0;
          tempVec.z = 0;
          if (jointPivot) {
              tempVec.x = jointPivot.x;
              tempVec.y = jointPivot.y;
              tempVec.z = jointPivot.z;
              bone.getDirectionToRef(tempVec, boneMesh, tempVec);
              if (distToJoint === undefined || distToJoint === null) {
                  distToJoint = jointPivot.length();
              }
              tempVec.x *= distToJoint;
              tempVec.y *= distToJoint;
              tempVec.z *= distToJoint;
          }
          if (bone.getParent()) {
              tempVec.addInPlace(mesh.getAbsolutePosition());
              bone.setAbsolutePosition(tempVec, boneMesh);
          }
          else {
              boneMesh.setAbsolutePosition(mesh.getAbsolutePosition());
              boneMesh.position.x -= tempVec.x;
              boneMesh.position.y -= tempVec.y;
              boneMesh.position.z -= tempVec.z;
          }
      };
      /**
       * Sync impostor to a bone
       * @param bone The bone that the impostor will be synced to.
       * @param boneMesh The mesh that the bone is influencing.
       * @param jointPivot The pivot of the joint / bone in local space.
       * @param distToJoint Optional distance from the impostor to the joint.
       * @param adjustRotation Optional quaternion for adjusting the local rotation of the bone.
       * @param boneAxis Optional vector3 axis the bone is aligned with
       */
      PhysicsImpostor.prototype.syncImpostorWithBone = function (bone, boneMesh, jointPivot, distToJoint, adjustRotation, boneAxis) {
          var mesh = this.object;
          if (mesh.rotationQuaternion) {
              if (adjustRotation) {
                  var tempQuat = PhysicsImpostor._tmpQuat;
                  bone.getRotationQuaternionToRef(Space.WORLD, boneMesh, tempQuat);
                  tempQuat.multiplyToRef(adjustRotation, mesh.rotationQuaternion);
              }
              else {
                  bone.getRotationQuaternionToRef(Space.WORLD, boneMesh, mesh.rotationQuaternion);
              }
          }
          var pos = PhysicsImpostor._tmpVecs[0];
          var boneDir = PhysicsImpostor._tmpVecs[1];
          if (!boneAxis) {
              boneAxis = PhysicsImpostor._tmpVecs[2];
              boneAxis.x = 0;
              boneAxis.y = 1;
              boneAxis.z = 0;
          }
          bone.getDirectionToRef(boneAxis, boneMesh, boneDir);
          bone.getAbsolutePositionToRef(boneMesh, pos);
          if ((distToJoint === undefined || distToJoint === null) && jointPivot) {
              distToJoint = jointPivot.length();
          }
          if (distToJoint !== undefined && distToJoint !== null) {
              pos.x += boneDir.x * distToJoint;
              pos.y += boneDir.y * distToJoint;
              pos.z += boneDir.z * distToJoint;
          }
          mesh.setAbsolutePosition(pos);
      };
      /**
       * The default object size of the imposter
       */
      PhysicsImpostor.DEFAULT_OBJECT_SIZE = new Vector3(1, 1, 1);
      /**
       * The identity quaternion of the imposter
       */
      PhysicsImpostor.IDENTITY_QUATERNION = Quaternion.Identity();
      PhysicsImpostor._tmpVecs = ArrayTools.BuildArray(3, Vector3.Zero);
      PhysicsImpostor._tmpQuat = Quaternion.Identity();
      //Impostor types
      /**
       * No-Imposter type
       */
      PhysicsImpostor.NoImpostor = 0;
      /**
       * Sphere-Imposter type
       */
      PhysicsImpostor.SphereImpostor = 1;
      /**
       * Box-Imposter type
       */
      PhysicsImpostor.BoxImpostor = 2;
      /**
       * Plane-Imposter type
       */
      PhysicsImpostor.PlaneImpostor = 3;
      /**
       * Mesh-imposter type
       */
      PhysicsImpostor.MeshImpostor = 4;
      /**
       * Capsule-Impostor type (Ammo.js plugin only)
       */
      PhysicsImpostor.CapsuleImpostor = 6;
      /**
       * Cylinder-Imposter type
       */
      PhysicsImpostor.CylinderImpostor = 7;
      /**
       * Particle-Imposter type
       */
      PhysicsImpostor.ParticleImpostor = 8;
      /**
       * Heightmap-Imposter type
       */
      PhysicsImpostor.HeightmapImpostor = 9;
      /**
       * ConvexHull-Impostor type (Ammo.js plugin only)
       */
      PhysicsImpostor.ConvexHullImpostor = 10;
      /**
       * Custom-Imposter type (Ammo.js plugin only)
       */
      PhysicsImpostor.CustomImpostor = 100;
      /**
       * Rope-Imposter type
       */
      PhysicsImpostor.RopeImpostor = 101;
      /**
       * Cloth-Imposter type
       */
      PhysicsImpostor.ClothImpostor = 102;
      /**
       * Softbody-Imposter type
       */
      PhysicsImpostor.SoftbodyImpostor = 103;
      return PhysicsImpostor;
  }());
  export { PhysicsImpostor };
  //# sourceMappingURL=physicsImpostor.js.map