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;
}
Related
How can I draw a line starting from one point in the direction of the angle between the points?
This is what I have for calculating the angle
double angle1 = atan2(point_1_y - point_2_y, point_3_x - point_2_x);
double angle2 = atan2(point_1_y - point_3_y, point_3_x - point_2_x);
double result = angle1 - angle2;
First write a function to normalise a vector:
double mag = sqrt(x*x + y*y);
x = x/mag;
y = y/mag;
(I don't know what language you use, so I don't know the syntax of a function.)
Then apply it to the two vectors:
double x1 = point_C_x - point_A_x;
double y1 = point_C_y - point_A_y;
normalise(x1, y1);
double x2 = point_B_x - point_A_x;
double y2 = point_B_y - point_A_y;
normalise(x2, y2);
Then add them to get a green vector, then use atan2:
double x_green = x1+x2;
double y_green = y1+y2;
double d = atan2(y_green, x_green);
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()
I am attempting to calculate the point of intersection between lines for a Optical Flow algorithm using a Hough Transform. However, I am not getting the points that I should be when I use my algorithm for calculating the intersections.
I save the Lines as an instance of a class that I created called ImageLine. Here is the code for my intersection method.
Point ImageLine::intersectionWith(ImageLine other)
{
float A2 = other.Y2() - other.Y1();
float B2 = other.X2() - other.X1();
float C2 = A2*other.X1() + B2*other.Y1();
float A1 = y2 - y1;
float B1 = x2 - x1;
float C1 = A1 * x1 + B1 * y1;
float det = A1*B2 - A2*B1;
if (det == 0)
{
return Point(-1,-1);
}
Point d = Point((B2 * C1 - B1 * C2) / det, -(A1 * C2 - A2 * C1) / det);
return d;
}
Is this method correct, or did I do something wrong? As far as I can tell, it should work, as it does for a single point that I hard-coded through, however, I have not been able to get a good intersection when using real data.
Considering the maths side: if we have two line equations:
y = m1 * x + c1
y = m2 * x + c2
The point of intersection: (X , Y), of two lines described by the following equations:
Y = m1 * X + c1
Y = m2 * X + c2
is the point which satisfies both equation, i.e.:
m1 * X + c1 = m2 * X + c2
(Y - c1) / m1 = (Y - c2) / m2
thus the point of intersection coordinates are:
intersectionX = (c2 - c1) / (m1 - m2)
intersectionY = (m1*c1 - c2*m2) / m1-m2 or intersectionY = m1 * intersectionX + c1
Note: c1, m1 and c2, m2 are calculated by getting any 2 points of a line and putting them in the line equations.
(det == 0) is unlikely to be true when you're using floating-point arithmetic, because it isn't precise.
Something like (fabs(det) < epsilon) is commonly used, for some suitable value of epsilon (say, 1e-6).
If that doesn't fix it, show some actual numbers, along with the expected result and the actual result.
For detailed formula, please go to this page.
But I love code so, here, check this code (I get it from github, so all credit goes to the author of that code):
///Calculate intersection of two lines.
///\return true if found, false if not found or error
bool LineLineIntersect(double x1, double y1, //Line 1 start
double x2, double y2, //Line 1 end
double x3, double y3, //Line 2 start
double x4, double y4, //Line 2 end
double &ixOut, double &iyOut) //Output
{
//http://mathworld.wolfram.com/Line-LineIntersection.html
double detL1 = Det(x1, y1, x2, y2);
double detL2 = Det(x3, y3, x4, y4);
double x1mx2 = x1 - x2;
double x3mx4 = x3 - x4;
double y1my2 = y1 - y2;
double y3my4 = y3 - y4;
double xnom = Det(detL1, x1mx2, detL2, x3mx4);
double ynom = Det(detL1, y1my2, detL2, y3my4);
double denom = Det(x1mx2, y1my2, x3mx4, y3my4);
if(denom == 0.0)//Lines don't seem to cross
{
ixOut = NAN;
iyOut = NAN;
return false;
}
ixOut = xnom / denom;
iyOut = ynom / denom;
if(!isfinite(ixOut) || !isfinite(iyOut)) //Probably a numerical issue
return false;
return true; //All OK
}
Assuming your formulas are correct, try declaring all your intermediate arguments as 'double'. Taking the difference of nearly parallel lines could result in your products being very close to each other, so 'float' may not preserve enough precision.
This question has been answered. Below is most of the code that you need to make it work! Hope it helps others.
Thanks to #Aki Suihkonen, #David Hammen, and #MBo.
Both Angle functions give the right answer.
I have three points:
A: 12 4 5
B: 6 8 -10
C: 5 6 7
I have implemented quaternions. I want to rotate point C so that Angle( A, B, C ) would be 40 degrees higher than before.
My question is: According to which axis do I have to rotate? I imagined that because A,B, and C create a plane I have to rotate point C according to the perpendicular axis to the vectors BA and BC. I obtained it with the CrossProduct of their unit vectors but when I try to get the Angle( A, B, C ) it does not give me the right result.
This is how I get the angle: (The old way)
results:
Angle of ABC before rotation = 67.3895.
Angle of ABC after rotation = 107.389.
float Angle( float x1, float y1, float z1,
float x2, float y2, float z2 )
{
float x, y, z;
CrossProduct( x1, y1, z1, x2, y2, z2, &x, &y, &z );
float result = atan2 ( L2Norm( x, y, z ),
DotProduct( x1, y1, z1, x2, y2, z2 ) );
return result;
}
Where the x1, y1, z1, x2, y2, z2 are the results from the unit vectors B-A and B-C.
Updated angle function:
results:
Angle of ABC before rotation = 67.3895.
Angle of ABC after rotation = 107.389.
Angle( Atom &atom1, Atom &atom2, Atom &atom3 )
{
float px1, py1, pz1;
float px2, py2, pz2;
UnitVector( atom1.X(), atom1.Y(), atom1.Z(),
atom2.X(), atom2.Y(), atom2.Z(),
&px1, &py1, &pz1 );
UnitVector( atom3.X(), atom3.Y(), atom3.Z(),
atom2.X(), atom2.Y(), atom2.Z(),
&px2, &py2, &pz2 );
float dot_product = DotProduct( px1, py1, pz1, px2, py2, pz2 );
float length_BA = sqrt( px1*px1 + py1*py1 + pz1*pz1 );
float length_BC = sqrt( px2*px2 + py2*py2 + pz2*pz2 );
return acos( dot_product / ( length_BA * length_BC ) );
}
float DotProduct( float x1, float y1, float z1,
float x2, float y2, float z2 )
{
return x1*x2 + y1*y2 + z1*z2;
}
void CrossProduct( float x1, float y1, float z1,
float x2, float y2, float z2,
float *ox, float *oy, float *oz )
{
*ox = (y1*z2) -(z1*y2);
*oy = -((x1*z2) -(z1*x2));
*oz = (x1*y2) -(y1*x2);
}
So my question is: According to which axis do I have to rotate point C so that Angle(A,B,C) would be 40 degrees larger than before?
// The 3 points.
Atom A( "A", -4, 2 , 8 );
Atom B( "B", -1, 3 , 4 );
Atom C( "C", -2, -4 , 5 );
float x1, y1, z1;
float x2, y2, z2;
float x, y, z;
// Get the cross product. Create the perpendicular vector to the BA and BC vectors.
PointVector( A.X(), A.Y(), A.Z(), B.X(), B.Y(), B.Z(), &x1, &y1, &z1 );
PointVector( C.X(), C.Y(), C.Z(), B.X(), B.Y(), B.Z(), &x2, &y2, &z2 );
CrossProduct( x1, y1, z1, x2, y2, z2, &x, &y, &z );
// Normalize the coordinates.
float length = sqrt( x*x + y*y + z*z );
length = 1.0 / length;
x *= length;
y *= length;
z *= length;
// Create the 40 degrees angle. It is supposed to increment the current ABC angle by 40 degrees.
float angle = 40*M_PI/180;
float sinAngleOver2 = sin(angle/2);
float w = cos(angle/2);
// Create the axis quat.
Quatd q(w, x * sinAngleOver2, y * sinAngleOver2, z * sinAngleOver2);
// Create the point quaternal. The angle of it equals to the current ABC angle.
angle = Angle( A, B, C ) *180/M_PI;
angle *= M_PI/180;
sinAngleOver2 = sin(angle/2);
w = cos(angle/2);
// Normalize the coordinates. The coordinates are the C point coordinates.
x = C.X() - B.X();
y = C.Y() - B.Y();
z = C.Z() - B.Z();
length = sqrt( x*x + y*y + z*z );
length = 1.0 / length;
x *= length;
y *= length;
z *= length;
Quatd qpt(w, x * sinAngleOver2, y * sinAngleOver2, z * sinAngleOver2);
// Rotate.
qpt = q*qpt*q.unitInverse();
Atom new_C;
new_C.X( qpt.x + B.X() );
new_C.Y( qpt.y + B.Y() );
new_C.Z( qpt.z + B.Z() );
cout << "Angle: " << Angle( A, B, new_C )*180/M_PI << '\n';
This code is incorrect:
// Normalize the coordinates. The coordinates are the C point coordinates.
length = sqrt( C.X()*C.X() + C.Y()*C.Y() + C.Z()*C.Z() );
length = 1.0 / length;
x = C.X() / length;
y = C.Y() / length;
z = C.Z() / length;
You've confused yourself by reusing your length variable to store 1 / length. You need to multiply the components of C by length to normalize your vector here.
I'm not familiar enough with quaternion maths to understand what you are trying to do at the end, but it does seem like you are rotating C around the origin. You want to rotate around B, which would mean subtracting B from C, performing your rotation around the origin, and then adding B onto the result to get back into your original space.
Personally, I would implement some kind of quaternion-vector multiplication, or convert the quaternion to a matrix in order to perform the transformation.
I have a small question about 3D.
What follows is an example of my problem.
I have two points:
A: 12 4 5
B: 6 8 -10
I have another point:
C: 5 6 7
I need to transform(?) point C so that the angle ABC is 48 degrees.
How do I do this? I would appreciate if someone can help me with the formulas or maybe even make the above example into a working one.
Another way to put it: How do I transform C.x, C.y, and C.z so that the angle ABC is 48 degrees?
I would really appreciate some help on this as I am stuck at the moment.
Side note:
I already implemented a method for finding the angle:
float Angle( float x1, float y1, float z1,
float x2, float y2, float z2 )
{
float x, y, z;
CrossProduct( x1, y1, z1, x2, y2, z2, &x, &y, &z );
float result = atan2 ( L2Norm( x, y, z ),
DotProduct( x1, y1, z1, x2, y2, z2 ) );
return result;
}
You use it:
Angle( B.x - A.x, B.y - A.y, B.z - A.z,
C.x - B.x, C.y - B.y, C.z - B.z );
A------C
|
c'' | c'
B
As three point in 3D define a plane, there are only 2 possible candidates for a transform C-->c' or C-->c'' at that plane.
c' would be then c' = A+t*(B-A) + u*(C-A) with constraint Normalize(c'-A) dot Normalize(B-A) == cos (48 / 180 * pi).
I'd first suggest normalizing D=(B-A), after that:
D dot D+u*(C-A) = 1 * |D+u(C-A)| * cos (48 degrees)
Dx*(Dx+u*(Cx-Ax))+ Dy*(Dy+u*(Cy-Ay))+Dz*(Dz+u*(Cz-Az)) ==
0.669 * sqrt ((Dx+u*(Cx-Ax))^2+(Dy+u*(Cy-Ay))^2+(Dz+u*(Cz-Az))^2)
This is of form a+u*b == 0.669*sqrt(c+du+e*u^2), which will be simplified to a second degree polynomial in u by squaring both sides.
The track of point C is actually a cone, you can imagine, B is the vertex and line AB is the central line of the cone, means the 3D cone is symmetric on AB.