Test if point inside angle - algorithm

In 2D plane there are four points: O, A, B, P.
O, A, B define an "angle", i.e. two rays, both originating at O, and one passing though A, while the other goes through B. How to tell on which "side" of the angle the point P lies, i.e. whether it is inside the space marked by the two rays?
Note that the points are placed arbitrarily, i.e. the angle might have larger size than π.
This is similar problem to determining which side of line a point lies, as discussed e.g. in comp.graphics.algorithms FAQ (Subject 1.02: How do I find the distance from a point to a line?), but here it is about two rays, instead of one line.
Edit: Apologies for not stating it more explicitly: the angle is oriented, i.e. given P, it might lay on the right of O, A, B, but then it is on the left of O, B, A. Let's say the triangle O, A, B has clock-wise orientation. Again, it is similar to the "which side of line" problem: there it also matters whether the line passes though A, B, or B, A.
An example:
\ \
A B
\ right \ left
left \ right \
O------B---- O------A----

When looking from O, we can split the plane into two regions or "sides".
A region that sweeps ray OA towards ray OB while rotating counterclockwise.
And the rest, i.e. ray OB sweeps counterclockwise to OA.
To check if the point is in which region, you can use
// if isInRegion(O, A, B) is true, P is in the first region.
// otherwise, isInRegion(O, B, A) will be true.
bool isInRegion(O, A, B, P) {
return isCCW(O, A, P) && !isCCW(O, B, P)
}
// ref: http://www.cs.cmu.edu/%7Equake/robust.html
// For more robust methods, see the link.
bool isCCW(a, b, c) {
return ((a.x - c.x)*(b.y - c.y) - (a.y - c.y)*(b.x - c.x)) > 0;
}
I tried it here.

The discussion that follows is meant to detect points inside the hatched area.
There are two cases to be considered:
the angle AOB is smaller than a flat, then the point P must be to the right of AO and to the right of OB (intersection of the two half planes),
the angle AOB is larger than a flat, then the point P must be to the right of AO or to the right of OB (union of the two half planes).
The complete boolean expression is
AO|B . (AO|P . OB|P) + ¬ AO|B . (AO|P + OB|P),
where XY|Z expresses that Z lies on the right of XY, which is equivalent to "XYZ is clockwise" and is determined by the sign of the triangle area.
I don't think it is possible to make the expression simpler, unless you have several P for the same AOB.

Related

Find point perpendicular to 2 points

It seems I am bad at vectors and math or forgot my entire university studies...
I have A, B, C points coordinates (X, Y, Z) where Z = 0.
C is placed in a half distance between A, B points.
D, E points are in parallel to A,B line
Any idea how to find D and E positions with three.js?
A, B, C are Vector3 three.js objects.
Any help is appreciated.
If C is at half the distance between A and B, offset orthogonally, as your figure seems to indicate, then it is simple:
D = C - 0.5AB and
E = C + 0.5AB,
where AB is the vector from A to B.
In THREE.js, you could write it for example like this:
const abHalf = b.clone().sub(a).multiplyScalar(0.5);
const d = c.clone().sub(abHalf);
const e = c.clone().add(abHalf);
though as usual when working with vectors, there are many other ways to calculate it; you may pick your favourite approach.
Is this what you meant?

How to do Ray and Triangle Edge intersect?

