Overlapping line segments in 2D space - language-agnostic

I need to find whether two lines overlap each other. I have the intersection code which returns 0, if two lines are parallel. But then I need to know if these two parallel lines overlap.
Edit:
A C B D
-----------------------------------------------
Line 1: A-B
Line 2: C-D
I need to find if Line 1 overlaps Line 2, but both lines can have a slope > 0.

You can compare to find if there is no over lap. you will have less comparisons in this way thus very efficient. Do following comparisons
D < A
B < C
If either case is true the lines are not overlapping. otherwise there must an overlap.
You will make least number of comparisons to determine if they are not overlapping. Otherwise there will be more comparisons to make.

Since you know they're both parallel, then just check whether line segment CD contains either of the endpoints of the first line (point A and point B).

For two co-linear line segments that are not necessarily axis-aligned:
Sort the vertices in clockwise order around the origin.
The lines overlap if the ordered vertices alternate between the two segments, e.g. Line1.Point1, Line2.Point1, Line1.Point2, Line2.Point2.

It is sufficient to calculate the areas of triangles ACB and CBD. If the area is 0, then the points are collinear, and if both areas are zero then the lines are overlapping.
You can calculate the area of a triangle ABC by this formula:
2*Area(ABC)= (bx – ax)(cy – ay) – (cx – ax)(by – ay);

