Check parallel lines in line-line collsion - c++

There are two lines defined by the coordinates of P1(x1, x2), P2(x2, x2) and so on.
How can you check if the two lines are parallel? On paper you could evaluate the value of den, when that is 0, the lines are parallel, but how can I do that in floating point arithmetics?
bool Tema1::lineLine(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
{
float den = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
float numA = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
float numB = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
float uA = numA / den;
float uB = numB / den;
return uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1;
}
If I try to compare a short line with one that's long, the den will still be pretty big.

Compare den with sum of squared length of both segments
float den = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
float cmp = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) +
(x4 - x3) * (x4 - x3) + (y4 - y3) * (y4 - y3);
if (abs(den)/cmp < 1e-10) //or another eps value
parallel

Related

How to Handle Corners in Segment Intersection Checks

I am creating a ray-casting simulation that uses ray-segment intersection checks. On the corners where two segments meet the code determines there is no intersection.
I have tried extending the segments a small distance but this causes other issues with the simulation. What can I do in this situation?
The code for the intersection check:
struct Point {
double x, y;
}
std::unique_ptr<Point> Ray::cast(const Boundary& wall) const {
const double x1 = wall.a.x;
const double y1 = wall.a.y;
const double x2 = wall.b.x;
const double y2 = wall.b.y;
const double x3 = pos.x;
const double y3 = pos.y;
const double x4 = pos.x + dir.x;
const double y4 = pos.y + dir.y;
const double den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (den == 0) {
return nullptr;
}
const double t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / den;
const double u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / den;
if ((t > 0.0f && t < 1.0f) && u > 0.0f) {
return std::make_unique<Point>(x1 + t * (x2 - x1), y1 + t * (y2 - y1));
}
else {
return nullptr;
}
}
Intersection Failure:
You need to include equal to check for when the float is zero:
if ((t >= 0.0f && t <= 1.0f) && u >= 0.0f) {
One standard answer is to define the question in terms of points’ relationship to the ray being cast. It is known how to partition the plane into non-overlapping regions that are “left of”, “right of”, and optionally “on” a line. (The last is optional because you can arbitrarily include it in one of the other two.) Then a ray hits a line segment if the two endpoints are in different regions.

Values for chaotic scattering simulation do not match with the base case

My first post on Stack Overflow, be gentle. I wrote a code to follow the position on the x,y plane of a particle of mass M on a potential V(r) described by a four-dimensional system of equations of motion
M(dv/dt)=-grad V(r), dr/dt=v,
Which are solved by using the Runge Kutta 4th Order method, where r=(x,y) and v=(vx,vy); now the state of the particle is defined by x, y and the angle theta between the vector v and the positive x-axis where the magnitude of the velocity is given by
|v|=sqrt(2(E-V(r))/M)
where E is the energy in the plane and the potential V(r) is given by
V(r)=x^2y^2exp[-(x^2+y^2)],
now here is the code I made for the initial values
x(0)=3,
y(0)=0.3905,
vx(0)=0,
vy(0)=-sqrt(2*(E-V(x(0), y(0)))),
where E=0.260*(1/exp(2))
// RK4
#include <iostream>
#include <cmath>
// constant global variables
const double M = 1.0;
const double DeltaT = 1.0;
// function declaration
double f0(double t, double y0, double y1, double y2, double y3); // derivative of y0
double f1(double t, double y0, double y1, double y2, double y3); // derivative of y1
double f2(double t, double y0, double y1, double y2, double y3); // derivative of y2
double f3(double t, double y0, double y1, double y2, double y3); // derivative of y3
void rk4(double t, double h, double &y0, double &y1, double &y2, double &y3); // method of runge kutta 4th order
double f(double y0, double y1); //function to use
int main(void)
{
double y0, y1, y2, y3, time, E, Em;
Em = (1.0/(exp(2.0)));
E = 0.260*Em;
y0 = 3.0; //x
y1 = 0.3905; //y
y2 = 0.0; //vx
y3 = -(std::sqrt((2.0*(E-f(3.0, 0.0)))/M)); //vy
for(time = 0.0; time <= 400.0; time += DeltaT)
{
std::cout << time << "\t\t" << y0 << "\t\t" << y1 << "\t\t" << y2 << "\t\t" << y3 << std::endl;
rk4(time, DeltaT, y0, y1, y2, y3);
}
return 0;
}
double f(double y0, double y1)
{
return y0*y0*y1*y1*(exp(-(y0*y0)-(y1*y1)));
}
double f0(double t, double y0, double y1, double y2, double y3)
{
return y2;
}
double f1(double t, double y0, double y1, double y2, double y3)
{
return y3;
}
double f2(double t, double y0, double y1, double y2, double y3)
{
return 2*y0*((y0*y0)-1)*(y1*y1)*(exp(-(y0*y0)-(y1*y1)))/M;
}
double f3(double t, double y0, double y1, double y2, double y3)
{
return 2*(y0*y0)*y1*((y1*y1)-1)*(exp(-(y0*y0)-(y1*y1)))/M;
}
void rk4(double t, double h, double &y0, double &y1, double &y2, double &y3) // method of runge kutta 4th order
{
double k10, k11, k12, k13, k20, k21, k22, k23, k30, k31, k32, k33, k40, k41, k42, k43;
k10 = h*f0(t, y0, y1, y2, y3);
k11 = h*f1(t, y0, y1, y2, y3);
k12 = h*f2(t, y0, y1, y2, y3);
k13 = h*f3(t, y0, y1, y2, y3);
k20 = h*f0(t+h/2, y0 + k10/2, y1 + k11/2, y2 + k12/2, y3 + k13/2);
k21 = h*f1(t+h/2, y0 + k10/2, y1 + k11/2, y2 + k12/2, y3 + k13/2);
k22 = h*f2(t+h/2, y0 + k10/2, y1 + k11/2, y2 + k12/2, y3 + k13/2);
k23 = h*f3(t+h/2, y0 + k10/2, y1 + k11/2, y2 + k12/2, y3 + k13/2);
k30 = h*f0(t+h/2, y0 + k20/2, y1 + k21/2, y2 + k22/2, y3 + k23/2);
k31 = h*f1(t+h/2, y0 + k20/2, y1 + k21/2, y2 + k22/2, y3 + k23/2);
k32 = h*f2(t+h/2, y0 + k20/2, y1 + k21/2, y2 + k22/2, y3 + k23/2);
k33 = h*f3(t+h/2, y0 + k20/2, y1 + k21/2, y2 + k22/2, y3 + k23/2);
k40 = h*f0(t + h, y0 + k30, y1 + k31, y2 + k32, y3 + k33);
k41 = h*f1(t + h, y0 + k30, y1 + k31, y2 + k32, y3 + k33);
k42 = h*f2(t + h, y0 + k30, y1 + k31, y2 + k32, y3 + k33);
k43 = h*f3(t + h, y0 + k30, y1 + k31, y2 + k32, y3 + k33);
y0 = y0 + (1.0/6.0)*(k10 + 2*k20 + 2*k30 + k40);
y1 = y1 + (1.0/6.0)*(k11 + 2*k21 + 2*k31 + k41);
y2 = y2 + (1.0/6.0)*(k12 + 2*k22 + 2*k32 + k42);
y3 = y3 + (1.0/6.0)*(k13 + 2*k23 + 2*k33 + k43);
}
The problem here is that when I run the code with the initial conditions given, the values do not match with what it is supposed to according to the case given by the problem
what the graphic should look like with the initial conditions given
now, I think i got right the implementation of the method but i do not know why the graphs do not match because when i run the code the particle goes away from the potential.
Any help will be appreciated.
The paths look chaotic with sharp turns. This requires an adaptive step size, you will need to implement some step size control. Either by comparing each step with two steps of half the step length or by using a method with embedded methods of higher order like Fehlberg or Dormand-Price.
More immediate errors:
define Em as V(1,1) to avoid unnecessary magic numbers
your initial position is, if you read the chart right,
y0 = 3.0;
y1 = -0.3905+k*0.0010;
with k=-1,0,1, note the minus sign.
your initial velocity is horizontal, and the kinetic energy is computed to complement the potential energy at that position. Thus
y2 = v0 = -(std::sqrt((2.0*(E-V(y0, y1)))/M));
y3 = v1 = 0.0;
With these changes and an adaptive solver I get (in python) the plot
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# capture the structure of the potential
f = lambda r : r*np.exp(-r);
df = lambda r : (1-r)*np.exp(-r);
V = lambda y1,y2 : f(y1*y1)*f(y2*y2);
M= 1.0
Em = V(1.0,1.0);
E = 0.260*Em;
def prime(t,y):
x1,x2,v1,v2 = y
dV_dx1 = 2*x1*df(x1*x1)*f(x2*x2);
dV_dx2 = 2*x2*df(x2*x2)*f(x1*x1);
return [ v1, v2, -dV_dx1/M, -dV_dx2/M ];
# prepare and draw the contour plot
X1,X0=np.ogrid[-4:3:100j,-4:3:100j]
plt.contour(X0.ravel(), X1.ravel(), V(X0,X1), Em*np.arange(0,1,0.1), colors='k', linewidths=0.3)
# display grid and fix the coordinate ranges
plt.grid();plt.autoscale(False)
for k in range(-1,1+1):
x01 = 3.0;
x02 = b = -0.3905 + 0.0010*k;
v01 = -( ( E-V(x01,x02) )*2.0/M )**0.5;
v02 = 0.0;
print "initial position (%.4f, %.4f), initial velocity (%.4f, %.4f)" % ( x01, x02, v01, v02 )
t0 = 0.0
tf = 50.0
tol = 1e-10
y0 = [ x01, x02, v01, v02 ]
t = np.linspace(t0,tf,501); y = odeint(lambda y,t: prime(t,y) , y0, t)
plt.plot(y[:,0], y[:,1], label="b=%.4f" % b, linewidth=2)
plt.legend(loc='best')
plt.show()

Returning Division in C++ Unit Test incorrectly coming back as 0

I am unit testing a C++ function using the built is Visual Studio 2015 framework. However, the test is failing and saying the actual value is 0. If I return (y2 - y1), then I get a value of 99. If I return (x2 - x1), I get 86400, but if I return (y2 - y1) / (x2 - x1) I get zero. Why is this? Do I need to do something to the Assert::AreEqual() to tell it to deal with floats? Even if I do the division in a float and then return the variable, I still get zero?
float averageGradient(int x1, int x2) {
//do some maths, the result of which: y1=-39, y2= 60, x1=683675, x2=770075
float m = (y2 - y1) / (x2 - x1);
return (y2 - y1) / (x2 - x1);
}
I am calling this with the following Unit Test:
TEST_METHOD(Average_Gradient) {
int x1 = 683675;
int x2 = x1 + 86400;
float gradient = averageGradient(x1, x2);
float answer = 0.001145833;
Assert::AreEqual(answer, gradient);
}
Even if I do the division in a float and then return the variable, I still get zero?
That's not what you're doing.
float averageGradient(int x1, int x2) {
//do some maths, the result of which: y1=-39, y2= 60, x1=683675, x2=770075
float m = (y2 - y1) / (x2 - x1);
return (y2 - y1) / (x2 - x1);
}
First does the division on the ints and assigns the result (0) to a float. Then you do the division on ints again and return that.
The result of integer division just truncates it and gives an int as result as well. You gotta cast at least 1 argument to float before doing the division if you want to get a float as result:
float averageGradient(int x1, int x2) {
//do some maths, the result of which: y1=-39, y2= 60, x1=683675, x2=770075
float m = (y2 - y1) / (float)(x2 - x1);
return m;
}
should do it.
Also where are you getting y1 and y2 from as you aren't taking them as arguments? Are those global variables?
You should be returning the m variable you declared as a float rather than the calculation. Your return should say simply: return m;

C++ Get Point on 3D Vector with Shortest Distance to given Point

I have given a 3D Line which is represented with two 3D Vectors (start-, endpoint), all in C++
vec3 x1 = [x,y,z]
vec3 x2 = [x,y,z]
also i have a 3D Point
vec3 x0 = [x,y,z]
I want to find the Point p which has the shortest distance d to my Point x0 from my given line.
Here's an image as an example:
Thanks for your help!
Take the equation of your line
p = x1 + t (x2 - x1)
The closest point p is such that the vector x0 - p is perpendicular to the line. (You can prove this with Pythagoras / elementary calculus).
Therefore you need
(p - x0) . (x2 - x1) = 0
where . is the dot product.
(x1 - x0 + t (x2 - x1)) . (x2 - x1) = 0
t = - [ (x1 - x0) . (x2 - x1) ] / |x2 - x1|^2
where |x2 - x1| is the magnitude.
Plug this into the first equation to find the p you want.
(PS sorry I couldn't format the equations)
You could project the vector x1->x0 onto the vector x1->x2, and then your point p will be x1 + projected vector. Something like this:
if (x1 == x2)
return x1;
vector x1x0 = x0 - x1;
vector x1x2 = x2 - x1;
float t = x1x0.dot(x1x2) / x1x2.SquaredLength();
if (t <= 0.0)
return x1;
else if(t >= 1.0)
return x2;
else
return x1 + t * x1x2;

Drawing line perpendicular to a given line

I have start and end coordinate of a line. I want to drawn another line sticking at the end of this this such that they will be perpendicular to each other.
I am trying to do this using the normal geometry. Is there any high-level API there in MFC for the same.
Thanks
If (dx,dy) are the differences in the x and y coodinates of the given line, you can make another line perpendicular by contriving for the differences in its coordinates to be (-dy, dx). You can scale that by any factor (-c*dy, c*dx) to change its length.
You have an existing line (x1, y1) to (x2, y2). The perpendicular line is (a1, b1) to (a2, b2), and centered on (x2, y2).
xdif = x2 - x1
ydif = y2 - y1
a1 = x2 - ydif / 2
b1 = y2 + xdif / 2
a2 = x2 + ydif / 2
b2 = y2 - xdif / 2
I think that works... I tested it for a few lines.
So if you have a line going from (1,1) to (5,3), the perpendicular line would be (5 - 2/2, 3+4/2) to (5 + 2/2, 3 - 4/2) or (4,5) to (6, 1).
You could use SetWorldTransform function from Win32 GDI API.
Sample code is here.
Let me add some c++ code based on kbelder answer. It make one vertex by origin point (x1,y1) and another vertex (x2,y2)
float GetDistance(float x1, float y1, float x2, float y2)
{
float cx = x2 - x1;
float cy = y2 - y1;
float flen = sqrtf((float)(cx*cx + cy*cy));
return flen;
}
void GetAxePoint(double x1, double y1, double x2, double y2, double& x3, double& y3, double vec_len, bool second_is_y)
{
double xdif = x2 - x1;
double ydif = y2 - y1;
if(second_is_y)
{
x3 = x1 - ydif;
y3 = y1 + xdif;
}
else
{
x3 = x1 + ydif;
y3 = y1 - xdif;
}
double vec3_len = GetDistance(x3, y3, x1, y1);
x3 = (x3-x1)/vec3_len;
y3 = (y3-y1)/vec3_len;
x3 = x1 + x3*vec_len;
y3 = y1 + y3*vec_len;
}