I'm facing problem intersecting ray with triangle edges. Actually, I'm trying to pick/intersect with triangle, vertex, edge of a mesh using Mouse. So I made ray from the Mouse current position and then I intersect it with the mesh elements like triangle/polygon, vertex, edge etc to work with it. Basically, 3d modeling stuffs. Intersecting with triangle was easy and fun. And the vertex part was tricky.
But now, I don't know how to intersect/pick with triangle edges. I mean how I treat them when intersecting with the Mouse Ray? First I thought they can be treated like a 3D line. But eventually failed to do the Ray and the Line intersect. Searched on the Internet but not found any helpful info. Although I found some open source projects are using OpenGL built-in picking features to pick/intersect with Edge. But in my case, I can't use that. :(
My current edge picking code structure looks like the following:
void pickEdge(Ray ray, Scene scene)
{
for each object in scene
{
mesh = getMesh(object)
for each triangle in mesh
{
for each edge in triangle
{
v1 = getV1(edge)
v2 = getV2(edge)
// Do intersect with 'ray' and 'v1', 'v2'. But how?
}
}
}
}
So I'm stuck here and really need some help. Any idea, algorithm or a small help is greatly appreciated.
In your case problem of finding intersection between triangle and ray in 3D space can be boiled down to finding point location (INSIDE, OUTSIDE, ON BOUNDARY) in triangle in 2D space (plane). All you should do is project triangle on screen plane, find intersection on edge and perform reverse projection on edge. Position of point is position of mouse. The only problem is to treat degenerate cases like mapping triangle into line segment. But I think it will not be problem, because such cases can be easily coped.
Please give a look to the algorithms at the end of this page and more in general all the ones that this website offers: http://geomalgorithms.com/a05-_intersect-1.html
The first approach is to orthogonally project the edge (and the ray) to a plane perpendicular to the ray, and then to compute the distance of the projected ray to the projected edge.
Ie., first you determine two orthogonal vectors rdir1, rdir2 orthogonal to your ray.
Then you calculate the projection of your ray (its base point) to this plane, which will simply yield a 2d point rp.
Then you project the edge to that plane, by simply applying dot products:
pv1 = new Vector2(DotProduct(v1, rdir1), DotProduct(v1, rdir2))
pv2 = new Vector2(DotProduct(v2, rdir1), DotProduct(v2, rdir2))
Now you can compute the distance from this 2d line pv1, pv2 to the point rp.
Provided that the direction of the edge is taken from the view matrix's "forward" direction, then two vectors orthogonal to that would be the view matrix's left and right vectors.
Doing the above recipe will then yield something similar to projecting the edge to the screen. Hence, alternatively you could project the edge to the screen and work with those coordinates.
First of all, what is the distance between two geometric objects A and B ? It is the minimal distance between any two points on A and B, ie. dist(A,B) = min { EuclideanLength(x - y) | x in A, y in B}. (If it exists and is unique, which it does in your case.)
Here EuclideanLength((x,y,z)) = sqrt(x^2 + y^2 + z^2) as you already know. Because sqrt is strictly increasing it suffices to minimize SquareEuclideanLength((x,y,z)) = x^2 + y^2 + z^2, which greatly simplifies the problem.
In your question the objects are a line segment A := {v1 + t*(v2-v1) | 0 <= t <= 1} and a line B := {p + s*d | s is any real number}. (Don't worry that you asked about a ray, a line is really what you want.)
Now calculating the distance comes down to finding appropriate t and s such that SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) is minimal and then computing EuclideanLength(v1 + t*(v2-v1) - p - s*d) to get the real distance.
To solve this we need some analytic geometry. Because d is not zero, we can write each vector v as a sum of a part that is orthogonal to d and a part that is a multiple of d: v = Ov + Mv. For such an "orthogonal decomposition" it always holds SquareEuclideanLength(v) = SquareEuclideanLength(Ov) + SquareEuclideanLength(Mv).
Because of d = Md in the above
SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) =
SquareEuclideanLength(Ov1 + t*(Ov2-Ov1) - Op)
+ SquareEuclideanLength(Mv1 + t*(Mv2-Mv1) - Mp - s*d)
the left addend does not depend on s and however you chose t you can find an s such that the right addend is 0 ! (Remember that Mv1, Mv2, ... are multiples of d.)
Hence to find the minimum you just have to find such maps O, M as above and find the minimizer t.
Assuming that d is normalized, these are actually given by Ov := CrossProduct(v, d) and Mv := DotProduct(v, d)*d, but just believe me, that this also works if d is not normalized.
So the recipe for finding the distance is now: find 0 <= t <= 1 that minimizes
SquareEuclideanLength(Cross(v1 - p, d) + t*Cross(v2 - v1, d))
= SquareEuclideanLength(Cross(v1 - p, d))
+ 2*t*Dot(Cross(v1 - p, d), Cross(v2 - v1, d))
+ t^2 SquareEuclideanLength(Cross(v2 - v1, d)).
You will already know this formula from Point-Line distance calculation (that's what it is) and it is solved by differentiating with respect to t and equalling 0.
So the minimizer of this equation is
t = -Dot(Cross(v1 - p, d), Cross(v2 - v1, d))/SquareEuclideanLength(Cross(v2 - v1, d))
Using this t you calculate v1 + t*(v2 - v1), the point on the line segment A that is closest to line B and you can plug this into your point-line distance algorithm to find the sought after distance.
I hope this helps you !

find all points within a range to any point of an other set

I have two sets of points A and B.
I want to find all points in B that are within a certain range r to A, where a point b in B is said to be within range r to A if there is at least one point a in A whose (Euclidean) distance to b is equal or smaller to r.
Each of the both sets of points is a coherent set of points. They are generated from the voxel locations of two non overlapping objects.
In 1D this problem fairly easy: all points of B within [min(A)-r max(A)+r]
But I am in 3D.
What is the best way to do this?
I currently repetitively search for every point in A all points in B that within range using some knn algorithm (ie. matlab's rangesearch) and then unite all those sets. But I got a feeling that there should be a better way to do this. I'd prefer a high level/vectorized solution in matlab, but pseudo code is fine too :)
I also thought of writing all the points to images and using image dilation on object A with a radius of r. But that sounds like quite an overhead.
You can use a k-d tree to store all points of A.
Iterate points b of B, and for each point - find the nearest point in A (let it be a) in the k-d tree. The point b should be included in the result if and only if the distance d(a,b) is smaller then r.
Complexity will be O(|B| * log(|A|) + |A|*log(|A|))
I archived further speedup by enhancing #amit's solution by first filtering out points of B that are definitely too far away from all points in A, because they are too far away even in a single dimension (kinda following the 1D solution mentioned in the question).
Doing so limits the complexity to O(|B|+min(|B|,(2r/res)^3) * log(|A|) + |A|*log(|A|)) where res is the minimum distance between two points and thus reduces run time in the test case to 5s (from 10s, and even more in other cases).
example code in matlab:
r=5;
A=randn(10,3);
B=randn(200,3)+5;
roughframe=[min(A,[],1)-r;max(A,[],1)+r];
sortedout=any(bsxfun(#lt,B,roughframe(1,:)),2)|any(bsxfun(#gt,B,roughframe(2,:)),2);
B=B(~sortedout,:);
[~,dist]=knnsearch(A,B);
B=B(dist<=r,:);
bsxfun() is your friend here. So, say you have 10 points in set A and 3 points in set B. You want to have them arrange so that the singleton dimension is at the row / columns. I will randomly generate them for demonstration
A = rand(10, 1, 3); % 10 points in x, y, z, singleton in rows
B = rand(1, 3, 3); % 3 points in x, y, z, singleton in cols
Then, distances among all the points can be calculated in two steps
dd = bsxfun(#(x,y) (x - y).^2, A, B); % differences of x, y, z in squares
d = sqrt(sum(dd, 3)); % this completes sqrt(dx^2 + dy^2 + dz^2)
Now, you have an array of the distance among points in A and B. So, for exampl, the distance between point 3 in A and point 2 in B should be in d(3, 2). Hope this helps.

How can I find out if point is within a triangle in 3D?

I need an algorithm (3D), which would determine if point belongs to a triangle. And also if it does I want to know the distance between some point in triangle and a another point. Triangles can be slightly rotated, but if point is outside triangles vertical reach then it should not be considered as inside the triangle.
Now I realize, my question probably doesn't make a lot of sense so here's the picture, which explains what I want.
Grey lines display, which way triangle is actually facing.
It's not actually that I want to check if a point is within a prism, but I after i find out if point lies within triangle (not exactly, might be on top of or below) then I need to find the distance between point and a triangle it belongs to. And depending on the distance function will finally return if that point is inside the triangle. A little inaccuracy is allowed. However, maybe I want to check if a point is within a prism, but do not know that. I am just horrible at math so I am not aware of correct terminology.
This seems like the 3D equivalent of Data structure to query points which lie inside a triangle.
You could use the same method in 3D: in 3D, a plane cuts the space in two halves: a point is either at one side of the plane or at the other side. The wedge-shape is a collection of planes: just combine the which_side_of_the_plane information for a given point with all the planes that build up the wedge.
You can use a cylindrical version of barycentric coordinates. I've only checked this for prisms that rise perpendicular from the triangular base -- another way to put this is that we are orthogonally projecting the point into the plane defined by the triangle, and checking if it is inside or not.
If you want more details on the math ask (or better yet, try to figure it out yourself since it's a neat little exercise).
If our triangle is ABC (non-degenerate), then N = (B-A)x(C-A) (cross product) is a normal to the (unique) plane defined by the triangle. Call the point we want to test P.
Now calculate the value a' = N . ((P-B) x (P-C)) (where . is dot product). a' is the usual barycentric coordinate multiplied by N.N (which is positive).
Similarly, we find b' = N . ((P-C) x (P-A)) and c' = N . ((P-A) x (P-B)). If all three of 'a'', 'b'', and 'c'' are non-negative, then the projection of P is inside the triangle (if you want to exclude the triangle itself, then all three must be strictly positive).
This can be split into 2 problems.
Test that the point inside the 3-planes defined by the triangle sides.
Find the distance to the plane defined by the triangle normal.(and use own logic to test if this distance is considered close or not).
Withe the example below, you can do a check, for eg:
if (isect_point_tri_prism_v3(p, v1, v2, v2) and
(dist_signed_squared_point_tri_plane_v3(p, v1, v2, v2) < (eps * eps)):
# do stuff
... where eps is the distance to consider points 'on the triangle'.
This code example uses functional Python so should be easy to move to other languages, it uses only simple arithmetic, no sqrt or complex functions.
# ----------------
# helper functions
def sub_v3v3(v0, v1):
return (v0[0] - v1[0], v0[1] - v1[1], v0[2] - v1[2])
def dot_v3v3(v0, v1):
return ((v0[0] * v1[0]) + (v0[1] * v1[1]) + (v0[2] * v1[2]))
def cross_v3v3(v0, v1):
return ((v0[1] * v1[2]) - (v0[2] * v1[1]),
(v0[2] * v1[0]) - (v0[0] * v1[2]),
(v0[0] * v1[1]) - (v0[1] * v1[0]))
def closest_to_line_v3(p, l0, l1):
"""
Return the closest point to p on the line defined by (l0, l1)
"""
u = sub_v3v3(l1, l0)
h = sub_v3v3(p, l0)
l = dot_v3v3(u, h) / dot_v3v3(u, u)
return (l0[0] + u[0] * l,
l0[1] + u[1] * l,
l0[2] + u[2] * l)
def point_in_slice_v3(p, v, l0, l1):
cp = closest_to_line_v3(v, l0, l1)
q = sub_v3v3(cp, v)
rp = sub_v3v3(p, v)
# For languages which allow divide-by-zero,
# this is taken into account and returns false.
h = dot_v3v3(q, rp) / dot_v3v3(q, q)
return (h >= 0.0 and h <= 1.0)
# --------------
# main functions
def isect_point_tri_prism_v3(p, v0, v1, v2):
"""
Return True when the point is inside the triangular prism.
Zero area triangles always return false.
"""
return (point_in_slice_v3(p, v0, v1, v2) and
point_in_slice_v3(p, v1, v2, v0) and
point_in_slice_v3(p, v2, v0, v1))
def dist_signed_squared_point_tri_plane_v3(p, v0, v1, v2):
"""
Return the squared distance to the triangle,
positive values are 'in-front' of the triangle, negative behind.
(using CCW coordinate system - OpenGL).
Remove the 'copysign' call for the non-signed version.
(if you don't need to know which side of the triangle the point is on).
"""
from math import copysign
n = cross_v3v3(sub_v3v3(v2, v1), sub_v3v3(v0, v1))
rp = sub_v3v3(p, v1)
len_sq = dot_v3v3(n, n)
side = dot_v3v3(rp, n)
fac = side / len_sq
return copysign(len_sq * (fac * fac), side)

Position of connected points in space

A-B-C-D are 4 points. We define r = length(B-C), angle, ang1 = (A-B-C) and angle ang2 = (B-C-D) and the torsion angle tors1 = (A-B-C-D). What I really need to do is to find the coordinates of C and D provided that I have the new values of r, ang1, ang2 and tors1.
The thing is that the points A and B are rigidly connected to each other, and points C and D are also connected to each other by a rigid connector, so to speak. That is the distance (C-D) remains fixed and also distance A-B remains fixed. There is no such rigid connection between the points B and C.
We have the old coordinates of the 4 points for some other set of (r,ang1,ang2,tors1) and we need to find the new coordinates when this defining set of variables changes to some arbitrary value.
I would be grateful for any helpful comments.
Thanks a lot.
I'm not allowed to post a picture because I'm a new user :(
Additional Info: An iterative solution is not going to be useful because I need to do this in a simulation "plenty of times O(10^6)".
I think the best way to approach this problem would be to think in terms of analytic geometry.
Each point A,B,C,D has some 3D coordinates (x,y,z) and you have some relationships between
them (e.g. distance B-C is equal to r means that
r = sqrt[ (x_b - x_c)^2 + (y_b - y_c)^2 + (z_b - z_c)^2 ]
Once you define such relations it remains to solve the resulting system of equations for the unknown values of coordinates of the points you need to determine.
This is a general approach, if you describe the problem better (maybe a picture?) it might be easy to find some efficient ways of solving such systems because of some special properties your problem has.
You haven't mentioned the coordinate system. Even if (r, a1, a2, t) don't change, the "coordinates" will change if the whole structure can be sent whirling off into space. So I'll make some assumptions:
Put B at the origin, C on the positive X axis and A in the XY plane with y&gt0. If you don't know the distance AB, calculate it from the old coordinates. Likewise CD.
A: (-AB cos(a1), AB sin(a1), 0)
B: (0, 0, 0)
C: (r, 0, 0)
D: (r + CD cos(a2), CD sin(a2) cos(t), CD sin(a2) sin(t))
(Just watch out for sign conventions in the angles.)
you are describing a set of constraints.
what you need to do is for every constraint check if they are still satisfied, and if not calc the most efficient way to get it correct again.
for instance, in case of length b-c=r if b-c is not r anymore, make it r again by moving both b and c to or from eachother so that the constraint is met again.
for every constraint one by one do this.
Then repeat a few times until the system has stabilized again (e.g. all constraints are met).
that's it
You are asking for a solution to a nonlinear system of equations. For the mathematically inclined, I will write out the constraint equations:
Suppose you have positions of points A,B,C,D. We define vectors AB=A-B, etc., and furthermore, we use the notation nAB to denote the normalized vector AB/|AB|. With this notation, we have:
AB.AB = fixed
CD.CD = fixed
CB.CB = r*r
nAB.nCB = cos(ang1)
nDC.nBC = cos(ang2)
Let E = D - DC.(nCB x nAB) // projection of D onto plane defined by ABC
nEC.nDC = cos(tors1)
nEC x nDC = sin(tors1) // not sure if your torsion angle is signed (if not, delete this)
where the dot (.) denotes dot product, and cross (x) denotes cross product.
Each point is defined by 3 coordinates, so there are 12 unknowns, and 6 constraint equations, leaving 6 degrees of freedom that are unconstrained. These are the 6 gauge DOFs from the translational and rotational invariance of the space.
Assuming you have old point positions A', B', C', and D', and you want to find a new solution which is "closest" (in a sense I defined) to those old positions, then you are solving an optimization problem:
minimize: AA'.AA' + BB'.BB' + CC'.CC' + DD'.DD'
subject to the 4-5 constraints above.
This optimization problem has no nice properties so you will want to use something like Conjugate Gradient descent to find a locally optimal solution with the starting guess being the old point positions. That is an iterative solution, which you said is unacceptable, but there is no direct solution unless you clarify your problem.
If this sounds good to you, I can elaborate on the nitty gritty of performing the numerical optimization.
This is a different solution than the one I gave already. Here I assume that the positions of A and B are not allowed to change (i.e. positions of A and B are constants), similar to Beta's solution. Note that there are still an infinite number of solutions, since we can rotate the structure around the axis defined by A-B and all your constraints are still satisfied.
Let the coordinates of A be A[0], A[1] and A[2], and similarly for B. You want explicit equations for C and D, as you mentioned in the response to Beta's solution, so here they are:
First find the position of C. As mentioned before, there are an infinite number of possibilities, so I will pick a good one for you.
Vector AB = A-B
Normalize(AB)
int best_i = 0;
for i = 1 to 2
if AB[i] < AB[best_i]
best_i = i
// best_i contains dimension in which AB is smallest
Vector N = Cross(AB, unit_vec[best_i]) // A good normal vector to AB
Normalize(N)
Vector T = Cross(N, AB) // AB, N, and T form an orthonormal frame
Normalize(T) // redundant, but just in case
C = B + r*AB*cos(ang1) + r*N*sin(ang1)
// Assume s is the known, fixed distance between C and D
// Update the frame
Vector BC = B-C, Normalize(BC)
N = Cross(BC, T), Normalize(N)
D = C + s*cos(tors1)*BC*cos(ang2) + s*cos(tors1)*N*sin(ang1) +/- s*sin(tors1)*T
That last plus or minus depends on how you define the orthonormal frame. Try one and see if it's what you want, otherwise it's the other sign. The notation above is pretty informal, but it gives a definite recipe for how to generate C and D from A, B, and your parameters. It also chooses a good C (which depends on a good, nondegenerate N). unit_vec[i] refers to the vector of all zeros, except for a 1 at index i. As usual, I have not tested the pseudocode above :)

Resources