Efficient rotating tray with 4 slots - algorithm

I have a circle divided into fourths. I need an algorithm that can rotate the circle from one position to another in the most efficient way.
The "trays" are named 1 to 4.
I now use the algoritm:
int degrees = (currentPos - newPos) * 90;
using the algorithm i get how many degrees i need to rotate the circle to get to the new position. However if i am in position 4 and need to go to 1, the result will be 4 - 1 * 90 = 270. In this case the most efficient would be to rotate -90 instead of 270. (the same goes for moving from 1 to 4).
Anyone got a good idea of how to do this? I can of course use an if statement:
if(degrees >= -180 && degrees <= 180)
sortingTrayMotor.rotate(degrees);
else if(degrees == -270)
sortingTrayMotor.rotate(90);
else
sortingTrayMotor.rotate(-90);
I guess there is a better way to do it though with some mod operation.

Exactly what you're doing, only if the result is > 180 degrees, subtract 360 degrees.

Related

Find all pixels on a circle

I need to find pixels laying on a circle centered on point (0,0). Right now I do this by using formulas:
x = round(r * cos(angle))
y = round(r * sin(angle))
and my angle takes values from 0 to 2 Pi.
However this is not producing accurate results. For example, it gives point (1,1) for diameter 1 and also for diameter 2. How to avoid it?

Partition an arc into portions as per the Quadrant in which that portion lies

The problem seems very simple but I am not able to find an elegant solution for it.
I have an arc defined by
startAngle ( -360 <= startAngle <= 360 ),
sweepAngle ( -360 <= sweepAngle <= 360 )
and a radius (not important here).
I want to divide this arc into pairs of (startAngle1, sweepAngle1), ... such that there is a different pair for each of the four quadrants.
Eg. If startAngle = 45, sweepAngle = 90, then there shall be two pairs (45,45) and (90,45).
A brute-force way is to check for all 4^2 possibilities (each of startAngle and corresponding endAngle (calculated by sweepAngle) can be in any of the 4 quadrants).
But I think an elegant simpler solution should be there. I just can't seem to find it.
Thanks.
EDIT:
One algorithm I just thought of is:
1. Starting from startAngle, I iterate towards the sweepAngle and keep checking whether I encounter any quadrant boundary (mod(theta) = 0, 90, 180, 270, 360).
2. Update to the list of arcs accordingly.
Anything better?
I would start with 90-startAngle%90, the modulo operator gives you the part which is startAngle in it's current quadrant. 90 minus that value is the part that the startAngle has to go in this quadrant. So, that is your first sweep angle. Now you can add always 90 to your next sweep angle. You do this until your calculated current sweepAngle is larger than your input sweepAngle. Then you know that you are in the last quadrant. In pseudo-code, out prints a new pair of angles:
currentPosition=startAngle
currentSweep = 90-startAngle%90
totalAngle=0
while (currentSweep < sweepAngle)
out (currentPosition, currentSweep)
currentPosition += currentSweep
totalAngle += currentSweep
currentSweep += 90;
out (currentPosition, sweepAngle-totalAngle)
Probably you have to look into the corner cases more closely, what happens when startAngle is exactly 90, e.g. But basically this should be the algorithm with a reasonable running time (and elegance, imo).

Algorithm or formula for the shortest direction of travel between two degrees on a circle?

