Restricting a point to an arc on a circle's circumference - math

This question is a bit specific. Assume for simplicity that I have a unit circle, i.e. a circle centered on the origin (0,0) with radius 1. On this circle I have three points: A, B, and C. Assume that B and C are fixed, and that A can be moved along the circle's circumference.
Question: What conditions can I check efficiently to ensure that A is not moved outside the arc between B and C originally containing it?
As a point of clarification: I do not just wish to detect whether the point is on this arc or not (i.e., get a boolean), but to have a quantifiable measure (for example, of distance) so I can prevent it from being moved outside. You can imagine my setup like this, restricting point A to the red arc:
Here are some ideas I have pondered so far, but none were successful:
Limit the angle alpha of A = [cos(alpha),sin(alpha)] to the origin between the angles beta and gamma of B=[cos(beta),sin(beta)] and C=[cos(gamma),sin(gamma)], where alpha, beta, and gamma are angles in radians. Unfortunately, this naive case only works in scenario (a) above. If the arc to which A is restricted crosses the (in my case, western) discontinuity from +pi/-pi, a naive upper and lower bound won't do.
Calculate the length of the arcs between A-to-B and A-to-C, then ensure that as A is moved this sum does not change. Unfortunately, I have only found this solution to calculate the arcs between two points, and it always calculates the shorter arc. In scenario (c), however, the correct arc A-to-B is the larger one.

