Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm not getting the required output i.e x2,y2,z2 in below code. Here the angle t is in degree, (x2,y2,z2) is the pint of vector face after being rotated and (a2,b2,c2) is the direction cosine of the rotated vector.I used rviz to visualize the rotating vector but its not comming as thought i.e its not rotating.
double xgp[ipgp] = 23, ygp[ipgp] = 45, zgp[ipgp] = 345; int ipgp = 0;
double a2, b2 , c2, a1, b1, c1 = ...
double la = 0.0032;
for(double t=0;t<360;t+=la)
{
double x2 = xgp[ipgp]+a2*cos(t)+a1*sin(t);
double y2 = ygp[ipgp]+b2*cos(t)+b1*sin(t);
double z2 = zgp[ipgp]+c2*cos(t)+c1*sin(t);
a2 = x2-xgp[ipgp]; // vector (xgp,ygp,zgp)->(x2,y2,z2)
b2 = y2-ygp[ipgp];
c2 = z2-zgp[ipgp];
int i = round(sqrt(pow(a2,2)+pow(b2,2)+pow(c2,2)));
std::cout<<i<<std::endl;
}
There are two issues with the code that you posted:
You did not specify how (a1,b1,c1) and (a2,b2,c2) are set. These need to be:
orthogonal to (xgp,ygp,zgp)
orthogonal to each other
unit vectors
In the loop, you reset (a2,b2,c2) to be the rotated unit vector. You can't do that and still maintain orthogonality between (a1,b1,c1) and (a2,b2,c2) for the next step of the loop. This is probably the main reason why your print out of i is not all 1's
The following code does what you intend
#include <iostream>
#include <math.h>
int main() {
double xgp = 23., ygp = 45., zgp = 345.;
// setting (a2,b2,c2) to be orthogonal to (xgp,ygp,zgp) with unit magnitude
double a2 = -45./sqrt(23.*23. + 45.*45.);
double b2 = 23./sqrt(23.*23. + 45.*45.);
double c2 = 0.;
// setting (a1,b1,c1) to be orthogonal to both (a2,b2,c2) and (xgp,ygp,zgp)
// using cross product (xgp,ygp,zgp) X (a2,b2,c2) with unit magnitude
double a1 = -23.*345./sqrt(23.*345.*23.*345. + 45.*345.*45.*345. + (23.*23. + 45.*45.)*(23.*23. + 45.*45.));
double b1 = -45.*345./sqrt(23.*345.*23.*345. + 45.*345.*45.*345. + (23.*23. + 45.*45.)*(23.*23. + 45.*45.));
double c1 = (23.*23. + 45.*45.)/sqrt(23.*345.*23.*345. + 45.*345.*45.*345. + (23.*23. + 45.*45.)*(23.*23. + 45.*45.));
double la = 0.0032;
for(double t=0;t<360;t+=la) {
double x2 = xgp+a2*cos(t)+a1*sin(t);
double y2 = ygp+b2*cos(t)+b1*sin(t);
double z2 = zgp+c2*cos(t)+c1*sin(t);
// cannot overwrite a2, b2, c2; otherwise (a2,b2,c2) is no longer orthogonal to (a1,b1,c1)!
double a3 = x2-xgp; // vector (xgp,ygp,zgp)->(x2,y2,z2)
double b3 = y2-ygp;
double c3 = z2-zgp;
// (a3,b3,c3) is a unit vector!
int i = round(sqrt(pow(a3,2)+pow(b3,2)+pow(c3,2)));
std::cout<<i<<std::endl;
}
return(0)
}
Note that rotating in units of degrees or radians does not matter in terms of your question. However, you should follow #Bob 's advice and make sure you know yourself what units you are intending.
Hope this helps.
Related
Sorry if this is the wrong place but I struggle a lot with the math and want to implement a circle fit in 3D using C++. I found lots of things in other programming languages but don't really understand whats going on there. Can anyone guide me on how to do that? I am not the best at math I would appreciate it if the explanation would be as simple as possible
What I tried (or tried to do lol) is as followed:
Get n points with x,y,z coordinates
fit a plane (which seems to fail)
project n points to 2d onto the fitted plane
fit a 2d circle
project the coordinates of the circle center back to 3d
I tried to use ordinary least squares for step 2 and also tested the results with eigens SVD which gave me completely different values compared to OSL. So I must be doing something completely wrong I guess.
Here is the code:
std::vector<Eigen::Vector4f> points;
Eigen::MatrixXf A(3,3);
Eigen::VectorXf b(3);
float a00 = 0;
float a01 = 0;
float a02 = 0;
float a10 = 0;
float a11 = 0;
float a12 = 0;
float a20 = 0;
float a21 = 0;
float a22 = 0;
float b0 = 0;
float b1 = 0;
float b2 = 0;
for (int i = 0; i < points.size(); i++) {
a00 += points[i].x() * points[i].x();
a01 += points[i].x() * points[i].y();
a02 += points[i].x();
a10 += points[i].x() * points[i].y();
a11 += points[i].y() * points[i].y();
a12 += points[i].y();
a20 += points[i].x();
a21 += points[i].y();
b0 += points[i].x() * points[i].z();
b1 += points[i].y() * points[i].z();
b2 += points[i].z();
}
A(0,0) = a00;
A(0, 1) = a01;
A(0, 2) = a02;
A(1,0) = a10;
A(1, 1) = a11;
A(1, 2) = a12;
A(2, 0) = a20;
A(2, 1) = a21;
A(2, 2) = points.size();
b(0) = b0;
b(1) = b1;
b(2) = b2;
auto leastsquaresOSL = (A.transpose() * A).ldlt().solve(A.transpose() * b);
auto leastsquaresSVD = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
EDIT: Someone suggested I edit my post and just focus on the plane fitting part. I will leave my original question up though. So here I go:
I have lots of points and want to fit a plane into it using Eigen::Vectors and Matrices. Then I would want to project the points onto the plane. I really don't know how to tackle this problem and most posts (if not all) were too complex and in Python or another language. If possible: Can anyone boil it down how to implement it in C++ using Eigen?
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
The problem states that given the radius of three circles, and assuming that three circles touch themselves in a way shown:
we need to find out the area of the blue portion between them. I have written the following code and run a few test cases. All of them worked fine. The online judge says the answer is wrong.
#include <iostream>
#include <math.h>
#include <iomanip>
using namespace std;
int main()
{
double r1, r2, r3, tarea, r1area, r2area, r3area;
long double res;
int i, test;
cin >> test;
for(i = 1;i <= test;i++)
{
cin >> r1 >> r2 >> r3;
tarea = sqrt(((r1 + r2 + r3)*r1*r2*r3));
r1area = 0.5*(r1*r1)*(asin((2*tarea)/((r1+r2)*(r1+r3))));
r2area = 0.5*(r2*r2)*(asin((2*tarea)/((r2+r3)*(r1+r3))));
r3area = 0.5*(r3*r3)*(asin((2*tarea)/((r1+r2)*(r2+r3))));
res = tarea - (r1area + r2area + r3area);
cout << "Case " << i << ": " << fixed << setprecision(8) << res << endl;
}
return 0;
}
The lack of simmetry in the formula is a strong evidence that something is wrong in the posted code, as shown in idclev 463035818's answer.
There's another mathematical issue, though, that may come up in the tests.
The code tries to implement the law of sines, in order to calculate the angles of the triangle formed by the centers of the circles. The problem is that when one of the radii is small enough, the corresponding angle in the triangle become obtuse and the chosen formula doesn't hold anymore.
Consider the documentation of std::asin, the returned value is in the range [-π/2, π/2], it can't represent an obtuse angle.
We could rewrite the formulas using the law of cosines (which doesn't have this issue) or we could just evaluate the greatest angle remembering that the three interior angles of a triangle add up to π.
#include <cmath>
#if __has_include(<numbers>)
# include <numbers>
#else
namespace std::numbers {
inline constexpr double pi = 3.14159265358979323846;
}
#endif
double area_circumscribed_by_circles(double r1, double r2, double r3)
{
// I want the third to have the smaller radius.
if (r1 < r2) {
if ( r1 < r3 )
std::swap(r1, r3);
} else {
if ( r2 < r3 )
std::swap(r2, r3);
}
if (r3 == 0.0)
return 0.0;
// Apply Heron's formula to find the area of the triangle
// formed by the centers of the circles.
double area = std::sqrt((r1 + r2 + r3) * r1 * r2 * r3);
// Find the first two angles using the law of sines.
double angle_1 = std::asin(2.0 * area / ((r1 + r2) * (r1 + r3)));
double angle_2 = std::asin(2.0 * area / ((r2 + r1) * (r2 + r3)));
// The third angle may be obtuse, we can't use the previous formula.
double angle_3 = std::numbers::pi - (angle_1 + angle_2);
// Now we can subtract the area of the sectors.
return area - 0.5 * (r1 * r1 * angle_1 + r2 * r2 * angle_2 + r3 * r3 * angle_3);
}
Look closely at the formulas:
r1area = 0.5*(r1*r1)*(asin((2*tarea)/((r1+r2)*(r1+r3))));
r2area = 0.5*(r2*r2)*(asin((2*tarea)/((r2+r3)*(r1+r3))));
r3area = 0.5*(r3*r3)*(asin((2*tarea)/((r1+r2)*(r2+r3))));
res = tarea - (r1area + r2area + r3area);
Without entering into the details of the maths I know that they cannot be correct. Why? Symmetry! The final result does not change if you permute the labeling of the circles. This is fine for the last line, because with
auto a = r1area;
auto b = r2area;
auto c = r3area;
all those expressions yield the same result:
res = tarea - (a + b + c);
res = tarea - (a + c + b);
res = tarea - (b + a + c);
res = tarea - (b + c + a);
....
Similarly you should get the same result for permutations of r1,r2 and r3 and this is not the case.
This
r1area = 0.5*(r1*r1)*(asin((2*tarea)/((r1+r2)*(r1+r3))));
can be rewritten as
r1area = calc_area( r1*r1, r1+r2, r1+r3);
or
Aarea = calc_area( A*A, A+B, A+C);
Because of the symmetry of the problem, it should be possible to get the forumla for Barea by permuting A,B and C, but if we swap A and B (those are just labels!) then we get
Barea = calc_area( B*B, B+A, B+C);
while you have:
r2area = 0.5*(r2*r2)*(asin((2*tarea)/((r2+r3)*(r1+r3))));
// ->
r2area = calc_area( r2*r2, r2+r3, r1+r3);
// ->
Barea = calc_area( B*B, B+C, A+C);
Note that the last parameter is B+C vs A+C, ie XArea has X+Y,X+Z in one case but X+Y,Y+Z in the other. Hence no permutation of the labels can make those formulas the same. However, the area between the circles will not change if you put different labels on the circles, ergo your formulas cannot be correct.
I can quite easily calculate the point of intersection given two lines. If I start with two vertices:
(x1,y1)
(x2,y2)
I can calculate the slope by doing (y1-y2)/(x1-x2), and then calculating the intercept
y1 - slope * x1
Then do that again, so I have to sets of slope and intercept, then just do:
x = (intercept2 - intercept1) / (slope1 - slope2)
y = slope1 * x + intercept1
(disclaimer: this might not even work, but i've gotten something very close to it to work, and it illustrates my general technique)
BUT that only works with data types with decimals, or non integral. Say the vertices are:
(0,1)
(10,2)
To calculate the slope would result in (1-2)/(0-10), which is -1/-10 which is not 1/10, it is 0.
How can I get code that yields a valid result using only integers?
Edit: I can't use floats AT ALL!. No casting, no nothing. Also, values are capped at 65535. And everything is unsigned.
In high school when subtracting fractions, our teachers taught us to find a common denominator
So 1/4 - 1/6 = 3/12 - 2/12 = 1/12
So do the same with your slopes.
int slope1 = n1 / d1; // numerator / denominator
int slope2 = n2 / d2;
// All divisions below should have 0 for remainder
int g = gcd( d1, d2 ); // gcd( 4, 6 ) = 2
int d = d1 * d2 / g; // common denominator (12 above)
int n = (d/d1) * n1 - (d/d2) * n2; // (1 in 1/12 above)
// n1/d1 - n2/d2 == n/d
I hope I got that right.
Hm..
(0,1)
(10,2)
and (y1-y2)/(x1-x2). Well, this is the description of one line, not the intersection of two lines.
As far as I remember lines are described in the form of x * v with x an skalar and v be a vector. Then it's
x * (0,1) = v2 and
x * (10, 2) = v2.
therefore the lines only intersect if exactly one solution to both equitions exist, overlap when there are infinitive numbers of solutions and don't intersect when they are parallel.
http://www.gamedev.net/topic/647810-intersection-point-of-two-vectors/
explains the calcuclation based on the dot - product.
Input: line L passing thru (x1, y1) and (x2, y2), and line M passing thru (X1, Y1) and (X2, Y2)
Output: (x, y) of the intersecting point of two lines L and M
Tell Wolfram Alpha to solve y = (y1-y2)/(x1-x2)*(x-x1)+y1 and y = (Y1-Y2)/(X1-X2)*(x-X1)+Y1 for x, y to get this solution:
http://www.wolframalpha.com/share/clip?f=d41d8cd98f00b204e9800998ecf8427e3at5u9evl8
But I have no idea on how to write a program to implement the above solution for your calculator with only uint16_t ALU.
Thanks to Graham Toal's answer, below is a primitive Rust implementation of the linked C code in their answer, modified to return the point of intersection for the complete line, as opposed to the line segment. It doesn't use much Rust-specific magic so should be reasonably easy to port to other languages.
The function returns a Point where the Lines intersect, if at all, and a flag denoting whether the intersection point lies on both intersected lines (true) or not (false).
/// 2D integer point
struct Point {
/// The x coordinate.
pub x: i32,
/// The y coordinate.
pub y: i32,
}
/// Line primitive
struct Line {
/// Start point
pub start: Point,
/// End point
pub end: Point,
}
/// Check signs of two signed numbers
///
/// Fastest ASM output compared to other methods. See: https://godbolt.org/z/zVx9cD
fn same_signs(a: i32, b: i32) -> bool {
a ^ b >= 0
}
/// Integer-only line segment intersection
///
/// If the point lies on both line segments, the second tuple argument will return `true`.
///
/// Inspired from https://stackoverflow.com/a/61485959/383609, which links to
/// https://webdocs.cs.ualberta.ca/~graphics/books/GraphicsGems/gemsii/xlines.c
fn intersection(l1: &Line, l2: &Line) -> Option<(Point, bool)> {
let Point { x: x1, y: y1 } = l1.start;
let Point { x: x2, y: y2 } = l1.end;
let Point { x: x3, y: y3 } = l2.start;
let Point { x: x4, y: y4 } = l2.end;
// First line coefficients where "a1 x + b1 y + c1 = 0"
let a1 = y2 - y1;
let b1 = x1 - x2;
let c1 = x2 * y1 - x1 * y2;
// Second line coefficients
let a2 = y4 - y3;
let b2 = x3 - x4;
let c2 = x4 * y3 - x3 * y4;
let denom = a1 * b2 - a2 * b1;
// Lines are colinear
if denom == 0 {
return None;
}
// Compute sign values
let r3 = a1 * x3 + b1 * y3 + c1;
let r4 = a1 * x4 + b1 * y4 + c1;
// Sign values for second line
let r1 = a2 * x1 + b2 * y1 + c2;
let r2 = a2 * x2 + b2 * y2 + c2;
// Flag denoting whether intersection point is on passed line segments. If this is false,
// the intersection occurs somewhere along the two mathematical, infinite lines instead.
//
// Check signs of r3 and r4. If both point 3 and point 4 lie on same side of line 1, the
// line segments do not intersect.
//
// Check signs of r1 and r2. If both point 1 and point 2 lie on same side of second line
// segment, the line segments do not intersect.
let is_on_segments = (r3 != 0 && r4 != 0 && same_signs(r3, r4))
|| (r1 != 0 && r2 != 0 && same_signs(r1, r2));
// If we got here, line segments intersect. Compute intersection point using method similar
// to that described here: http://paulbourke.net/geometry/pointlineplane/#i2l
// The denom/2 is to get rounding instead of truncating. It is added or subtracted to the
// numerator, depending upon the sign of the numerator.
let offset = if denom < 0 { -denom / 2 } else { denom / 2 };
let num = b1 * c2 - b2 * c1;
let x = if num < 0 { num - offset } else { num + offset } / denom;
let num = a2 * c1 - a1 * c2;
let y = if num < 0 { num - offset } else { num + offset } / denom;
Some((Point::new(x, y), is_on_segments))
}
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.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I am working with set of points, and my goal is to add 4 vectors together and calculate the resultant between start and end point,
Since I already prepared the code to do the above part which seems to be working fine but am not to sure about it.
Anyway the real reason I am posting this question is to do with the resultant direction and angle.
I find it hard to either understand the concept of finding resultant angle and direction as well as PROGRAMMING wise.
Consider this scenario....Image
1st add vectors "Head 2 Tail"
From what I have learned about vector addition is to subtract x2 - x1, y2 -y1 this will dive me the misplacement difference and do the same calculation for all the points from A-E
To get the resultant I square root all the points x to power of 2 and add all the y position to power of 2.
This ideology seem to work fine.....
But the QUESTION here is how do i get the angle and direction of that resultant....?
the code I use to calculate resultant:
double Pta;
double Ptb;
Point vect;
float R1, R2;
float resultant;
for(vector<Point>::iterator iter_a = Left_Arm_xy.begin()+1; iter_a != Left_Arm_xy.end(); ++iter_a)
{
if(center.y <= 240)
{
vect.x = iter_a->x - (iter_a -1)->x;
vect.y = iter_a->y - (iter_a -1)->y;
vect_add.push_back(Point(vect.x,vect.y));
for(vector<Point>::iterator iter_v = vect_add.begin(); iter_v - vect_add.begin() + 4 < vect_add.size(); iter_v+=4)
{
R1 = iter_v->x + (iter_v +1)->x + (iter_v +2)->x + (iter_v +3)->x;
R2 = iter_v->y + (iter_v +1)->y + (iter_v +2)->y + (iter_v +3)->y;
resultant = sqrt(pow(R1,2) + pow(R2,2));
}
}
Consider this..............
Ok lets consider Points A[2,4], B[4,8], C[10,12], To add this vectors i add vectors/points I subtract point B x4 - A x2 and point B y8 - A y4 and point C x10 - B x4 and point C y12 - B y8 this will give me the the displacements between points....Now to get the Resultant i add all the Points X's and Y's x's 2+4+10 = 16 y's 4+8+12 = 24, Next i would square root 16 ^2 + 24^2 = 28.84. So based on these calculations where resultant is a number not and x and y value how can i get the direction and angle....?
It is a simple summation of vectors.
(x, y) = (x1, y1) + (x2, y2) + ... = (x1+x2+..., y1+y2+...)
When you have the final vector, it's angle is found by using
tan(angle) = y/x
The angle between two vectors is generally defined as:
Angle = arccos( DotProduct(v1, v2) / ( Length(v1) * Length(v2) ) );
The direction is simply subtraction of the two vectors:
Direction = v2 - v1;
Usually, you have to normalize this to get a unit vector:
Len = SquareRoot( direction.x * direction.x + direction.y * direction.y );
Direction.x /= Len;
Direction.y /= Len;
Thus, you'll have a unit direction vector and the angle of the vector.