Given two degrees on a 360 degree circle. Lets call them Source and Destination.
For example Source could be 120 degrees and Destination could be 30 degrees.
Is there an elegant solution to the question of which direction of travel from Source to Destination is shorter, i.e. is it shorter clockwise (increasing the degrees) or anti clockwise (decreasing the degrees)?
For example with the degrees given above then the solution would be: Go anti clockwise. On the other hand with Source as 350 and Destination as 20 then the solution would be: Go clockwise.
if ((dest - source + 360) % 360 < 180)
// clockwise
else
// anti-clockwise
BTW, your convention that clockwise == "increasing the degrees" is the opposite of the Trigonometry 101 convention that the rest of the world is using, and is therefore confusing (was to me, anyhow).
Compute the difference, then normalise it to +/-180. Positive numbers indicate travel in the direction of increasing angle (clockwise in your case).
This is the function I use to output the shortest distance between two degrees with negative and positive numbers. It also works on degress outside the 0 - 360 ranges.
function shortestDistDegrees(start, stop) {
const modDiff = (stop - start) % 360;
let shortestDistance = 180 - Math.abs(Math.abs(modDiff) - 180);
return (modDiff + 360) % 360 < 180 ? shortestDistance *= 1 : shortestDistance *= -1;
}
shortestDistDegrees(50, -20) // Output: -70
shortestDistDegrees(-30, -370) // Output: 20
shortestDistDegrees(160, -710) // Output: -150
This is the algorithm I use for my in-game cameras:
rotSpeed = 0.25; //arbitrary speed of rotation
angleDiff = 180-abs(abs(source-dest)-180); //find difference and wrap
angleDiffPlus = 180-abs(abs((source+rotSpeed)-dest)-180); //calculate effect of adding
angleDiffMinus = 180-abs(abs((source-rotSpeed)-dest)-180); // ... subtracting
if(angleDiffPlus < angleDiff){ //if adding to ∠source reduces difference
source += rotSpeed; //add to ∠source
}else if(angleDiffMinus < angleDiff){ //if SUBTRACTING from ∠source reduces difference
source -= rotSpeed; //subtract from ∠source
}else{ //if difference smaller than rotation speed
source = dest; //set ∠source to ∠destination
}
By "wrapping" the angle we can calculate difference. We can then test the current difference versus predictions to see which direction would actually reduce the difference.
NPE's answer is good, but adding 360 before taking the modulo of 360 is a waste of time depending on the language. Therefore
if ((dest - source) % 360 < 180)
// clockwise
else
// anti-clockwise
Note that the Mod function has to return absolute values.
For example
dest = 5, source = 10
wolfram alpha
-5 modulo 360 = 355
Beckhoff's implementation of Structured Text
LMOD(-5, 360) = -5
LMOD(-5+360, 360) = 355
MODABS(-5, 360) = 355
The general answer here is: "Modulo arithmetics". You might want to read up on that, it's worth it.

How does a perlin noise field work?

I'm looking at this example in particular:
http://www.airtightinteractive.com/demos/processing_js/noisefield08.html
And here's the code for it:
http://www.airtightinteractive.com/demos/processing_js/noisefield08.pjs
I guess I need explaining for what these lines do in the particle class:
d=(noise(id,x/mouseY,y/mouseY)-0.5)*mouseX;
x+=cos(radians(d))*s;
y+=sin(radians(d))*s;
I understand that noise calculates a value based on the coordinates given, but I don't get the logic in dividing the particles' x pos by the mouseY, or the y pos by the mouseY. I also don't understand what 'id', which seems to be a counter stands for, or what the next two lines accomplish.
Thanks
Move mouse to change particle motion.
d seems to be the direction of motion. By putting mouseY and mouseX into the calculation of d it allows the underlying field to depend on the mouse position. Without a better understanding of the function itself I can't tell you exactly what affect mouseY and mouseX have on the field.
By running cos(radians(d)) and sin(radians(d)) the code turns an angle (d) into a unit vector. For example, if d was 1 radian then cos(radians(d)) would be -1 and sin(radians(d)) would be 0 so it turns the angle 1 radians into the unit vector (-1,0).
So it appears that there is some underlying motion field which determines the direction the particles move. The motion field is represented by the noise function and takes in the current position of the particle, the particle id (perhaps to give each particle independent motion or perhaps to remember a history of the particle's motion and base the future motion on that history) and the current position of the mouse.
The actual distance the particle moves is s which is determined randomly to be between 2 and 7 pixels.
By running cos(radians(d)) and sin(radians(d)) the code turns an angle (d) into a unit vector. For example, if d was 1 radian then cos(radians(d)) would be -1 and sin(radians(d)) would be 0 so it turns the angle 1 radians into the unit vector (-1,0).
Slight correction: that is a rotation of pi radians (180 degrees), not 1 radian (around 57 degrees).

Interpolating angles

I am trying to do a rotation of a game object by setting a start and end point and X frames to do the movement. Then interpolate start and end angle to get it done.
It works well, but I am trying to do the shortest possible route as an option (as opposed to "do the longest route").
In most cases it works, but if the rotation goes above 360 or below 0, I don't know how to detect it and alter the numbers. (for example if I want to take the shortest route from 270 to 90, the shortest route goes above 360/0, so is never used, so 270 should become -45 to interpolate to 90).
I am terrible at explaining and I am not native English to round it up, so I will use pseudocode of what I have.
thing.start_angle = 180
thing.end_angle = 90
thing.angle = interpolate(thing.start_angle, thing.end_angle, position)
I like this way (for the detailed time control over a "if angle > max_angle then angle - 1"), but I can't find a "rule" for how to detect if the angle will rotate...
How can I find if the rotation will go below 0 or above 360, to act accordingly?
The angle will wrap if
thing.end_angle - thing.start_angle >= 180 or < -180
(assuming an angle range of 0 to 379).

Resources