From 0b87df45b5bb586a15a092fe322ef20e224a7dde Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Tue, 10 Jul 2018 11:16:56 -0700
Subject: [PATCH 1/4] cleanup return statement

---
 libraries/entities/src/EntityItem.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 31ec189cf9..8e382fabd4 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -2414,11 +2414,7 @@ bool EntityItem::shouldSuppressLocationEdits() const {
     }
 
     // if any of the ancestors are MyAvatar, suppress
-    if (isChildOfMyAvatar()) {
-        return true;
-    }
-
-    return false;
+    return isChildOfMyAvatar();
 }
 
 QList<EntityDynamicPointer> EntityItem::getActionsOfType(EntityDynamicType typeToGet) const {

From 9171fcbe8bdbf08a48a0550188818d0c54b6d011 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Tue, 10 Jul 2018 11:17:13 -0700
Subject: [PATCH 2/4]  explicit insert/erase into _simpleKinematicEntities

---
 .../physics/src/PhysicalEntitySimulation.cpp  | 55 +++++++++++++------
 1 file changed, 38 insertions(+), 17 deletions(-)

diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp
index b990d3612b..5666e75aa1 100644
--- a/libraries/physics/src/PhysicalEntitySimulation.cpp
+++ b/libraries/physics/src/PhysicalEntitySimulation.cpp
@@ -59,7 +59,10 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
             _entitiesToAddToPhysics.insert(entity);
         }
     } else if (canBeKinematic && entity->isMovingRelativeToParent()) {
-        _simpleKinematicEntities.insert(entity);
+        SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+        if (itr == _simpleKinematicEntities.end()) {
+            _simpleKinematicEntities.insert(entity);
+        }
     }
 }
 
@@ -150,7 +153,10 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
             removeOwnershipData(motionState);
             _entitiesToRemoveFromPhysics.insert(entity);
             if (canBeKinematic && entity->isMovingRelativeToParent()) {
-                _simpleKinematicEntities.insert(entity);
+                SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+                if (itr == _simpleKinematicEntities.end()) {
+                    _simpleKinematicEntities.insert(entity);
+                }
             }
         } else {
             _incomingChanges.insert(motionState);
@@ -160,11 +166,20 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
         // The intent is for this object to be in the PhysicsEngine, but it has no MotionState yet.
         // Perhaps it's shape has changed and it can now be added?
         _entitiesToAddToPhysics.insert(entity);
-        _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic
+        SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+        if (itr != _simpleKinematicEntities.end()) {
+            _simpleKinematicEntities.erase(itr);
+        }
     } else if (canBeKinematic && entity->isMovingRelativeToParent()) {
-        _simpleKinematicEntities.insert(entity);
+        SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+        if (itr == _simpleKinematicEntities.end()) {
+            _simpleKinematicEntities.insert(entity);
+        }
     } else {
-        _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic
+        SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+        if (itr != _simpleKinematicEntities.end()) {
+            _simpleKinematicEntities.erase(itr);
+        }
     }
 }
 
