I am attempting to calculate a full 360 degree rotation from a captured starting angle while the phone is being held vertically in either portrait or landscape.
I can easily get a starting angle by listening to the deviceorientation event and capturing the beta and gamma values to calculate a "start" angle with a button click => let startAngle = Match.atan2(beta,gamma)/(Math.PI /180)
I then calc the to delta with Math.abs(currentAngle - startAngle). The problem is when I cross 180 or -180 values I don't know the direction I came from. I also cross that boundary twice getting to 360. I could also go either clockwise or counter clockwise (pitch up or down). I would like to calculate a full 360 and reset to 0 at the start point. Not sure if using Trigonometry is the way to go here. Thanks in advance for any help or suedo logic that will help.
var startAngle = 150; //Just a test start value. Usually comes from setPoint button click
var currAngle = 0;
var calcRotation = 0;
window.addEventListener('deviceorientation', this.orientation, false);
orientation = event => {
var alpha = event.alpha;
var beta = event.beta;
var gamma = event.gamma;
//If device is vertical
if(this.isVertical)
{
this.currAngle = Math.round(Math.atan2(beta, gamma) / (Math.PI/180));
//Calculate the difference
this.calcRotation = this.currAngle - this.startAngle;
Related
Im trying to figure out how to simulate where the new XY coords and rotation will be based on the speed of two motors. e.g if the left wheel is at 50% speed and the right wheel is at 80% speed then it will go forwards but slightly to the left.
I'm using JavaScript to draw onto a canvas.
function setMotors(left, right){
var motorLoop = setTimeout(() =>{
rotation = //new rotation
x = //new x
y = //new y
clearCvs();
drawRobot(x, y, rotation);
}, 1000/60);
}
I see it like this:
where l0,l1 are the arclengths traveled by wheels, d is distance between wheels and r is turning radius of the first wheel leading to system:
omg * r = v0
omg *(r+d) = v1
where omg is the turn speed [rad/s] so (unless I made a math mistake):
r = (v0*d)/(v1-v0) [units]
omg = (v1-v0)/d [rad/s]
using your values:
r = (50*30)/(80-50) = 50.0 [pixels]
omg = (80-50)/30 = 1.0 [rad/s] = ~57.3 [deg/s]
Ignoring all possible grip/drift issues ... Signs of the results determine on which side the robot turns ...
This one is bugging me quite a bit.
I'm trying to achieve rotation of a Cannon.Body based on the mouse input.
By using the (Cannon) Three FPS example to demonstrate, you can see what the issue is.
https://codepen.io/Raggar/pen/EggaZP
https://github.com/RaggarDK/Baby/blob/baby/pl.js
When you run the code and enable pointerlockcontrols by clicking on the "click to play" area and press W for 1 second to get the sphere into the view of the camera, you'll see that the sphere moves according to the WASD keys by applying velocity. If you move the mouse, the quaternion is applied to the Body, and the proper velocity is calculated.
Now turn 180 degrees, and the rotation on the X axis is now negated somehow.
When moving the mouse up, the sphere rotates down.
How would one fix such issue? Maybe I'm doing something wrong elsewhere, that might mess with the quaternion?
Maybe I should mention, in the playercontroller(pl.js), I'm applying the rotation to the sphereBody, instead of the yaw- and pitchObjects.
Relevant code from pl.js (Line 49):
var onMouseMove = function ( event ) {
if ( scope.enabled === false ) return;
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
cannonBody.rotation.y -= movementX * 0.002;
cannonBody.rotation.x -= movementY * 0.002;
cannonBody.rotation.x = Math.max( - PI_2, Math.min( PI_2, cannonBody.rotation.x ) );
//console.log(cannonBody.rotation);
};
And (Line 174):
euler.x = cannonBody.rotation.x;
euler.y = cannonBody.rotation.y;
euler.order = "XYZ";
quat.setFromEuler(euler);
inputVelocity.applyQuaternion(quat);
cannonBody.quaternion.copy(quat);
velocity.x = inputVelocity.x;
velocity.z = inputVelocity.z;
Inside the animate() function, codepen (Line 305):
testballMesh.position.copy(sphereBody.position);
testballMesh.quaternion.copy(sphereBody.quaternion);
The problem is the way you assign angles to and from the Quaternions. The quaternion x,y,z,w properties are not directly compatible with angles, so you need to convert.
This is how to set the angle around a given axis for a CANNON.Quaternion:
var axis = new CANNON.Vec3(1,0,0);
var angle = Math.PI / 3;
body.quaternion.setFromAxisAngle(axis, angle);
Extracting the Euler angles from quaternions is probably not be the best way to attack the second part of the problem. You could instead just store the rotation around X and Y axes when the user moves the mouse:
// Declare variables outside the mouse handler
var angleX=0, angleY=0;
// Inside the handler:
angleY -= movementX * 0.002;
angleX -= movementY * 0.002;
angleX = Math.max( - PI_2, Math.min( PI_2, angleX ) );
And then to get the rotation as a quaternion, use two quaternions separately (one for X angle and one for Y) and then combine them to one:
var quatX = new CANNON.Quaternion();
var quatY = new CANNON.Quaternion();
quatX.setFromAxisAngle(new CANNON.Vec3(1,0,0), angleX);
quatY.setFromAxisAngle(new CANNON.Vec3(0,1,0), angleY);
var quaternion = quatY.mult(quatX);
quaternion.normalize();
To apply the quaternion to your velocity vector:
var rotatedVelocity = quaternion.vmult(inputVelocity);
Pro tip: don't use Euler angles if you can avoid them. They usually cause more problems than they solve.
I need to calculate the angle between 3 points. For this, I do the following:
Grab the 3 points (previous, current and next, it's within a loop)
Calculate the distance between the points with Pythagoras
Calculate the angle using Math.acos
This seems to work fine for shapes without angels of over 180 degrees, however if a shape has such an corner it calculates the short-side. Here's an illustration to show what I mean (the red values are wrong):
This is the code that does the calculations:
// Pythagoras for calculating distance between two points (2D)
pointDistance = function (p1x, p1y, p2x, p2y) {
return Math.sqrt((p1x - p2x)*(p1x - p2x) + (p1y - p2y)*(p1y - p2y));
};
// Get the distance between the previous, current and next points
// vprev, vcur and vnext are objects that look like this:
// { x:float, y:float, z:float }
lcn = pointDistance(vcur.x, vcur.z, vnext.x, vnext.z);
lnp = pointDistance(vnext.x, vnext.z, vprev.x, vprev.z);
lpc = pointDistance(vprev.x, vprev.z, vcur.x, vcur.z);
// Calculate and print the angle
Math.acos((lcn*lcn + lpc*lpc - lnp*lnp)/(2*lcn*lpc))*180/Math.PI
Is there something wrong in the code, did I forget to do something, or should it be done a completely different way?
HI there your math and calculations are perfect. Your running into the same problem most people do on calculators, which is orientation. What I would do is find out if the point lies to the left or right of the vector made by the first two points using this code, which I found from
Determine which side of a line a point lies
isLeft = function(ax,ay,bx,by,cx,cy){
return ((bx - ax)*(cy - ay) - (by - ay)*(cx - ax)) > 0;
}
Where ax and ay make up your first point bx by your second and cx cy your third.
if it is to the left just add 180 to your angle
I've got a working but not necessarily brief example of how this can work:
var point1x = 0, point1y = 0,
point2x = 10, point2y = 10,
point3x = 20, point3y = 10,
point4x = 10, point4y = 20;
var slope1 = Math.atan2(point2y-point1y,point2x-point1x)*180/Math.PI;
var slope2 = Math.atan2(point3y-point2y,point3x-point2x)*180/Math.PI;
var slope3 = Math.atan2(point4y-point3y,point4x-point3x)*180/Math.PI;
alert(slope1);
alert(slope2);
alert(slope3);
var Angle1 = slope1-slope2;
var Angle2 = slope2-slope3;
alert(180-Angle1);
alert(180-Angle2);
(see http://jsfiddle.net/ZUESt/1/)
To explain the multiple steps the slopeN variables are the slopes of the individual line segments. AngleN is the amount turned at each junction (ie point N+1). A positive angle is a right turn and a negative angle a left turn.
You can then subtract this angle from 180 to get the actual interior angle that you want.
It should be noted that this code can of course be compressed and that five lines are merely outputting variables to see what is going on. I'll let you worry about optimizing it for your own use with this being a proof of concept.
You need to check boundary conditions (apparently, if points are colinear) and apply the proper calculation to find the angle.
Also, a triangle can't have any (interior) angle greater than 180 degress. Sum of angle of triangle is 180 degrees.
I have a Player Entity that is governed by gravity and I have another entity at the bottom of the screen that moves around.
When my falling player entity hits the entity at the bottom I want it to bounce off of it.
Ideally I'd like to use the .bounciness property of the player entity.
You want your bottom entity to contain the following properties:
checkAgainst: ig.Entity.TYPE.A, // player entity type
collides: ig.Entity.COLLIDES.ACTIVE
Then you want your check() method of your bottomEntity to reverse the velocity of the player entity when it collides with it.
check: function(other) {
other.vel.y -= 100; // you could also use other.accel.y
}
Also if you want you can handle deflection angles with collisions as well (similar to the Arkanoid games):
If the player hits in the center, you want it to go straight up. If it hits on the right half, you want it to go right; if it hits on the left, you want it to go left.
So find where the player hits the bottom entity, and find its angle relative to the end of the entity.
var playerPos = player.pos.x - bottomEntity.pos.x;
var relativePos = ( bottomEntity.size.x - playerPos);
var angle = relativePos * ( Math.PI / bottomEntity.size.x ); // translate to radians - this finds the number of radians per bottom entity pixel
Once you got the angle, take the cos of it to grab the direction. Multiply the direction times the bottom entities velocity, and you've got the bottom entities new velocity.
var newVel = Math.cos( angle ) * bottomEntity.vel.x;
Then your check() method would look like this:
check: function(other) {
var playerPos = other.pos.x - bottomEntity.pos.x;
var relativePos = ( bottomEntity.size.x - playerPos);
var angle = relativePos * ( Math.PI / bottomEntity.size.x ); // translate to radians - this finds the number of radians per bottom entity pixel
other.vel.y -= newVel;
}
BACKGROUND:
The app allows users to upload a photo of themselves and then place a pair of glasses over their face to see what it looks like. For the most part, it is working fine. After the user selects the location of the 2 pupils, I auto zoom the image based on the ratio between the distance of the pupils and then already known distance between the center points of the glasses. All is working fine there, but now I need to automatically place the glasses image over the eyes.
I am using KinectJS, but the problem is not with regards to that library or javascript.. it is more of an algorithm requirement
WHAT I HAVE TO WORK WITH:
Distance between pupils (eyes)
Distance between pupils (glasses)
Glasses width
Glasses height
Zoom ratio
SOME CODE:
//.. code before here just zooms the image, etc..
//problem is here (this is wrong, but I need to know what is the right way to calculate this)
var newLeftEyeX = self.leftEyePosition.x * ratio;
var newLeftEyeY = self.leftEyePosition.y * ratio;
//create a blue dot for testing (remove later)
var newEyePosition = new Kinetic.Circle({
radius: 3,
fill: "blue",
stroke: "blue",
strokeWidth: 0,
x: newLeftEyeX,
y: newLeftEyeY
});
self.pointsLayer.add(newEyePosition);
var glassesWidth = glassesImage.getWidth();
var glassesHeight = glassesImage.getHeight();
// this code below works perfect, as I can see the glasses center over the blue dot created above
newGlassesPosition.x = newLeftEyeX - (glassesWidth / 4);
newGlassesPosition.y = newLeftEyeY - (glassesHeight / 2);
NEEDED
A math genius to give me the algorithm to determine where the new left eye position should be AFTER the image has been resized
UPDATE
After researching this for the past 6 hours or so, I think I need to do some sort of "translate transform", but the examples I see only allow setting this by x and y amounts.. whereas I will only know the scale of the underlying image. Here's the example I found (which cannot help me):
http://tutorials.jenkov.com/html5-canvas/transformation.html
and here is something which looks interesting, but it is for Silverlight:
Get element position after transform
Is there perhaps some way to do the same in Html5 and/or KinectJS? Or perhaps I am going down the wrong road here... any ideas people?
UPDATE 2
I tried this:
// if zoomFactor > 1, then picture got bigger, so...
if (zoomFactor > 1) {
// if x = 10 (for example) and if zoomFactor = 2, that means new x should be 5
// current x / zoomFactor => 10 / 2 = 5
newLeftEyeX = self.leftEyePosition.x / zoomFactor;
// same for y
newLeftEyeY = self.leftEyePosition.y / zoomFactor;
}
else {
// else picture got smaller, so...
// if x = 10 (for example) and if zoomFactor = 0.5, that means new x should be 20
// current x * (1 / zoomFactor) => 10 * (1 / 0.5) = 10 * 2 = 20
newLeftEyeX = self.leftEyePosition.x * (1 / zoomFactor);
// same for y
newLeftEyeY = self.leftEyePosition.y * (1 / zoomFactor);
}
that didn't work, so then I tried an implementation of Rody Oldenhuis' suggestion (thanks Rody):
var xFromCenter = self.leftEyePosition.x - self.xCenter;
var yFromCenter = self.leftEyePosition.y - self.yCenter;
var angle = Math.atan2(yFromCenter, xFromCenter);
var length = Math.hypotenuse(xFromCenter, yFromCenter);
var xNew = zoomFactor * length * Math.cos(angle);
var yNew = zoomFactor * length * Math.sin(angle);
newLeftEyeX = xNew + self.xCenter;
newLeftEyeY = yNew + self.yCenter;
However, that is still not working as expected. So, I am not sure what the issue is currently. If anyone has worked with KinectJS before and has an idea of what the issue may be, please let me know.
UPDATE 3
I checked Rody's calculations on paper and they seem fine, so there is obviously something else here messing things up.. I got the coordinates of the left pupil at zoom factors 1 and 2. With those coordinates, maybe someone can figure out what the issue is:
Zoom Factor 1: x = 239, y = 209
Zoom Factor 2: x = 201, y = 133
OK, since it's an algorithmic question, I'm going to keep this generic and only write pseudo code.
I f I understand you correctly, What you want is the following:
Transform all coordinates such that the origin of your coordinate system is at the zoom center (usually, central pixel)
Compute the angle a line drawn from this new origin to a point of interest makes with the positive x-axis. Compute also the length of this line.
The new x and y coordinates after zooming are defined by elongating this line, such that the new line is the zoom factor times the length of the original line.
Transform the newly found x and y coordinates back to a coordinate system that makes sense to the computer (e.g., top left pixel = 0,0)
Repeat for all points of interest.
In pseudo-code (with formulas):
x_center = image_width/2
y_center = image_height/2
x_from_zoom_center = x_from_topleft - x_center
y_from_zoom_center = y_from_topleft - y_center
angle = atan2(y_from_zoom_center, x_from_zoom_center)
length = hypot(x_from_zoom_center, y_from_zoom_center)
x_new = zoom_factor * length * cos(angle)
y_new = zoom_factor * length * sin(angle)
x_new_topleft = x_new + x_center
y_new_topleft = y_new + y_center
Note that this assumes the number of pixels used for length and width stays the same after zooming. Note also that some rounding should take place (keep everything double precision, and only round to int after all calculations)
In the code above, atan2 is the four-quadrant arctangent, available in most programming languages, and hypot is simply sqrt(x*x + y*y), but then computed more carefully (e.g., to avoid overflow etc.), also available in most programing languages.
Is this indeed what you were after?