I'm building an Arduino-based control system for a model railway turntable and I need to be able to rotate it clockwise or counterclockwise at will. I have 21 positions on the turntable, which I currently have numbered 0-20. I need to figure out how many "clicks" counterclockwise it will take to get to a given track number. How on earth can I go about finding this?
If there's a math-y way I can do it, that would be fantastic. I don't want to have an endless series of IF statements if I can avoid it.
Never mind. I found a very simple, elegant way.
Let's take my turntable for example. 21 positions, numbered 0-20.
If we are at track 0, and we have 20 tracks total, and we want to go to track 16 counterclockwise, we could do:
moves = 0 + ((20 + 1) - 16)
This yields 5, meaning if we move the turntable counterclockwise 5 tracks, we end up at track 16.
Simple, elegant, and extends to fit an infinite number of possible positions.
Related
I'm not sure if something like this has been asked but I've spent days trying to figure this out to no avail.
I've been working on a project that has a straight tube and a sleeve placed some length down the tube, this part of the problem isn't causing any issues but the orientation of the placed sleeve is. When the sleeve is placed it is given a location that intersects another object giving it all the information it needs to be placed, but I need that sleeve to orient itself with the tube, pretty much just along the roll axis, but I would like to hammer out how yaw and pitch would be done similarly.
The tube has transform data connected to it. It has an origin for the center point of the tube, and 3 xyz points standing for each basis axis. in example for one of the tubes tested:
origin:{(119.814557964, -37.330669765, 8.400185257)},
BasisX: {(1.000000000, 0.000000000, 0.000000000)},
BasisY: {(0.000000000, 0.939692621, 0.342020143)},
BasisZ: {(0.000000000, -0.342020143, 0.939692621)}.
In some of the solution parts I've come across I found some ways this information is used. And I've had some success with this way of doing it:
(note: I realize this code has a lot of pointless variable use, I didn't want to adjust it and confuse myself more)
upDownAxis = givenSleeveObject.passedOnTransform.BasisZ;
leftRightAxis = givenSleeveObject.passedOnTransform.BasisX;
tempOfVector = givenSleeveObject.passedOnTransform.OfVector(upDownAxis);//this ofvector is applying the transform to the vector
rotationAngle = upDownAxis.AngleOnPlaneTo(tempOfVector, leftRightAxis);
This was able to give me the angle rotation of this particular tube which was 20 degrees.
The problem is that this doesn't really work along the y axis the same, and completely wrong along the z axis. Likely due to after rotating to z axis the axis for each direction changes to one of the others at that angle. Also if it is of any help, the direction of the tube basically follows the basisX. If z is the only one with a 1, it is heading upward.
So now my issue is, how can I find the roll of this tube no matter it's orientation? Also rotation direction might matter in the long run. Since this object's transforms are all connected to itself, there must be a way to know how much of a roll has been done to it even at an extreme of 45 in every axis, right?
I have a complicated problem and it involves an understanding of Maths I'm not confident with.
Some slight context may help. I'm building a 3D train simulator for children and it will run in the browser using WebGL. I'm trying to create a network of points to place the track assets (see image) and provide reference for the train to move along.
To help explain my problem I have created a visual representation as I am a designer who can script and not really a programmer or a mathematician:
Basically, I have 3 shapes (Figs. A, B & C) and although they have width, can be represented as a straight line for A and curves (B & C). Curves B & C are derived (bend modified) from A so are all the same length (l) which is 112. The curves (B & C) each have a radius (r) of 285.5 and the (a) angle they were bent at was 22.5°.
Each shape (A, B & C) has a registration point (start point) illustrated by the centre of the green boxes attached to each of them.
What I am trying to do is create a network of "track" starting at 0, 0 (using standard Cartesian coordinates).
My problem is where to place the next element after a curve. If it were straight track then there is no problem as I can use the length as a constant offset along the y axis but that would be boring so I need to add curves.
Fig. D. demonstrates an example of a possible track layout but please understand that I am not looking for a static answer (based on where everything is positioned in the image), I need a formula that can be applied no matter how I configure the track.
Using Fig. D. I tried to work out where to place the second curved element after the first one. I used the formula for plotting a point of the circumference of a circle given its centre coordinates and radius (Fig. E.).
I had point 1 as that was simply a case of setting the length (y position) of the straight line. I could easily work out the centre of the circle because that's just the offset y position, the offset of the radius (r) (x position) and the angle (a) which is always 22.5° (which, incidentally, was converted to Radians as per formula requirements).
After passing the values through the formula I didn't get the correct result because the formula assumed I was working anti-clockwise starting at 3 o'clock so I had to deduct 180 from (a) and convert that to Radians to get the expected result.
That did work and if I wanted to create a 180° track curve I could use the same centre point and simply deducted 22.5° from the angle each time. Great. But I want a more dynamic track layout like in Figs. D & E.
So, how would I go about working point 5 in Fig. E. because that represents the centre point for that curve segment? I simply have no idea.
Also, as a bonus question, is this the correct way to be doing this or am I over-complicating things?
This problem is the only issue stopping me from building my game and, as you can appreciate, it is a bit of a biggie so I thank anyone for their contribution in advance.
As you build up the track, the position of the next piece of track to be placed needs to be relative to location and direction of the current end of the track.
I would store an (x,y) position and an angle a to indicate the current point (with x,y starting at 0, and a starting at pi/2 radians, which corresponds to straight up in the "anticlockwise from 3-o'clock" system).
Then construct
fx = cos(a);
fy = sin(a);
lx = -sin(a);
ly = cos(a);
which correspond to the x and y components of 'forward' and 'left' vectors relative to the direction we are currently facing. If we wanted to move our position one unit forward, we would increment (x,y) by (fx, fy).
In your case, the rule for placing a straight section of track is then:
x=x+112*fx
y=y+112*fy
The rule for placing a curve is slightly more complex. For a curve turning right, we need to move forward 112*sin(22.5°), then side-step right 112*(1-cos(22.5°), then turn clockwise by 22.5°. In code,
x=x+285.206*sin(22.5*pi/180)*fx // Move forward
y=y+285.206*sin(22.5*pi/180)*fy
x=x+285.206*(1-cos(22.5*pi/180))*(-lx) // Side-step right
y=y+285.206*(1-cos(22.5*pi/180))*(-ly)
a=a-22.5*pi/180 // Turn to face new direction
Turning left is just like turning right, but with a negative angle.
To place the subsequent pieces, just run this procedure again, calculating fx,fy, lx and ly with the now-updated value of a, and then incrementing x and y depending on what type of track piece is next.
There is one other point that you might consider; in my experience, building tracks which form closed loops with these sort of pieces usually works if you stick to making 90° turns or rather symmetric layouts. However, it's quite easy to make tracks which don't quite join up, and it's not obvious to see how they should be modified to allow them to join. Something to bear in mind perhaps if your program allows children to design their own layouts.
Point 5 is equidistant from 3 as 2, but in the opposite direction.
So I have a ship, that has thrusters at the bottom and that can only use these to move forward. It can also rotate itself around its center. Its thrusters gives it acceleration, so it doesn't move at a constant velocity. What I want to do is to tell it "move to point B".
I have come up with a solution but it doesn't work very well and it doesn't rotate smoothly, it moves jerkily and it doesn't end up exactly where it should be, so I have to have a big margin of error.
Is this a normal problem, and if so is there a "standard" way of doing it? Is this an easy problem? I want to make it look like the ship is steering itself to that point, using the constraints (thrusters, rotation) the player has. This excludes just lerping it from point A to B. Or does it?
I'd love some help in solving this problem. Positions are stored in vectors, and it's a 2D problem. Just for reference I'm including my solution, which basically is accelerating the ship until and rotating it to point to the point. I think my implementation of this idea is the problem:
Vector diff = vector_sub(to_point, pos);
float angle = vector_getangle(diff);
float current_angle = vector_getangle(dir);
float angle_diff = rightrange(angle) - rightrange(current_angle);
float len = vector_getlength(diff);
// "Margin of error"
float margin = 15.0;
// Adjust direction, only if we're not stopping the next thing we do (len <= margin)
if ( len > margin && fabs(angle_diff) > 2.0 )
{
dir = vector_setangle(dir, current_angle + (angle_diff)*delta*(MY_PI) - MY_PI/2);
}
else if ( len > margin )
{
dir = vector_normalize(diff);
}
// accelerate ship (if needed)
acc.x = acc.y = speed;
acc = vector_setangle(acc, vector_getangle(dir));
if ( len <= margin )
{
// Player is within margin of error
}
If you are not looking for a very general solution that works online, then there is a simple solution. What I mean by online is continuously re-calculating the actions along the complete trajectory.
Assuming the ship is at rest at start, simply rotate it towards your target point (while still at rest). Now, your ship can reach the target by accelerating for t seconds, rotating back while in motion (for 0.5 seconds as per your constraint), and decelerating for another t seconds. If the distance between current point and destination is d, then the equation you need to solve is:
d = 0.5*a*t^2 + 0.5*a*t + 0.5*a*t^2
The first term is distance traveled while accelerating. The second term is distance traveled while rotating (v*t_rot, v=a*t, t_rot=0.5). The final term is the distance traveled while decelerating. Solve the above for t, and you have your trajectory.
If the ship is moving at start, I would first stop it (just rotate in opposite direction of its speed vector, and decelerate until at rest). Now we know how to reach destination.
The problem with offline trajectory calculation is that it is not very accurate. There is a good chance that you will end up in the vicinity of the target, but not exactly on top of it.
Let's make the problem a little more interesting: the ship cannot rotate without acceleration. Let's call this acceleration vector a_r, a vector that is at a certain angle against the ship's direction (somewhat like having a thruster at an angle at the back). Your task now is to rotate the ship and accelerate in such a direction that the speed component perpendicular to the vector connecting the current position to the target is canceled out. Instead of trying to calculate the vectors offline, I would go with an online approach with this.
The easiest thing to do would be to add the following algorithm calculated at every time interval:
Calculate the vector pointing from ship to destination.
Split your current speed vector into two components: towards the destination, and perpendicular to it.
If perpendicular speed is zero, skip 4
Start rotating towards the negative of the perpendicular vector's direction. If already looking away from it (not exact opposite, but just looking away), also fire main thruster.
This will oscillate a bit, I suspect it will also stabilize after a while. I must admit, I don't know how I would make it stop at destination.
And the final approach is to model the ship's dynamics, and try to linearize it. It will be a non-linear system, so the second step will be necessary. Then convert the model to a discrete time system. And finally apply a control rule to make it reach target point. For this, you can change your state-space from position and speed to error in position and (maybe) error in speed, and finally add a regulation control (a control loop that takes the current state, and generates an input such that the state variables will approach zero).
This last one is fairly difficult in the maths compartment, and you'd probably need to study control engineering a bit to do it. However, you'll get much better results than the above simplistic algorithm - which admittedly might not even work. In addition, you can now apply various optimization rules to it: minimize time to reach target, minimize fuel consumption, minimize distance traveled, etc.
I'm having trouble wrapping my mind around how to calculate the normal for a moving circle in a 2d space. I've gotten as far as that I'm suppose to calculate the Normal of the Velocity(Directional Speed) of the object, but that's where my college algebra mind over-heats, any I'm working with to 2d Circles that I have the centerpoint, radius, velocity, and position.
Ultimately I'm wanting to use the Vector2.Reflect Method to get a bit more realistic physics out of this exercise.
thanks ahead of time.
EDIT: Added some code trying out suggestion(with no avail), probably misunderstanding the suggestion. Here I'm using a basketball and a baseball, hence base and basket. I also have Position, and Velocity which is being added to position to create the movement.
if ((Vector2.Distance(baseMid, basketMid)) < baseRadius + basketRadius)
{
Vector2 baseNorm = basketMid - baseMid;
baseNorm.Normalize();
Vector2 basketNorm = baseMid - basketMid;
basketNorm.Normalize();
baseVelocity = Vector2.Reflect(baseVelocity, baseNorm);
basketVelocity = Vector2.Reflect(basketVelocity, basketNorm);
}
basePos.Y += baseVelocity.Y;
basePos.X += baseVelocity.X;
basketPos.Y += basketVelocity.Y;
basketPos.X += basketVelocity.X;
basketMid = new Vector2((basketballTex.Width / 2 + basketPos.X), (basketballTex.Height / 2 + basketPos.Y));
baseMid = new Vector2((baseballTex.Width / 2 + basePos.X), (baseballTex.Height / 2 + basePos.Y));
First the reflection. If I'm reading your code right, the second argument to Vector2.Reflect is a normal to a surface. A level floor has a normal of (0,1), and a ball with velocity (4,-3) hits it and flies away with velocity (4,3). Is that right? If that's not right then we'll have to change the body of the if statement. (Note that you can save some cycles by setting basketNorm = -baseNorm.)
Now the physics. As written, when the two balls collide, each bounces off as if it had hit a glass wall tangent to both spheres, and that's not realistic. Imagine playing pool: a fast red ball hits a stationary blue ball dead center. Does the red ball rebound and leave the blue ball where it was? No, the blue ball gets knocked away and the red ball loses most of its speed (all, in the perfect case). How about a cannonball and a golf ball, both moving at the same speed but in opposite directions, colliding head-on. Will they both bounce equally? No, the cannonball will continue, barely noticing the impact, but the golf ball will reverse direction and fly away faster than it came.
To understand these collisions you have to understand momentum (and if you want collisions that aren't perfectly elastic, like when beanbags collide, you also have to understand energy). A basic physics textbook will cover this in an early chapter. If you just want to be able to simulate these things, use the center-of-mass frame:
Vector2 CMVelocity = (basket.Mass*basket.Velocity + base.Mass*base.Velocity)/(basket.Mass + base.Mass);
baseVelocity -= CMVelocity;
baseVelocity = Vector2.Reflect(baseVelocity, baseNorm);
baseVelocity += CMVelocity;
basketVelocity -= CMVelocity;
basketVelocity = Vector2.Reflect(basketVelocity, basketNorm);
basketVelocity += CMVelocity;
The normal of a circle at a given point on its edge is going to be the direction from its center to that point. Assuming that you're working with collisions of circles here, then one easy "shorthand" way to work this out would be that at the time of collision (when the circles are touching), the following will hold true:
Let A be the center of one circle and B the center of the other. The normal for circle A will be normalize(B-A) and the normal for circle B will be normalize(A-B). This is true because the point where they touch will always be colinear with the centers of the two circles.
Caveat: I'm not going to assume that this is completely correct. Physics are not my specialty.
Movement has no effect on a normal. Typically, a normal is just a normalized (length 1) vector indicating a direction, typically the direction that a poly faces on a 3d object.
What I think you want to do is find the collision normal between two circles, yes? If so, one of the cool properties of spheres is that if you find the distance between the centers of them, you can normalize that to get the normal of the sphere.
What seems correct for 2d physics is that you take the velocity * mass (energy) of a sphere, and multiply that by the normalized vector to the other sphere. Add the result to the destination sphere's energy, subtract it from the original sphere's energy, and divide each, individually, by mass to get the resulting velocity. If the other sphere is moving, do the same in reverse. You can probably simplify the math down from there, of course, but it's late and I don't feel like doing it :)
If both spheres are moving, repeat the process for the other sphere (though you could probably simplify that equation to get some more efficient math).
This is just back-of-the-napkin math, but it seems to give the correct results. And, hey, I once derived Euler angles on my own, so sometimes my back-of-the-napkin math actually works out.
This also assumes perfectly elastic collisions.
If I'm incorrect, I'd be happy to find out where :)
I'm working with bots in Call Of Duty and their vision is calculated with a bulletTracePassed function, there's no other way to calculate that, since there's not really bot functions, so this will return true if a bullet can pass from point A to point B returning true/false, which works great MOST of the times, but causes a chaos in those 2 cases mainly:
When the mapper didn't put any kind iDFLAGS_PENETRATION on the walls (means the wall have no resistance to bullets, so there's not contact/hit, and the bullets pass through like was nothing.
When we have Trees, Plants, etc in the middle
In those 2 cases the bots will see the other players when shoudn't, and in jungle like maps it's a complete hell to play.
Ok, the right way to do these fixes are just fix the maps, adding the right penetration in those walls and dense vegetation, but is not possible do that because are SEVERAL maps by SEVERAL modders, and even official releases with the same problems, and of course, we don't have their sources to apply these fixes.
So the only way to do that is via script, and I'm thinking in doing something like this:
I have the position of the eye of the attacker bot in 3D like (x,y,z) for exemple (1000,500,22), and also the position which hit the other players like (2000,1200,60), which is returned by the function bulletTracePassed.
But for exemple, in a wall I have part of it without any collision, so the bots can see through them, so would like to set the middle of the wall with position (1600,800,50) and angles (10,-40,-90) and a square radius of the size to of the square/plane, for exemple, 500.
So I want to test if the ray passed through this square/plane, then returning false/true to let me use it to make the bots decide to aim to shoot or not this player behind the "bad" wall.
Looking around I found the function rayPlaneIntersection, which by the name seams what I want, but didn't get right yet how it works in my solution, since I can't see any kind of angles of even a square radius to determine their size... or are doing to a single point only?
rayPlaneIntersectionrayPlaneIntersection(ray0: vec3, ray1: vec3, origin?: vec3 | number[], normal?: vec3 | number[]): vec3 | undefined
Defined in raymath.ts:130
Computes the intersection point of a given ray and a given plane (rooted at [ 0, 0, 0 ]). t = -(dot(plane.xyz, origin) + plane.w) / dot(plane.xyz, ray); The ray intersects when (t > 0.0) && (t < tm) is true.
Parameters
ray0: vec3 Start point of a ray.
ray1: vec3Far point of a ray, used to derive the ray direction.
Default value origin: vec3 | number[] = [0.0, 0.0, 0.0]
Point on a plane with origin [ 0, 0, 0 ].
Default value normal: vec3 | number[] = [0.0, 1.0, 0.0]
Normal of the plane with origin [ 0, 0, 0 ].
Returns vec3 | undefined
If ray intersects, the intersection point on the plane if the plane was hit.
Anyone could point an exemple of this use in my exemple? Or any other function that might give me the same (or even similar) result to let me at least start to fix this problem?
I know it's not an easy task, that's why I'm posting here, after many lost hours trying to do it alone without success yet.
thank you very much.