@@ -212,7 +227,6 @@ const VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemoveFromPhys
         assert(motionState);
       // TODO CLEan this, just a n extra check to avoid the crash that shouldn;t happen
       if (motionState) {
-
             _entitiesToAddToPhysics.remove(entity);
             if (entity->isDead() && entity->getElement()) {
                 _deadEntities.insert(entity);
@@ -255,7 +269,10 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re
             // this entity should no longer be on the internal _entitiesToAddToPhysics
             entityItr = _entitiesToAddToPhysics.erase(entityItr);
             if (entity->isMovingRelativeToParent()) {
-                _simpleKinematicEntities.insert(entity);
+                SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
+                if (itr == _simpleKinematicEntities.end()) {
+                    _simpleKinematicEntities.insert(entity);
+                }
             }
         } else if (entity->isReadyToComputeShape()) {
             ShapeInfo shapeInfo;
@@ -375,19 +392,21 @@ void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionSta
 }
 
 void PhysicalEntitySimulation::addOwnershipBid(EntityMotionState* motionState) {
-    if (!getEntityTree()->isServerlessMode()) {
-        motionState->initForBid();
-        motionState->sendBid(_entityPacketSender, _physicsEngine->getNumSubsteps());
-        _bids.push_back(motionState);
-        _nextBidExpiry = glm::min(_nextBidExpiry, motionState->getNextBidExpiry());
+    if (getEntityTree()->isServerlessMode()) {
+        return;
     }
+    motionState->initForBid();
+    motionState->sendBid(_entityPacketSender, _physicsEngine->getNumSubsteps());
+    _bids.push_back(motionState);
+    _nextBidExpiry = glm::min(_nextBidExpiry, motionState->getNextBidExpiry());
 }
 
 void PhysicalEntitySimulation::addOwnership(EntityMotionState* motionState) {
-    if (!getEntityTree()->isServerlessMode()) {
-        motionState->initForOwned();
-        _owned.push_back(motionState);
+    if (getEntityTree()->isServerlessMode()) {
+        return;
     }
+    motionState->initForOwned();
+    _owned.push_back(motionState);
 }
 
 void PhysicalEntitySimulation::sendOwnershipBids(uint32_t numSubsteps) {
@@ -426,7 +445,9 @@ void PhysicalEntitySimulation::sendOwnershipBids(uint32_t numSubsteps) {
 }
 
 void PhysicalEntitySimulation::sendOwnedUpdates(uint32_t numSubsteps) {
-    bool serverlessMode = getEntityTree()->isServerlessMode();
+    if (getEntityTree()->isServerlessMode()) {
+        return;
+    }
     PROFILE_RANGE_EX(simulation_physics, "Update", 0x00000000, (uint64_t)_owned.size());
     uint32_t i = 0;
     while (i < _owned.size()) {
@@ -438,7 +459,7 @@ void PhysicalEntitySimulation::sendOwnedUpdates(uint32_t numSubsteps) {
             }
             _owned.remove(i);
         } else {
-            if (!serverlessMode && _owned[i]->shouldSendUpdate(numSubsteps)) {
+            if (_owned[i]->shouldSendUpdate(numSubsteps)) {
                 _owned[i]->sendUpdate(_entityPacketSender, numSubsteps);
             }
             ++i;

From dd6be374fadd79227e411c116175f3f0002d6559 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Tue, 10 Jul 2018 11:18:38 -0700
Subject: [PATCH 3/4] cleanup and optimization rotational integration

---
 libraries/shared/src/PhysicsHelpers.cpp | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/libraries/shared/src/PhysicsHelpers.cpp b/libraries/shared/src/PhysicsHelpers.cpp
index b43d55020e..988af98c46 100644
--- a/libraries/shared/src/PhysicsHelpers.cpp
+++ b/libraries/shared/src/PhysicsHelpers.cpp
@@ -42,22 +42,27 @@ glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float time
     // Exponential map
     // google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia
 
-    float speed = glm::length(angularVelocity);
+    glm::vec3 axis = angularVelocity;
+    float angle = glm::length(axis) * timeStep;
     // limit the angular motion because the exponential approximation fails for large steps
     const float ANGULAR_MOTION_THRESHOLD = 0.5f * PI_OVER_TWO;
-    if (speed * timeStep > ANGULAR_MOTION_THRESHOLD) {
-        speed = ANGULAR_MOTION_THRESHOLD / timeStep;
+    if (angle > ANGULAR_MOTION_THRESHOLD) {
+        angle = ANGULAR_MOTION_THRESHOLD;
     }
 
-    glm::vec3 axis = angularVelocity;
-    if (speed < 0.001f) {
-        // use Taylor's expansions of sync function
-        axis *= (0.5f * timeStep - (timeStep * timeStep * timeStep) * (0.020833333333f * speed * speed));
+    const float MIN_ANGLE = 0.001f;
+    if (angle < MIN_ANGLE) {
+        // for small angles use Taylor's expansion of sin(x):
+        //   sin(x) = x - (x^3)/(3!) + ...
+        // where: x = angle/2
+        //   sin(angle/2) = angle/2 - (angle*angle*angle)/48
+        // but (angle = speed * timeStep) and we want to normalize the axis by dividing by speed
+        // which gives us:
+        axis *= timeStep * (0.5f - 0.020833333333f * angle * angle);
     } else {
-        // sync(speed) = sin(c * speed)/t
-        axis *= (sinf(0.5f * speed * timeStep) / speed );
+        axis *= (sinf(0.5f * angle) * timeStep / angle);
     }
-    return glm::quat(cosf(0.5f * speed * timeStep), axis.x, axis.y, axis.z);
+    return glm::quat(cosf(0.5f * angle), axis.x, axis.y, axis.z);
 }
 /* end Bullet code derivation*/
 

From 8ea18e3359405eefdb97afc27ba2958c7e2f376d Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Tue, 10 Jul 2018 11:20:18 -0700
Subject: [PATCH 4/4] integrate active kinematic even when grabbed

---
 libraries/physics/src/EntityMotionState.cpp | 40 ++++++++++++---------
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp
index 9089f02aaf..a610a6f2a6 100644
--- a/libraries/physics/src/EntityMotionState.cpp
+++ b/libraries/physics/src/EntityMotionState.cpp
@@ -234,7 +234,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
         return;
     }
     assert(entityTreeIsLocked());
-    if (_motionType == MOTION_TYPE_KINEMATIC && !_entity->hasAncestorOfType(NestableType::Avatar)) {
+    if (_motionType == MOTION_TYPE_KINEMATIC) {
         BT_PROFILE("kinematicIntegration");
         // This is physical kinematic motion which steps strictly by the subframe count
         // of the physics simulation and uses full gravity for acceleration.
@@ -327,13 +327,6 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
         return true;
     }
 
-    bool parentTransformSuccess;
-    Transform localToWorld = _entity->getParentTransform(parentTransformSuccess);
-    Transform worldToLocal;
-    if (parentTransformSuccess) {
-        localToWorld.evalInverse(worldToLocal);
-    }
-
     int numSteps = simulationStep - _lastStep;
     float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP;
 
@@ -361,6 +354,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
         return true;
     }
 
+    if (_body->isStaticOrKinematicObject()) {
+        return false;
+    }
+
     _lastStep = simulationStep;
     if (glm::length2(_serverVelocity) > 0.0f) {
         // the entity-server doesn't know where avatars are, so it doesn't do simple extrapolation for children of
@@ -388,6 +385,12 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
     // TODO: compensate for _worldOffset offset here
 
     // compute position error
+    bool parentTransformSuccess;
+    Transform localToWorld = _entity->getParentTransform(parentTransformSuccess);
+    Transform worldToLocal;
+    if (parentTransformSuccess) {
+        localToWorld.evalInverse(worldToLocal);
+    }
 
     btTransform worldTrans = _body->getWorldTransform();
     glm::vec3 position = worldToLocal.transform(bulletToGLM(worldTrans.getOrigin()));
@@ -407,20 +410,23 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
 
     if (glm::length2(_serverAngularVelocity) > 0.0f) {
         // compute rotation error
-        float attenuation = powf(1.0f - _body->getAngularDamping(), dt);
-        _serverAngularVelocity *= attenuation;
+        //
 
         // Bullet caps the effective rotation velocity inside its rotation integration step, therefore
         // we must integrate with the same algorithm and timestep in order achieve similar results.
-        for (int i = 0; i < numSteps; ++i) {
-            _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity,
-                                                                       PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);
+        float attenuation = powf(1.0f - _body->getAngularDamping(), PHYSICS_ENGINE_FIXED_SUBSTEP);
+        _serverAngularVelocity *= attenuation;
+        glm::quat rotation = computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
+        for (int i = 1; i < numSteps; ++i) {
+            _serverAngularVelocity *= attenuation;
+            rotation = computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * rotation;
         }
+        _serverRotation = glm::normalize(rotation * _serverRotation);
+        const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation
+        glm::quat actualRotation = worldToLocal.getRotation() * bulletToGLM(worldTrans.getRotation());
+        return (fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT);
     }
-    const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation
-    glm::quat actualRotation = worldToLocal.getRotation() * bulletToGLM(worldTrans.getRotation());
-
-    return (fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT);
+    return false;
 }
 
 bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {