Let (x1, y1, z1) and (x2, y2, z2) be two points in Euclidian 3-space on the surface of an axis-aligned side-length-2 cube centered at the origin.
How do I efficiently compute the distance (or squared distance) between the points over the surface of the cube?
Internally, I represent points as (offset1, offset2, faceNumber) but an (x,y,z) format (as referenced above) is readily available.
I prefer C or Python code but I'll happily accept pseudocode or anything, really.
EDIT:
Some facts:
Shortest paths are always monotone in x, y, and z.
If the points are on the same face then it's trivially just Euclidian distance.
If the points are not on the same face, the shortest path could involve either 2 or 3 faces.
EDIT: What I would do, is turn the 3d cube into a 2d plane. The caveat is that, if the point is on the opposite side of the cube, you need to place the final surface on all ends of the cross.
If a cube had sides like this that you could fold around so that 4 touched side 1.
5
1 2 3 4
6
You would have a 2d plane that ultimately looked like this
3
4/5 5 5/2
3 4 1 2 3
4/6 6 2/6
3
So, I modified this. Now each of the corner panels represents the connections that can take place between both panels. When you initially lay out this array, each point on panels 2, 4, 5, and 6, will map to three points. The solution is then the shortest line to any of the given points, that represent point 2, in the event you need to map it to multiple points.
Mapping points from the 3d cube, to their initial 1 - 6 pains on the 2d graph is really quite simple. The only difficulty left is figuring out how to map points from the 2 plane, onto the "2/6" plane and so forth. This is just a matter of thinking through each situation. Ex: 2 -> 2/6 is different from 5 -> 5/2. My intuition is that it's either going to be 90 degree or -90 degree rotation, before shifting the width of the cube in the appropriate direction.
For example, to properly handle the situation you laid out we would have a value at the bottom left corner of plane one, and the bottom right corner of plane 2. After the following: '
points in plane 2/6 = rot90(points in plane 2) - width of the cube.
We will have a point in the bottom left corner of plane 2/6. This will then appropriately be the shortest path, and appropriately this path crosses the face of plane 6.
Related
I'm writing a code to simulate a lap time on motorcycle, using GNU Octave.
The racetrack is represented by the mid line (as x-y point values) and width "B".
The points of the racetrack midline are not at the same distance, for example a straight section have just two points, a bend could have 5-10 points.
The racing line is a closed loop cubic bezier.
I would like to calculate the distance of that bezier from the midline, to check if the vehicle goes off road (if distance > B/2 I'm out of track). I'm not interested in where this happens, only if happens.
Right now to check if the code works, I've made this by calculating the distance of every point of the racing line to the midline as the height of a triangle, where the two base vertex are two points of the mid line and the top vertex is the point of the racing line.
It works but I'm looking for an alternative method because this one is very slow.
As alternative I tought to "straighten" the mid line by calculating angle of each section, and then straighten the racing line with the same "transformation" and check min and max Y value, that must be less than B/2. The problem with this approach is that racing line and mid line are not the same length, in some part of racetrack racing line could be shorter, in other could be longer, so the transformation will not be linear.
Another option could be to transform the racetrack into a matrix filled with "0" inside track, "1" outside track, and the racing line will be a matrix with the same MxN filled with "0" everywhere and "1" where there is he racing line. By sum these two matrices, if there is some "2" I'm out of track. Right now I don't find a method to made this.
I've found the answer of my problem, using the function "inpolygon".
So, I set the outside boundary of racetrack as polygon, and all points of racing line as points to check. The function tell me if some point is outside the polygon.
Then, I repeat the same, setting inside boundary as polygon. Now all racing line points must be outside the polygon.
This question already has answers here:
Formula for controlling the movement of a tank-like vehicle?
(10 answers)
Closed 7 years ago.
I'm trying to simulate a tank-like/skid-steered vehicle, i.e. both of the wheels (one on each side) have separate velocities, and steering is done by increasing or decreasing the velocity of one of the sides.
For example, If I set the velocity of the left wheel to 5, and the right wheel to 3, it will turn right. What I'd like to know is, given the velocities of the wheels Vl and Vr, and the distance between the wheels D, by how many degrees will the direction the vehicle is pointing in change in one tick?
I've tried looking at Formula for controlling the movement of a tank-like vehicle?, and the links on that question, but haven't come up with anything. All my best guesses have failed.
First: the really easy edge cases. if V_l and V_r are zero, don't move. If they're the same, don't turn.
Second, if only one of V_l and V_r are zero, the tank pivots around the stationary tread, and the moving tread traces out an arc of length V_big with a radius of curvature D. theta = Vbig/D, plus or minus some sign conventions based on your coordinates. (the tank base also translates some distance but the calculations for that are dependent on where the center of rotation of the tank is defined to be and your coordinate system, so that detail is left as an exercise for the reader.)
Third, symmetry concerns! Obviously tank treads turning is left/right symmetric. If the left tread is twice as fast as the right the tank should turn the same amount as if the right tread is twice as fast as the left, just in a different direction. Ditto for going backwards.
Fourth: Meat and potatoes! I'm assuming neither tank tread can slip whatsoever. The faster tread traces an arc of length V_fast on a circle of radius r+D marked out by an angle theta. If you recall your trig V_fast=(r+D)*theta. The slower wheel traces out an arc of length V_slow on a circle of radius r marked out by the same angle.(V_slow = theta*r) Divide one equation by the other, receive V_fast/V_slow = (r+D)/r. Apply algebra to provide r=D/((V_fast/V_slow)-1) Note that this explodes appropriately when V_slow is zero or when V_fast=V_slow, and you appropriately receive r=D when V_fast=2*V_slow Recall that theta=V_slow*r: theta=(V_fast-V_slow)/D
IN RADIANS, mind you That's a crucial detail.
NOTE: If you define 'turning right' as positive theta and turning left as negative theta, it all works out and theta=(V_l-V_r)/D, even for negative speeds. The tank won't turn around to face the direction of travel, it'll keep facing the correct way.
I am developing a game with Flixel as a base, and part of what I need is a way to check for collisions along a line (a line from point A to point B, specifically). Best way to explain this is I have a laser beam shooting from one ship to another object (or to a point in space if nothing is overlapping the line). I want the line to reach only until it hits an object. How can I determine mathematically / programatically where along a line the line is running into an object?
I could try measuring the length of the line and checking points for collision until one does, but that seems like way too much overhead to do every frame when I'm sure there is a mathematical way to determine it.
Edit: Before checking an object for collision with the line itself, I would first eliminate any objects not within the line's bounding box - defined by the x of the left-most point, the y of the top-most point, the x of the right-most point, and the y of the bottom-most point. This will limit line-collision checks to a few objects.
Edit again: My question seems to still not be fully clear, sorry. Some of the solutions would probably work, but I'm looking for a simple, preferably mathematical solution. And when I say "rectangle" I mean one whose sides are locked to the x and y axis, not a rotatable rectangle. So a line is not a rectangle of width 0 unless it's at 90 or -90 degrees (assuming 0 degrees points to the right of the screen).
Here's a visual representation of what I'm trying to find:
So, you have a line segment (A-B) and I gather that line segment is moving, and you want to know at what point the line segment will collide with another line segment (your ship, whatever).
So mathematically what you want is to check when two lines intersect (two lines will always intersect unless parallel) and then check if the point where they intersect is on your screen.
First you need to convert the line segments to line equations, something like this:
typedef struct {
GLfloat A;
GLfloat B;
GLfloat C;
} Line;
static inline Line LineMakeFromCoords(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) {
return (Line) {y2-y1, x1-x2, (y2-y1)*x1+(x1-x2)*y1};
}
static inline Line LineMakeFromSegment(Segment segment) {
return LineMakeFromCoords(segment.P1.x,segment.P1.y,segment.P2.x,segment.P2.y);
}
Then check if they intersect
static inline Point2D IntersectLines(Line line1, Line line2) {
GLfloat det = line1.A*line2.B - line2.A*line1.B;
if(det == 0){
//Lines are parallel
return (Point2D) {0.0, 0.0}; // FIXME should return nil
}else{
return (Point2D) {(line2.B*line1.C - line1.B*line2.C)/det, (line1.A*line2.C - line2.A*line1.C)/det};
}
}
Point2D will give you the intersect point, of course you have to test you line segment against all the ship's line segments, which can be a bit time consuming, that's were collision boxes, etc enter the picture.
The math is all in wikipedia, check there if you need more info.
Edit:
Add-on to follow up comment:
Same as before test your segment for collision against all four segments of the rectangle, you will get one of 3 cases:
No collision/collision point not on screen(remember the collision tests are against lines, not line segments, and lines will always intersect unless parallel), taunt Player for missing :-)
One collision, draw/do whatever you want the segment you're asking will be A-C (C collision point)
Two collisions, check the size of each resulting segment (A-C1) and (A-C2) using something like the code below and keep the one with the shortest size.
static inline float SegmentSizeFromPoints(Vertice3D P1, Vertice3D P2) {
return sqrtf(powf((P1.x - P2.x),2.0) + pow((P1.y - P2.y),2.0));
}
The tricky bit when dealing with collisions, is figuring out ways of minimizing the number of tests you have to make.
Find the formula for the line y = ((y2 - y1)/(x2 - x1)) * (x - x1) + y1
Find the bounding boxes for your sprites
For each sprite's bounding box:
For each corner of the current bounding box:
Enter the x value of the corner's coordinate into the line formula (from 1) and subtract the y value of the coordinate from the result
Record the sign from the calculation in 5
If all 4 signs are equal, then no collision has/will occur. If any sign is different, then a collision is possible, do further checks.
I'm not mathematically gifted but I think you could do something like this:
Measure the distance from the centre of the block and the laser beam.
Measure the distance between the centre of the block and the edge of the block at a given angle (there would be a formula for this I just don't know what it is).
Subtract the result of point 1 from the result of point 2.
Good thing about this is that if point 1 is larger than point 2 you know there hasn't been a collision yet.
Alternatively use box2d, and just use b2ContactPoint
You should look at the Separating Axis Theorem. This is generally used for polygons, but I think that you can make it work for a line and a polygon.
I found a link that explains it in a concise manner, here.
I have been tasked with trying to create a drawing tool that draws dotted lines as you drag the mouse across the stage. I can easily capture the points on MouseEvent.MOUSE_MOVE and store them in a vector and then draw the points as dots:
The problem is that I need to calculate evenly distributed points on an ever growing Vector of points so I can only draw the line between say every 5th point (say using modulus). I have been battling away with Bezier curve equations both Quadratic and Cubic but still can't quite figure out how to convert my Vector of points into an evenly distributed Vector of Points without sucking the life from the CPU.
Anyone help me? I see that George Profenza has come close to this one here on stack overflow...George?
hmm, I would try it like this: go over the points, calculate the distance between one and the next, keep track of the total distance, keep track of how many dots you placed already. Then, for each next point in the vector, see how many evenly distributed dots you would need to put between the new one and the last one and draw them on Bezier to make fancy, but straight should already be nice even.
example:
3 points in vector, total distance 22. distance per evenly distributed dot: 5. Hence, dots drawn on screen so far: 4. New point has distance 7 to last one, makes total distance 29. You need 5 points now (Math.floor(29/5)=5), you have 4, so you need to draw 1. Rest distance = 22 - 4*5 = 2. So then distance to do = 5-2 = 3. And 3 / distance between new and last point (9) = 0.333 -> so place this point on 1/3rd of the line between the new point in your vector and the last point. As in dot.x = seccondLastPoint.x + ((lastPoint.x - seccondLastPoint.x) * 0.333.
I'm pretty sure that will give you the desired result. Do you think you can build the code from this description?
Short question: Given a point P and a line segment L, how do I find the point (or points) on L that are exactly X distance from P, if it guaranteed that there is such a point?
The longer way to ask this question is with an image. Given two circles, one static and one dynamic, if you move the dynamic one towards the static one in a straight line, it's pretty easy to determine the point of contact (see 1, the green dot).
Now, if you move the dynamic circle towards the static circle at an angle, determining the point of contact is much more difficult, (see 2, the purple dot). That part I already have done. What I want to do is, after determining the point of contact, decrease the angle and determine the new point of contact (see 3, 4, the red dot).
In #4, you can see the angle is decreased by less than half, and the new point of contact is half-way between the straight-line point and the original point. In #7, you can see the angle is bisected, but the new point of contact moves much farther than half way back towards the straight-line point.
In my case, I always want to decrease the angle to 5/6ths its original value, but the original angle and distance between the circles are variable. The circles are all the same radius. The actual data I need after decreasing the angle is the vector between the new center of the dynamic circle and the static circle, that is, the blue line in 3, 4, 6, and 7, if that makes the calculation any easier.
So far, I know I have to move the dynamic circle along the line that the purple circle is a center of, towards the center of the static circle. Then the circle has to move directly back towards the original position of the dynamic circle. The hard part is knowing exactly how far back it has to move so that it's just touching the other circle.
To answer your short question, if you are on the Cartesian plane, then find the equation of the line L is sitting on (given the two endpoints of L, this is simple). Find the equation of the perpendicular to said line, which passes through P (this is done by taking the negative inverse of the slope, plugging in P's x and y values, and solving for the intercept). Then find the point where the two perpendicular lines intersect by using their equations as a single system of equations (with x's and y's equal). Then find the distance between the point of intersection and the point P, which is one leg of a triangle. Finally, with that distance and the distance X you are given, use Pythagorean theorem to find the distance of the other leg of the triangle. Now the point you are looking for is a point on L, and also on the line on which L sits. So using the distance you just obtained, the intersection point you had found before, and the equation of L's line, you can find the desired point's coordinates. There can only be a maximum of 2 such points, so all you have to test for is whether the coordinates of the points found are actually on L, or beyond L but still on its line. Sorry for the long answer and if you wanted a geometric explanation rather than an algebraic one.
Draw a circle with the same centre as the stationary circle and the radius of the sum of both radii. There are two intersections with the translation line of the moving circle's centre. The place of the moving circle's center at the time of contact is the closer of those two intersections.
Let the ends of your segment be A and B, and the center of your stationary circle be C. Let the radius of both circles be r. Let the center of the moving circle at the moment of collision be D. We have a triangle ACD, of which we know: the distance AC, because it is constant, the angle DAC, because that's what you are changing, and the distance CD, which is exactly 2r. Theoretically, two sides and angle should let you get all the rest of a triangle...