Line equation is direction of line in infinite, by finding slope or intercept you wont be able do anything with them(even though horizontal line doesn't have slope), i suggest use point on line.
so AB is your line [(x,y),(x,y)] and C is on of the point (x,y) and then you need to check if point on the line.
Check Point On a Line

We are given two line segments
AB = line segment from (Ax,Ay) to (Bx,By)
CD = line segment from (Cx,Cy) to (Dx,Dy)
with the same slope.
Order the endpoints E1 < E2 < E3 < E4 such that Ei,x ≤ Ei+1,x and Ei,y ≤ Ei+1,y if Ei,x = Ei+1,x
If E1 and E2 are from different segments, the overlap is the segment from E2 to E3.
There are some degenerate cases:
A < B = C < D
A < C = D < B
A < B = C = D
A = B = C = D
These result in a single point of intersection. I'm not sure if any of those can occur in your system, but if so you'll have to decide whether or not you consider that "overlap" and add special case checks.

The characteristic of two segments of being in the same lines is called collinearity and can be tested calculating the area of the 2 triangles formed by one segment endpoints and, respectively, the endpoints of the other segment. If the area is zero or close to zero below a threshold the segments are collinear.
public static bool AreSegmentsCollinear(Segment a, Segment b, double epsilon)
{
return IsPointCollinear(a, b.Left, epsilon) && IsPointCollinear(a, b.Right, epsilon);
}
public static bool IsPointCollinear(Segment a, Vector2D p, double epsilon)
{
return Math.Abs(GetSignedTriangleArea2(a, p)) <= epsilon;
}
/// <returns>The squared signed area of the triangle formed with endpoints
/// of segment a and point p</returns>
public static double GetSignedTriangleArea2(Segment a, Vector2D p)
{
return (p - a.Left) ^ (a.Right - a.Left);
}
/// <summary>Cross product of vectors in 2D space. NB: it returns a
/// magnitude (scalar), not a vector</summary>
/// <returns>The area of the parallelogram formed with u, v as the edges</returns>
public static Double operator ^(Vector2D u, Vector2D v)
{
return u.X * v.Y - u.Y * v.X;
}

Just to be clear since there seems to be some confusion in the answers, the question being asked is as follows. Given two 2D line segments A and B how do I determine if both of the following are true:
A and B are colinear.
A and B intersect.
Note that there are tolerances involved in both questions i.e. how close to parallel and how near each other do A and B need to be to be considered colinear? How much do they need to overlap to be considered overlapping?
I think to handle such tolerances robustly the best algorithm is to treat the line segments as thin rectangles, where the thickness of the rectangles is a tolerance parameter t1. Let t2 be another tolerance parameter on slopes that are considered parallel. Then the algorithm becomes
If the slope of A and the slope of B are not within t2 of each other return false. To handle vertical lines cleanly, slope can be represented as a unit vector and the test can be on whether the Euclidean distance between the two unit vectors is smaller than t2.
Represent A and B as (non-axis-aligned) rectangles R1 and R2. Where R1 encloses A in the obvious way, i.e. it is length(A) + t1 units long and is t1 units wide with A centered inside it, and R2 analogously encloses B.
Determine if R1 and R2 intersect each other. This can be done relatively efficiently by treating each rectangle as the union of two triangles and testing for triangle-triangle intersections across all combinations of A triangles and B triangles. If there is an intersection return true; otherwise return false.

With lines l1 and l2 given in the following form [x1, y1, x2, y2] the following python code will give the intersection for collinear line segments with any slope.
intersection = line_intersect(l1, l2)
def line_intersect(l1, l2):
"""Find the intersection of two line segments"""
x1, y1, x2, y2 = l1
x3, y3, x4, y4 = l2
x_inter = component_intersect(x1, x2, x3, x4)
y_inter = component_intersect(y1, y2, y3, y4)
return math.sqrt(x_inter**2 + y_inter**2)
def component_intersect(c1, c2, c3, c4):
"""Calculate intersection in one dimension/component"""
# find left endpoints
cl1 = min(c1, c2)
cl2 = min(c3, c4)
# find right endpoints
cr1 = max(c1, c2)
cr2 = max(c3, c4)
# find endpoints of intersection
c_inter_l = max(cl1, cl2)
c_inter_r = min(cr1, cr2)
# calcuate intersection
c_inter = c_inter_r - c_inter_l
c_inter = max(c_inter, 0)
return c_inter

Related

How to find area enclosed by points in octave using Quadrature or any other method

I have two sets of coordinates (both positive and negative values, not necessarily in increasing order, and in many cases there are different values of y for the same value of x) which I can load into two row vectors of equal size.
I want to calculate the area enclosed by the curve.
How to do it with octave?
I tried this answer but it does not work because it seems that the area printed (204.64) is too high (see picture).
I tried the code:
function showdata(fName)
M = dlmread(fName);
H = M(2:end, 1); % starting row number is 2
B = M(2:end, 2);
aux = figure();
plot(H, B,'linewidth',2);
xlabel ("Auxilary field H (A/m)");
ylabel ("Magnetic Field B (Tesla)");
area = polyarea(H,B)
axis([min(H), max(H), min(B), max(B)]);
grid on;
grid minor on;
title (area,"fontsize",20);
Then I am calling showdata('data.txt') in Octave.
Picture of Data points:
This is the data file I am using.
There is a function for computing convex hull called "convhull" in Octave. It returns the indices of the points formming convex hull data.
M = dlmread("data.txt"); #I removed the header in data.txt
x = M(:,1);
y = M(:,2);
k = convhull(x,y);
plot (x(k), y(k), "r-", x, y, "b+");
n = rows(k);
x_prime = vertcat(x(k(n)), x(k(1:n-1)));
y_prime = vertcat(y(k(n)), y(k(1:n-1)));
A = .5*abs(x_prime'*y(k)-y_prime'*x(k)); #80.248
polyarea(x(k), y(k)) == A and true
Maybe convex hull is not good estimate of area because the top left and the down-right lines are a little far away from the points. There are other ways to form a polygon from data
, one of which could be alpha shape. However, alpha shape are more complicated and there is no corresponding pre-built function in Octave.
Update:
Each x corresponds to at least one y cordinate. I marked the highest point and lowest point laying on the same x and estimate the area again.
There is the code:
[uni, ~] = sort(unique(x));
n = rows(uni);
outline = [];
for i = 1:n
y_list = y(x==uni(i));
[y_max, ~] = max(y_list);
outline(i, :)= [uni(i), y_max];
[y_min, ~] = min(y_list);
outline(2*n-i+1,:)= [uni(i), y_min];
endfor
figure;
plot (x(k), y(k), "r-", x, y, "b+", outline(:,1), outline(:,2), "g-", "linewidth", 3);
polyarea(outline(:,1), outline(:,2)) #74.856
By the way, if the arguments of function polyarea do not form a close curve function polyarea would return wrong area.
Four point on a unit square:
[(0,0), (1,0), (1,1), (0,1)], [(0,0), (1,1), (1,0), (0,1)]
polyarea([0,1,1,0],[0,0,1,1])!==polyarea([0,1,1,0],[0,1,0,1]).

Create a function to generate random points in a parallelogram

I hope someone can help me here, I have been asked to write some code for an Lua script for a game. Firstly i am not an Lua Scripter and I am defiantly no mathematician.
What i need to do is generate random points within a parallelogram, so over time the entire parallelogram becomes filled. I have played with the scripting and had some success with the parallelogram (rectangle) positioned on a straight up and down or at 90 degrees. My problem comes when the parallelogram is rotated.
As you can see in the image, things are made even worse by the coordinates originating at the centre of the map area, and the parallelogram can be positioned anywhere within the map area. The parallelogram itself is defined by 3 pairs of coordinates, start_X and Start_Y, Height_X and Height_Y and finally Width_X and Width_Y. The random points generated need to be within the bounds of these coordinates regardless of position or orientation.
Map coordinates and example parallelogram
An example of coordinates are...
Start_X = 122.226
Start_Y = -523.541
Height_X = 144.113
Height_Y = -536.169
Width_X = 128.089
Width_Y = -513.825
In my script testing i have eliminated the decimals down to .5 as any smaller seems to have no effect on the final outcome. Also in real terms the start width and height could be in any orientation when in final use.
Is there anyone out there with the patients to explain what i need to do to get this working, my maths is pretty basic, so please be gentle.
Thanks for reading and in anticipation of a reply.
Ian
In Pseudocode
a= random number with 0<=a<=1
b= random number with 0<=b<=1
x= Start_X + a*(Width_X-Start_X) + b*(Height_X-Start_X)
y= Start_Y + a*(Width_Y-Start_Y) + b*(Height_Y-Start_Y)
this should make a random point at coordinates x,y within the parallelogram
The idea is that each point inside the parallelogram can be specified by saying how far you go from Start in the direction of the first edge (a) and how far you go in the direction of the second edge (b).
For example, if you have a=0, and b=0, then you do not move at all and are still at Start.
If you have a=1, and b=0, then you move to Width.
If you have a=1, and b=1, then you move to the opposite corner.
You can use something like "texture coordinates", which are in the range [0,1], to generate X,Y for a point inside your parallelogram. Then, you could generate random numbers (u,v) from range [0,1] and get a random point you want.
To explain this better, here is a picture:
The base is formed by vectors v1 and v2. The four points A,B,C,D represent the corners of the parallelogram. You can see the "texture coordinates" (which I will call u,v) of the points in parentheses, for example A is (0,0), D is (1,1). Every point inside the parallelogram will have coordinates within (0,0) and (1,1), for example the center of the parallelogram has coordinates (0.5,0.5).
To get the vectors v1,v2, you need to do vector subtraction: v1 = B - A, v2 = C - A. When you generate random coordinates u,v for a random point r, you can get back the X,Y using this vector formula: r = A + u*v1 + v*v2.
In Lua, you can do this as follows:
-- let's say that you have A,B,C,D defined as the four corners as {x=...,y=...}
-- (actually, you do not need D, as it is D=v1+v2)
-- returns the vector a+b
function add(a,b)
return {x = a.x + b.x, y = a.y + b.y} end
end
-- returns the vector a-b
function sub(a,b)
return {x = a.x - b.x, y = a.y - b.y} end
end
-- returns the vector v1*u + v2*v
function combine(v1,u,v2,v)
return {x = v1.x*u + v2.x*v, y = v1.y*u + v2.y*v}
end
-- returns a random point in parallelogram defined by 2 vectors and start
function randomPoint(s,v1,v2)
local u,v = math.random(), math.random() -- these are in range [0,1]
return add(s, combine(v1,u,v2,v))
end
v1 = sub(B,A) -- your basis vectors v1, v2
v2 = sub(C,A)
r = randomPoint(A,v1,v2) -- this will be in your parallelogram defined by A,B,C
Note that this will not work with your current layout - start, width, height. How do you want to handle rotation with these parameters?

Correct solution for this tensor

I'm implementing the system in this paper and I've come a little unstuck correctly implementing the radial tensor field.
All tensors in this system are of the form given on page 3, section 4
R [ cos(2t), sin(2t); sin(2t), -cos(2t) ]
The radial tensor field is defined as:
R [ yy - xx, -2xy; -2xy, -(yy-xx) ]
In my system I'm only storing R and Theta, since I can calculate the tensor based off just that information. This means I need to calculate R and Theta for the radial tensor. Unfortunately, my attempts at this have failed. Although it looks correct, my solution fails in the top left and bottom right quadrants.
Addendum: Following on from discussion in the comments about the image of the system not working, I'll put some hard numbers here too.
The entire tensor field is 800x480, the center point is at { 400, 240 }, and we're using the standard graphics coordinate system with a negative y axis (ie. origin in the top left).
At { 400, 240 }, the tensor is R = 0, T = 0
At { 200, 120 }, the tensor is R = 2.95936E+9, T = 2.111216
At { 600, 120 }, the tensor is R = 2.95936E+9, T = 1.03037679
I can easily sample any more points which you think may help.
The code I'm using to calculate values is:
float x = i - center.X;
float xSqr = x * x;
float y = j - center.Y;
float ySqr = y * y;
float r = (float)Math.Pow(xSqr + ySqr, 2);
float theta = (float)Math.Atan2((-2 * x * y), (ySqr - xSqr)) / 2;
if (theta < 0)
theta += MathHelper.Pi;
Evidently you are comparing formulas (1) and (2) of the paper. Note the scalar multiple l = || (u_x,u_y) || in formula (1), and identify that with R early in the section. This factor is implicit in formula (2), so to make them match we have to factor R out.
Formula (2) works with an offset from the "center" (x0,y0) of the radial map:
x = xp - x0
y = yp - y0
to form the given 2x2 matrix:
y^2 - x^2 -2xy
-2xy -(y^2 - x^2)
We need to factor out a scalar R from this matrix to get a traceless orthogonal 2x2 matrix as in formula (1):
cos(2t) sin(2t)
sin(2t) -cos(2t)
Since cos^2(2t) + sin^2(2t) = 1 the factor R can be identified as:
R = (y^2 - x^2)^2 + (-2xy)^2 = (x^2 + y^2)^2
leaving a traceless orthogonal 2x2 matrix:
C S
S -C
from which the angle 'tan(2t) = S/C` can be extracted by an inverse trig function.
Well, almost. As belisarius warns, we need to check that angle t is in the correct quadrant. The authors of the paper write at the beginning of Sec. 4 that their "t" (which refers to the tensor) depends on R >= 0 and theta (your t) lying in [0,2pi) according to the formula R [ cos(2t), sin(2t); sin(2t) -cos(2t) ].
Since sine and cosine have period 2pi, t (theta) is only uniquely determined up to an interval of length pi. I suspect the authors meant to write either that 2t lies in [0,2pi) or more simply that t lies in [0,pi). belisarius suggestion to use "the atan2 equivalent" will avoid any division by zero. We may (if the function returns a negative value) need to add pi so that t >= 0. This amounts to adding 2pi to 2t, so it doesn't affect the signs of the entries in the traceless orthogonal matrix (since 'R >= 0` the pattern of signs should agree in formulas (1) and (2) ).

Determining the intersection of a triangle and a plane

I have a single triangle and a plane (in 3 dimensional space), How would I calculate the line segment where the two cross, if there is no crossing then I need to detect this case.
The end result I'm looking for is two 3 dimensional vectors, which define the start and end points of the line segment.
To help you out a little, I have already calculated the intersection ray between the plane of the face, and the plane, I simply need to find the endpoints to clip that ray into a line segment.
For those who like reading things in code:
Face face; //a face, defined by 3 points
Plane plane; //a plane, defined by a normal vector and a distance
Ray intersection; //a ray, defined by a point and a direction, initialised to the intersection of the face plane and the face
Segment s = CalculateSegment(face, plane, intersection); //this method needs defining
Here's some suggested pseudo code. Simple version first, more robust version later (just to help separate the principle from the neuances).
Simple version:
// Assume the plane is given as the equation dot(N,X) + d = 0, where N is a (not
// neccessarily normalized) plane normal, and d is a scalar. Any way the plane is given -
// DistFromPlane should just let the input vector into the plane equation.
vector3d planeN;
float planeD;
float DistFromPlane( vector3d P)
{
// if N is not normalized this is *not* really the distance,
// but the computations work just the same.
return dot(planeN,P) + planeD;
}
bool GetSegmentPlaneIntersection( vector3d P1, vector3d P2, vector3d& outP)
{
float d1 = DistFromPlane(P1),
d2 = DistFromPlane(P2);
if (d1*d2 > 0) // points on the same side of plane
return false;
float t = d1 / (d1 - d2); // 'time' of intersection point on the segment
outP = P1 + t * (P2 - P1);
return true;
}
void TrianglePlaneIntersection(vector3d triA, vector3d triB, vector3d triC,
vector3dArray& outSegTips)
{
vector3d IntersectionPoint;
if( GetSegmentPlaneIntersection( triA, triB, IntersectionPoint))
outSegTips.Add(IntersectionPoint);
if( GetSegmentPlaneIntersection( triB, triC, IntersectionPoint))
outSegTips.Add(IntersectionPoint);
if( GetSegmentPlaneIntersection( triC, triA, IntersectionPoint))
outSegTips.Add(IntersectionPoint);
}
Now adding some robustness:
[Edit: Added explicit consideration for the case of a single vertex on the plane]
vector3d planeN;
float planeD;
float DistFromPlane( vector3d P)
{
return dot(planeN,P) + planeD;
}
void GetSegmentPlaneIntersection( vector3d P1, vector3d P2, vector3dArray& outSegTips)
{
float d1 = DistFromPlane(P1),
d2 = DistFromPlane(P2);
bool bP1OnPlane = (abs(d1) < eps),
bP2OnPlane = (abs(d2) < eps);
if (bP1OnPlane)
outSegTips.Add(P1);
if (bP2OnPlane)
outSegTips.Add(P2);
if (bP1OnPlane && bP2OnPlane)
return;
if (d1*d2 > eps) // points on the same side of plane
return;
float t = d1 / (d1 - d2); // 'time' of intersection point on the segment
outSegTips.Add( P1 + t * (P2 - P1) );
}
void TrianglePlaneIntersection(vector3d triA, vector3d triB, vector3d triC,
vector3dArray& outSegTips)
{
GetSegmentPlaneIntersection( triA, triB, outSegTips));
GetSegmentPlaneIntersection( triB, triC, outSegTips));
GetSegmentPlaneIntersection( triC, triA, outSegTips));
RemoveDuplicates(outSegTips); // not listed here - obvious functionality
}
Hopefully that gives an idea, but there are still quite a few potential optimizations. If, for example, you're calculating these intersections for every triangle in a large mesh, you might calculate and cache the DistanceFromPlane once per vertex, and just retrieve it for every edge the vertex participates in. There can be more advanced caching too, depending on your scenario and data representation.
Plug the 3 points into the plane equation (defined by the 4 parameters you listed a,b,c,d) and determine which pairs are on opposite sides of the plane.
Given the plane equation:
Ax + By + Cz + D = 0
where A,B,C is the normal (unit length) and D is the distance to origin IIRC, you plug in points (x,y,z) and see if this result is positive or negative. It will be zero for points on the plane, and the sign will tell you which side a point is on when the result is not 0. So pick pairs of points on opposite sides (there will be at most 2) and compute the intersection of those 2 segments with the plane using a standard ray/plane intersection formula which escapes me right now. Those will be the 2 points that form the segment you seek.
EDIT
Come to think of it, the values you get from plugging the points into the plane equation should be useful for interpolating between pairs of points to get the intersection of segments with the plane.
Len Fn = Axn + Byn + C*zn + D be the result of plugging in point n.
Then suppose F1 = -4 and F2 = 8. So points P1 and P2 are on opposite sides of the plane. We will also have P = P1*2/3 + P2*1/3 is the point of intersection of the segment from P1 to P2 with the plane. Generalizing this into a proper formula is left as an exorcise.
Find the intersection of each line segment bounding the triangle with the plane. Merge identical points, then
if 0 intersections exist, there is no intersection
if 1 intersection exists (i.e. you found two but they were identical to within tolerance) you have a point of the triangle just touching the plane
if 2 points then the line segment between them is the intersection
next step, search SO for line-segment to plane intersection algorithms (or just use the one provided by your framework)...
It depends a bit on what libraries you have. I have created my own geometry library which can calculate the intersection of a line with a plane. In this case calculate the three points of intersection of the three edges of the triangle and then calculate which of them lie between vertices. This could be 0 (no intersection), or 2 which is the case you want. (There are special cases where the two points are coincident - a point of the triangle).

Finding points on a line with a given distance

I have a question i know a line i just know its slope(m) and a point on it A(x,y) How can i calculate the points(actually two of them) on this line with a distance(d) from point A ???
I m asking this for finding intensity of pixels on a line that pass through A(x,y) with a distance .Distance in this case will be number of pixels.
I would suggest converting the line to a parametric format instead of point-slope. That is, a parametric function for the line returns points along that line for the value of some parameter t. You can represent the line as a reference point, and a vector representing the direction of the line going through that point. That way, you just travel d units forward and backward from point A to get your other points.
Since your line has slope m, its direction vector is <1, m>. Since it moves m pixels in y for every 1 pixel in x. You want to normalize that direction vector to be unit length so you divide by the magnitude of the vector.
magnitude = (1^2 + m^2)^(1/2)
N = <1, m> / magnitude = <1 / magnitude, m / magnitude>
The normalized direction vector is N. Now you are almost done. You just need to write the equation for your line in parameterized format:
f(t) = A + t*N
This uses vector math. Specifically, scalar vector multiplication (of your parameter t and the vector N) and vector addition (of A and t*N). The result of the function f is a point along the line. The 2 points you are looking for are f(d) and f(-d). Implement that in the language of your choosing.
The advantage to using this method, as opposed to all the other answers so far, is that you can easily extend this method to support a line with "infinite" slope. That is, a vertical line like x = 3. You don't really need the slope, all you need is the normalized direction vector. For a vertical line, it is <0, 1>. This is why graphics operations often use vector math, because the calculations are more straight-forward and less prone to singularities.
It may seem a little complicated at first, but once you get the hang of vector operations, a lot of computer graphics tasks get a lot easier.
Let me explain the answer in a simple way.
Start point - (x0, y0)
End point - (x1, y1)
We need to find a point (xt, yt) at a distance dt from start point towards end point.
The distance between Start and End point is given by d = sqrt((x1 - x0)^2 + (y1 - y0)^2)
Let the ratio of distances, t = dt / d
Then the point (xt, yt) = (((1 - t) * x0 + t * x1), ((1 - t) * y0 + t * y1))
When 0 < t < 1, the point is on the line.
When t < 0, the point is outside the line near to (x0, y0).
When t > 1, the point is outside the line near to (x1, y1).
Here's a Python implementation to find a point on a line segment at a given distance from the initial point:
import numpy as np
def get_point_on_vector(initial_pt, terminal_pt, distance):
v = np.array(initial_pt, dtype=float)
u = np.array(terminal_pt, dtype=float)
n = v - u
n /= np.linalg.norm(n, 2)
point = v - distance * n
return tuple(point)
Based on the excellent answer from #Theophile here on math stackexchange.
Let's call the point you are trying to find P, with coordinates px, py, and your starting point A's coordinates ax and ay. Slope m is just the ratio of the change in Y over the change in X, so if your point P is distance s from A, then its coordinates are px = ax + s, and py = ay + m * s. Now using Pythagoras, the distance d from A to P will be d = sqrt(s * s + (m * s) * (m * s)). To make P be a specific D units away from A, find s as s = D/sqrt(1 + m * m).
I thought this was an awesome and easy to understand solution:
http://www.physicsforums.com/showpost.php?s=f04d131386fbd83b7b5df27f8da84fa1&p=2822353&postcount=4