# How to rotate an object depending on the position on the sphere?

Who can help me understand what I am doing wrong? I need to move an object along an imaginary sphere around the planet, and the bottom of the object should always be perpendicular to the surface of the planet. The movement works correctly for me, but there is a problem with rotation along one of the axes. When I move an object from its original position up or down, everything works correctly, the object is always perpendicular to the surface of the planet, but when I move the object to the left or right, the rotation starts to accelerate. Below are screenshots of the object’s behavior, as well as part of the code.
I should note that the initial position of the object is set from the settings, namely the latitude, longitude, radius, as well as the initial rotation of the object. I use TweenJS for smooth movement.

let newLat = 0;
let newLon = 0;
if (this.prevLat === null && this.prevLon === null) {
this.prevLat = targetModel.lat;
this.prevLon = targetModel.lon;
}
if (event.key === 'W' || event.key === 'ArrowUp') {
newLat = this.prevLat + this.ySpeed;
newLon = this.prevLon;
} else if (event.key === 'S' || event.key === 'ArrowDown') {
newLat = this.prevLat - this.ySpeed;
newLon = this.prevLon;
} else if (event.key === 'A' || event.key === 'ArrowLeft') {
newLon = this.prevLon - this.xSpeed;
newLat = this.prevLat;
} else if (event.key === 'D' || event.key === 'ArrowRight') {
newLon = this.prevLon + this.xSpeed;
newLat = this.prevLat;
} else if (event.key === 'Spacebar') {
//existedObject.position.set(0, 0, 0);
}
let { newPosition, newRotation } = this.getNewPositionOfTheObjectOnTheSphere(newLat, newLon, targetModel.radiusOffset);
let tempObjForRotation = existedObject.clone();
tempObjForRotation.rotation.x = newRotation.x;
tempObjForRotation.rotation.y = newRotation.y;
tempObjForRotation.rotation.z = newRotation.z;
this.rotateObject(tempObjForRotation, targetModel.rotation);
newRotation = {
x: tempObjForRotation.rotation.x,
y: tempObjForRotation.rotation.y,
z: tempObjForRotation.rotation.z
};
this.prevLat = newLat;
this.prevLon = newLon;

let vectorOfExistedObj = existedObject.rotation.toVector3();
vectorOfExistedObj.x = Math.abs(vectorOfExistedObj.x);
vectorOfExistedObj.y = Math.abs(vectorOfExistedObj.y);
vectorOfExistedObj.z = Math.abs(vectorOfExistedObj.z);
let vectorOfTempObj = tempObjForRotation.rotation.toVector3();
//let vectorOfTempObj = new THREE.Vector3(newRotation.x, newRotation.y, newRotation.z);
vectorOfTempObj.x = Math.abs(vectorOfTempObj.x);
vectorOfTempObj.y = Math.abs(vectorOfTempObj.y);
vectorOfTempObj.z = Math.abs(vectorOfTempObj.z);

let rotationModel = {
x: 0,
y: 0,
z: 0
};

if (event.key === 'W' || event.key === 'ArrowUp') {
rotationModel.z = -angleDifference;
} else if (event.key === 'S' || event.key === 'ArrowDown') {
rotationModel.z = angleDifference;
} else if (event.key === 'A' || event.key === 'ArrowLeft') {
rotationModel.x = -angleDifference;
} else if (event.key === 'D' || event.key === 'ArrowRight') {
rotationModel.x = angleDifference;
} else if (event.key === 'Spacebar') {
//existedObject.position.set(0, 0, 0);
}

this.rotateObject(existedObject, rotationModel);

let positionTween = new TWEEN.Tween(existedObject.position)
.to(newPosition, 1000)
.onStart(() => {
this.blockPositionMovement = true;
})
.onComplete(() => {
this.blockPositionMovement = false;
})
.start();
private getNewPositionOfTheObjectOnTheSphere(lat: number, lon: number, radiusOffset: number) {
let planetSize = this.getPlanetSize();
let latRad = lat * (Math.PI / 180);
let lonRad = -lon * (Math.PI / 180);
return {
newPosition: new THREE.Vector3(
),
newRotation: { x: 0.0, y: -lonRad, z: latRad - Math.PI * 0.5 }
};
}
private rotateObject(object: any, rotation: EulerAngles) {
if (rotation.x !== 0) {
}
if (rotation.y !== 0) {
}
if (rotation.z !== 0) {
}
}

I found a correct solution. Now I am using quaternions for rotation.

let tempObjForRotation = existedObject.clone();
tempObjForRotation.quaternion.setFromEuler(new THREE.Euler(newRotation.x, newRotation.y, newRotation.z));

***
let quaternionA = new THREE.Quaternion().copy(existedObject.quaternion); // src quaternion
let quaternionB = new THREE.Quaternion().copy(tempObjForRotation.quaternion); // dst quaternion
let quaternionM = new THREE.Quaternion();
let o = { t: 0 };

let rotationTween = new TWEEN.Tween(o).to({ t: 1 }, 500).onUpdate(() => {
quaternionM.slerpQuaternions(quaternionA, quaternionB, o.t)
existedObject.quaternion.set(quaternionM.x, quaternionM.y, quaternionM.z, quaternionM.w);
}).start();