Given any two points on a circle, in your case B and C, there are of course two possible arcs. We use A to select between the two options. You say you want to prevent a point, say D, from moving outside this arc. I'm interpreting this to mean that we want a function which, if D lies on the arc defined by BC and A, returns D, otherwise it returns B or C, depending on which is nearer to D.
We can define the following function to implement this scheme:
def contstrainPoint(A, B, C, D)
M = midpoint(B, C)
If dot(MA, MD) >= 0
return D
else if(dot(MB, MD) >= 0
return B
else
return C
Where M is the midpoint of the chord BC and dot is the dot product function.

Take the cross product (A-B)x(A-C). This will have one non-zero component, normal to the plane. That component will vary smoothly, positive when A is on one arc, negative when it is on the other, and zero when it crosses B or C.

Related

Having 3 vectors, how to check that a straight line can be drawn through them

I get the positions of 5 enemies in the game in vectors. Depending on the distance I choose, the number of enemies can vary from 0 to 5. I need to know their vectors each time to check whether it is possible to draw a straight line through a certain number of heroes (vectors).
After that, my hero will have to use his ability called wall. It consists of 2 start and end vectors. Thus, check whether my hero can put a wall on the enemies in the line to catch them
Let's say there are 3 enemy heroes whose positions I can get. I need to find out if I can pass through them directly, in order to use the ability on them.
Here's what using the ability looks like in the game
Here is getting the vector of one of the heroes
The ability itself can be twisted at a certain point. But anyway, it is necessary that the wall would touch several heroes
Wherever I move the mouse, I can put it in the desired position. But unfortunately it takes a lot of time, so I would like to automate
The coordinates of the wall itself, or rather its two edges, I can also get, but only after the ability has been used
If one prefers geometry to linear algebra...
Then One can compute the dot product of (unit-vector1. Unit-Vector2). That is equal to the SIN of the angle between them.
So if unit vector is the shooter position to target1, unit vector2 is the shooter to target2, etc... then when DOTPRODUCT(Vector1,vector2) = 1 and DOTPRODUCT(Vector1,vector3) = 1, then the three points are in syzygy.
And repeat from shooter to as many targets as you have to determine whether some or all of the points are in syzygy.
From your statement that there is a start and an endpoint I take that you select two enemys and want to trap anything in between.
So you're actually not looking for a straight line that can be drawn through your enemy positions but if they are withn a rectangle. It would be very unlikely and for more points nearly impossible that they are all collinear anyway.
So it becomes quite trivial. You draw a line through start and end enemy. Then you check the remaining enemies distance to that line vs the width of your AoE. Maye you want to also handle some body width in that calculation.
https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
You can describe all points belonging to line (x0, y0) + (dx, dy)t = (x1, y1). Chose any two points and t as 1 and you will get (dx, dy) for line connecting two dots. Now you will need to find distance between this line and (x2, y2). it is distance between (x2, y2) and (xd, yd), where on one hand (xd, yd) = (x0, y0) + t1(dx, dy) and on other hand (xd, yd) = (x2, y2) + t2*(-dy, dx). Solving this two equations you will find t1, t2, (xd, yd) and distance between (x2, y2) and (xd, yd), which is distance between (x2, y2) and line, connecting (x0, y0) and (x1, y1).
Knowing this, you select dots with min_x and max_x and calculate ditance between line, connecting said dots and rest of the dots. If distance is lesser then some threshold of your choice, then you can assume that you can have line passing through all dots.
Any line in the plane can be described by an equation a*x + b*y + c = 0 with (a, b) ≠ (0, 0). Note that if you have an equation of this form, then multiplying each coefficient a, b, c with the same number yields an equation describing the same line. That's the reason (a, b, c) is called a homogeneous coordinate vector for that line.
How do you find a, b, c? One simple approach would be treating this as three linear equations in three unknowns. You plug in the x and y coordinates for all your three points, and get tree equations for a thorough c. However, there is a catch. Since the right hand side of each equation is zero, a = b = c = 0 is always a solution. In those cases where there is only one solution, that will be it. So in order for there to be a line, you need more than one solution. The mathematical tool to determine whether a set of equations had more than one solution is the determinant. It is zero if the system has no single unique solution.
Long story short: three points are collinear (on a line) if
⎛x1 y1 1⎞
det ⎜x2 y2 1⎟ = 0
⎝x3 y3 1⎠
The homogeneous coordinate vector describing the line world correspond to the kernel of that matrix.
Of course, if your input coordinates are floating point numbers, exact zero is unlikely. Presumably that wall does allow for some error in some way, and you'd need to tell us about that in order to get an answer that models this aspect correctly. In the mean time, know that the absolute value of the determinant above is proportional to the area of the triangle created by these three points. So if your were to pick a constant threshold value, the farther your enemies are apart along the direction of the wall, the less they could deviate from the straight line without violating that threshold.

Find all points with integer coordinates inside tetrahedron

I am trying to find all the points with integer coordinates that lie inside of a tetrahedron (I want to somehow be able to loop through them). I know the coordinates of the four points (A, B, C, D) that define the tetrahedron.
What I'm currently doing is I find the bounding box of the tetrahedron (minimum and maximum x, y, z coordinates of A, B, C, D) and then do a loop through all of the points inside the bounding box. For every such point, I calculate the barycentric coordinates (using the equations from Wikipedia) and check if the point is inside the tetrahedron (if any of the barycentric coordinates is negative or bigger than 1, the point isn't inside).
Is there a better way to do this? Currently there is around 1/6 chance that the point I am testing (from the bounding box) really lies inside the tetrahedron, so I think I'm doing too many unnecessary computations.
I am working with a list of tetrahedra that I generated by triangulating a bigger volume (I am expanding the volume and want to interpolate the missing values using tetrahedral interpolation). I am not using any external libraries.
Another idea for improving:
check if a "rod" parrallel to z-axis (i.e. x=4, y=6) runs through the tetrahedron. If not, no values with (x=4, y=5, z) can be inside.
Else, find where the rod intersects the edge of the tetrahedron (by finding out where the planes that make up the edge of the tetrahedron intersect it).
Say these planes intersect at z=1.3 and z= 10.04. Then you know all points (4,5, 2) to (4,5,10) are inside.
Repeat for all values of x and y.
This should be faster in practice, because it will save you 1 loop.
Your approach is the correct one. There are some possible optimisations, which might be worth it or not depending on the requirements. For example:
There is an easier way to check if a given point is inside or outside of the tetrahedron.
It amounts to checking the which half-space the point belongs to with respect to each of the 4 sides of the tetrahedron:
Each side is defined by 3 points (say A, B, C). Then a plane normal is a (C-A)x(B-A) (that's cross product of vectors in the plane). If this coordinates are (a,b,c), then the plane equation is F(x,y,z) = ax+by+cz = 0. For a given point (x0, y0, z0) the sign of F(x0,y0,z0) determines which half-plane the points belong to.
The point is that you can precompute plane quations for each side of the tetrahedron as well as the sign which corresponds to 'outside' an then the check for a given point amounts to doing at most 4 evaluations (one for each side), each taking 3 multiplications and 2 additions.

How to determine if a point approximates an extension to the line between two other points?

I have a three points (A,B,C) that denote objects moving in 2D space. For each node I know its position and its velocity vector. All three objects are moving in the same direction.
I would like to know whether a point C (x3, y3) approximates a "positive" extension to the line formed by points A(x1, y1) and B(x2, y2). That is, I would like to know whether point C is "ahead" of point B (i.e "A->B->C" and not "C->A->B").
I know that checking if points A, B, C are collinear will give me an indication of all three points are lying on the same line, however, i cannot figure out whether point C approximates a positive extension to the line.
Any suggestion would be highly appreciated.
You can calculate the scalar product of the difference vectors AB and BC. If that is positive, then C is what you call 'in front of B. It may be way off to the left or right, though.
The scalar product would be calculated as
(b1-a1)x(c1-b1) + (b2-a2)x(c2-b2).
when A=(a1, a2), B=(b1, b2), C= (c1,c2) - it is the cos of the angle between the two vectors times the lengths of the vectors, and cos is positive for angles less than 90 degree.

How to find the two opposite normals or two segments?

I have a two segments AB and CD (in red). These two segments are facing each others. They are not completely parallel but will never be perpendicular to each others either.
From that, I need to find the two normals of these segments (in blue) that oppose each others (i.e. the two normals are outside ABCD). I know how to calculate the normals of the segments but obviously each segment has two normals, and I cannot figure out how to programmatically select the ones I need. Any suggestion?
Calculate the vector v between the midpoints of the two segments, pointing from AB to CD. Now the projection of the desired normal to AB onto v must be negative and the projection of the desired normal to CD onto v must be positive. So just calculate the normals, check against v, and negate the normals if needed to make them satisfy the condition.
Here it is in Python:
# use complex numbers to define minimal 2d vector datatype
def vec2d(x,y): return complex(x,y)
def rot90(v): return 1j * v
def inner_prod(u, v): return (u * v.conjugate()).real
def outward_normals(a, b, c, d):
n1 = rot90(b - a)
n2 = rot90(d - c)
mid = (c + d - a - b) / 2
if inner_prod(n1, mid) > 0:
n1 = -n1
if inner_prod(n2, mid) < 0:
n2 = -n2
return n1, n2
Note that I assume the endpoints define lines meeting the conditions in the problem. Nor do I check for the edge case when the lines have the same midpoint; the notion of "outside" doesn't apply in that case.
I think there are two cases to consider:
Case 1: Intersection between lines occurs outside the endpoints of either segment.
In this case the midpoint method suggested by #Michael J. Barber will work for sure. So form a vector between the midpoints of the segments, compute the dot product of your normal vectors with this midpoint vector and check the sign.
If you're computing the normal for lineA, the dot product of the normal with the vector midB -> midA should be +ve.
Case 2: Intersection between lines occurs inside the endpoints of one segment.
In this case form a vector between either one of the endpoints of the segment that does not enclose the intersection point and the intersection point itself.
The dot product of the normal for the segment that does enclose the intersection point and this new vector should be +ve.
You can find the outward normal for the other segment by requiring that the dot product between the two normals is -ve (which would only be ambiguous in the case of perpendicular segments).
I've assumed that the segments are not co-linear or actually intersecting.
Hope this helps.
You can reduce the four combinations for the signs as follows:
Calculate the dot product of the normals, a negative sign indicates that both show outside or inside.
As I suppose that your normals have unit lenght, you can detect parallelity if the dot product has magnitude one. A positive value indicates that both show in the same direction, a negative value says that both show in different directions.
It the normals are not parallel: parametrize lines as x(t) = x0 + t * n for a normal n and calculate the t for which both intersect. A negative t will indicate that both show outside. It is enough if you do this for one of the normals, as you reduced your combinations from 4 to 2 in step 1.
If both normals are parralel: Calculate the time t for which the normals hit the midpoint between of your segments. As in 2. is enough if you do this for one of the normals, as you reduced your combinations from 4 to 2 in step 1.

3D Trilateration using given distances of unknown fixed points

I am new to this forum and not a native english speaker, so please be nice! :)
Here is the challenge I face at the moment:
I want to calculate the (approximate) relative coordinates of yet unknown points in a 3D euclidean space based on a set of given distances between 2 points.
In my first approach I want to ignore possible multiple solutions, just taking the first one by random.
e.g.:
given set of distances: (I think its creating a pyramid with a right-angled triangle as a base)
P1-P2-Distance
1-2-30
2-3-40
1-3-50
1-4-60
2-4-60
3-4-60
Step1:
Now, how do I calculate the relative coordinates for those points?
I figured that the first point goes to 0,0,0 so the second one is 30,0,0.
After that the third points can be calculated by finding the crossing of the 2 circles from points 1 and 2 with their distances to point 3 (50 and 40 respectively). How do I do that mathematically? (though I took these simple numbers for an easy representation of the situation in my mind). Besides I do not know how to get to the answer in a correct mathematical way the third point is at 30,40,0 (or 30,0,40 but i will ignore that).
But getting the fourth point is not as easy as that. I thought I have to use 3 spheres in calculate the crossing to get the point, but how do I do that?
Step2:
After I figured out how to calculate this "simple" example I want to use more unknown points... For each point there is minimum 1 given distance to another point to "link" it to the others. If the coords can not be calculated because of its degrees of freedom I want to ignore all possibilities except one I choose randomly, but with respect to the known distances.
Step3:
Now the final stage should be this: Each measured distance is a bit incorrect due to real life situation. So if there are more then 1 distances for a given pair of points the distances are averaged. But due to the imprecise distances there can be a difficulty when determining the exact (relative) location of a point. So I want to average the different possible locations to the "optimal" one.
Can you help me going through my challenge step by step?
You need to use trigonometry - specifically, the 'cosine rule'. This will give you the angles of the triangle, which lets you solve the 3rd and 4th points.
The rules states that
c^2 = a^2 + b^2 - 2abCosC
where a, b and c are the lengths of the sides, and C is the angle opposite side c.
In your case, we want the angle between 1-2 and 1-3 - the angle between the two lines crossing at (0,0,0). It's going to be 90 degrees because you have the 3-4-5 triangle, but let's prove:
50^2 = 30^2 + 40^2 - 2*30*40*CosC
CosC = 0
C = 90 degrees
This is the angle between the lines (0,0,0)-(30,0,0) and (0,0,0)- point 3; extend along that line the length of side 1-3 (which is 50) and you'll get your second point (0,50,0).
Finding your 4th point is slightly trickier. The most straightforward algorithm that I can think of is to firstly find the (x,y) component of the point, and from there the z component is straightforward using Pythagoras'.
Consider that there is a point on the (x,y,0) plane which sits directly 'below' your point 4 - call this point 5. You can now create 3 right-angled triangles 1-5-4, 2-5-4, and 3-5-4.
You know the lengths of 1-4, 2-4 and 3-4. Because these are right triangles, the ratio 1-4 : 2-4 : 3-4 is equal to 1-5 : 2-5 : 3-5. Find the point 5 using trigonometric methods - the 'sine rule' will give you the angles between 1-2 & 1-4, 2-1 and 2-4 etc.
The 'sine rule' states that (in a right triangle)
a / SinA = b / SinB = c / SinC
So for triangle 1-2-4, although you don't know lengths 1-4 and 2-4, you do know the ratio 1-4 : 2-4. Similarly you know the ratios 2-4 : 3-4 and 1-4 : 3-4 in the other triangles.
I'll leave you to solve point 4. Once you have this point, you can easily solve the z component of 4 using pythagoras' - you'll have the sides 1-4, 1-5 and the length 4-5 will be the z component.
I'll initially assume you know the distances between all pairs of points.
As you say, you can choose one point (A) as the origin, orient a second point (B) along the x-axis, and place a third point (C) along the xy-plane. You can solve for the coordinates of C as follows:
given: distances ab, ac, bc
assume
A = (0,0)
B = (ab,0)
C = (x,y) <- solve for x and y, where:
ac^2 = (A-C)^2 = (0-x)^2 + (0-y)^2 = x^2 + y^2
bc^2 = (B-C)^2 = (ab-x)^2 + (0-y)^2 = ab^2 - 2*ab*x + x^2 + y^2
-> bc^2 - ac^2 = ab^2 - 2*ab*x
-> x = (ab^2 + ac^2 - bc^2)/2*ab
-> y = +/- sqrt(ac^2 - x^2)
For this to work accurately, you will want to avoid cases where the points {A,B,C} are in a straight line, or close to it.
Solving for additional points in 3-space is similar -- you can expand the Pythagorean formula for the distance, cancel the quadratic elements, and solve the resulting linear system. However, this does not directly help you with your steps 2 and 3...
Unfortunately, I don't know a well-behaved exact solution for steps 2 and 3, either. Your overall problem will generally be both over-constrained (due to conflicting noisy distances) and under-constrained (due to missing distances).
You could try an iterative solver: start with a random placement of all your points, compare the current distances with the given ones, and use that to adjust your points in such a way as to improve the match. This is an optimization technique, so I would look up books on numerical optimization.
If you know the distance between the nodes (fixed part of system) and the distance to the tag (mobile) you can use trilateration to find the x,y postion.
I have done this using the Nanotron radio modules which have a ranging capability.

Resources