Calculating the minimum translation to seperate two lines - c++

Given two intersecting line segments(AB and CD) in R2 find the translation with the smallest magnitude to apply to CD so that it is no longer intersecting AB.
What I've tried. I calculate the distance from each point on each line to the opposite line. Then I pick the smallest of the 4 values and apply that to the perpendicular of the line. However, the translation I calculate is often in the wrong direction. How do I fix this?
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <iterator>
class Vector2
{
public:
double x;
double y;
Vector2() : x(x), y(y) {}
Vector2(double x, double y) : x(x), y(y) {}
Vector2 operator*(double val) { return Vector2(x*val, y*val);}
Vector2 operator/(double val) { return Vector2(x/val, y/val);}
Vector2 operator+(Vector2 &v) { return Vector2(x+v.x, y+v.y);}
Vector2 operator-(Vector2 &v) { return Vector2(x-v.x, y-v.y);}
Vector2 Perpendicular() { return Vector2(y, -x); }
double Dot( Vector2 &v) {return (x * v.x) + (y * v.y); }
double Magnitude() { return std::sqrt(Dot(*this)); }
Vector2 Normal() { return *this / Magnitude(); }
double GetDistance( Vector2 &v) { Vector2 d = *this - v; return d.Magnitude(); }
};
class Line
{
public:
Line() : a(Vector2()), b(Vector2()) {}
Line( Vector2 a, Vector2 b) : a(a), b(b) {};
double DistanceFromPoint( Vector2 &p) ;
Vector2 GetTranslation( Line &l) ;
Vector2& GetPoint(unsigned i) {if (i==0) return a; else return b;}
double GetLength() { return GetPoint(0).GetDistance(GetPoint(1)); }
Vector2 a;
Vector2 b;
};
double Line::DistanceFromPoint( Vector2 &p)
{
double l2 = GetLength() * GetLength();
Vector2 pv = p - GetPoint(0);
Vector2 wv = GetPoint(1) - GetPoint(0);
double t = std::max(0.d, std::min(1.d, pv.Dot(wv) / l2));
Vector2 projection = (wv * t) + GetPoint(0);
return p.GetDistance(projection);
}
Vector2 Line::GetTranslation( Line &l)
{
// Calculate Distances from each point to rthe opposite line
std::vector<double> dist(4);
dist[0] = DistanceFromPoint(l.GetPoint(0));
dist[1] = DistanceFromPoint(l.GetPoint(1));
dist[2] = l.DistanceFromPoint(GetPoint(0));
dist[3] = l.DistanceFromPoint(GetPoint(1));
//Get the smallest distance
auto it = std::min_element(std::begin(dist), std::end(dist));
double min = *it;
unsigned pos = std::distance(std::begin(dist), it);
// Get the normalized perpendicular of line
Vector2 axis;
if (pos == 2 || pos == 3)
axis = (GetPoint(1) - GetPoint(0)).Perpendicular().Normal();
else
axis = (l.GetPoint(1) - l.GetPoint(0)).Perpendicular().Normal();
std::cout << "min: " << min << std::endl;
std::cout << "axis: (" << axis.x << "," << axis.y << ")" << std::endl;
//Apply that min to the perpendicular
return axis * min;
}
int main()
{
Line A;
Line B;
Vector2 t;
std::cout << "Left" << std::endl;
A = Line(Vector2(0, 4), Vector2(8, 4));
B = Line(Vector2(2, 0), Vector2(2, 6));
t = A.GetTranslation(B);
std::cout << "Expected: (-2, 0)" << std::endl;
std::cout << "Got: (" << t.x << "," << t.y << ")" << std::endl << std::endl;
std::cout << "Right" << std::endl;
B = Line(Vector2(6, 0), Vector2(6, 6));
t = A.GetTranslation(B);
std::cout << "Expected: (2, 0)" << std::endl;
std::cout << "translation: (" << t.x << "," << t.y << ")" << std::endl << std::endl;
std::cout << "Top" << std::endl;
B = Line(Vector2(4, 0), Vector2(4, 6));
t = A.GetTranslation(B);
std::cout << "Expected: (0, -2)" << std::endl;
std::cout << "translation: (" << t.x << "," << t.y << ")" << std::endl << std::endl;
std::cout << "Bottom" << std::endl;
B = Line(Vector2(4, 6), Vector2(4, 8));
t = A.GetTranslation(B);
std::cout << "Expected: (0, -2)" << std::endl;
std::cout << "translation: (" << t.x << "," << t.y << ")" << std::endl;
}

Your idea will work. You only need to have a signed distance function like #Tommy mentioned. Also, note that you will have to get the right perpendicular direction as well, depending on your sign conventions in the distance function.
Here is a demo

You've got the right approach. From reasoning about the Minkowski sum, the shortest vector of separation will be perpendicular to one of the lines and will be just long enough to push one of the endpoints to the surface of the other line.
However your DistanceFromPoint returns an unsigned distance: it's always zero or positive. You then use a single perpendicular per line to multiply that by. So you should end up going the wrong way 50% of the time because your distance has no sign.
You might prefer to rearrange, not least because it'll save some of your square roots:
get the two axes;
for each line, project the vector from any point on the line to each endpoint of the other line onto that line's axis. This produces a signed result;
pick the shortest of those results by magnitude;
calculate the separation axis as the negative of the shortest number times the axis it was calculated on.
... because if you're embedded by n units along axis q then the way to resolve that is to move -n units along q; so pick the least n.

Related

Need help utilizing two classes in one function,

So basically I created two classes for two vectors and got there norms. How would I approach using both classes to find the distance between both vectors in my main function ? I know I can use the friend function but we have not been taught that in class so I have to use the scope :: operator and constructor and destructors. I been trying different things but nothing works any ideas ? I am fairly new to c++.
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
class Vector {
private:
float x;
float y;
float z;
public:
Vector(float xaxis, float yaxis, float zaxis)
{
x = xaxis;
y = yaxis;
z = zaxis;
}
float getx() { return x; }
float gety() { return y; }
float getz() { return z; }
float normVector()
{
float result = sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2));
return result;
}
};
class Vectortwo {
private:
float x;
float y;
float z;
public:
Vectortwo(float xaxis, float yaxis, float zaxis)
{
x = xaxis;
y = yaxis;
z = zaxis;
}
float getx() { return x; }
float gety() { return y; }
float getz() { return z; }
float normVectortwo()
{
float result = sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2));
return result;
}
};
int main()
{
Vector v(2, 2, 2);
v.getx();
v.gety();
v.getz();
v.normVector();
cout << " X axis" << v.getx() << endl;
cout << " Y axis" << v.gety() << endl;
cout << " Z axis" << v.getz() << endl;
cout << " The norm of our first vector " << v.normVector() << endl;
Vectortwo b(3, 3, 3);
b.getx();
b.gety();
b.getz();
b.normVectortwo();
cout << " X axis" << b.getx() << endl;
cout << " Y axis" << b.gety() << endl;
cout << " Z axis" << b.getz() << endl;
cout << " The norm of our first vector " << b.normVectortwo() << endl;
return 0;
}
I know I can use the friend function but we have not been taught that in class [...]
You can always use getx(), gety() and getz() directly to calculate the distance. Since this gets a bit tiresome to write more than once you can write a little function that wraps the calculation:
float distance(Vector v1, Vectortwo v2)
{
return sqrt(
pow(v1.getx() - v2.getx(), 2)
+ pow(v1.gety() - v2.gety(), 2)
+ pow(v1.getz() - v2.getz(), 2)
);
}
It has to be declared before main() (but after Vector and Vectortwo) and could be used like this:
cout << "The distance is " << distance(v, b) << " units." << endl;
Since you somehow declared to vector classes Vector and Vectortwo that are basically identical (apart from the name), you can also just remove Vectortwo and use Vector for both instances, v and b. That would simplify the code and both parameters of the distance() function could be of type Vector.

How to print two coordinates from class?

I have been trying to print the points like The position of the point is (1,2) from using class, but I can't figure out a way to do it. I simply can't find a way to return two numbers like that, but the problem requires solution that way.
#include <iostream>
using namespace std;
class MyPoint{
public:
int x,y,radius;
MyPoint()
{
x=0;
y=0;
}
MyPoint(int x1,int y1)
{
x=x1;
y=y1;
}
int point_display()
{
char st=(x,y);
return st;
}
int getAdd()
{
return x+y;
}
};
int main()
{
MyPoint mypoint;
cin>>mypoint.x>>mypoint.y;
cout<<"The position of the point is "<<mypoint.point_display()<<endl;
cout<<"The sum of the coordinates is "<<mypoint.getAdd()<<endl;
return 0;
}
The usual solution to this is to provide an overload of operator << for class MyPoint to print the point.
Something like this:
#include <iostream>
using namespace std;
class MyPoint{
public:
int x,y,radius;
MyPoint()
{
x=0;
y=0;
}
MyPoint(int x1,int y1)
{
x=x1;
y=y1;
}
int getAdd()
{
return x+y;
}
friend ostream& operator << (ostream& os, const MyPoint& p);
};
ostream& operator << (ostream& os, const MyPoint& p)
{
os << p.x << ", " << p.y;
return os;
}
int main()
{
MyPoint mypoint { 1,2 };
cout<<"The position of the point is "<<mypoint<<endl;
cout<<"The sum of the coordinates is "<<mypoint.getAdd()<<endl;
return 0;
}
Output:
The position of the point is 1, 2
The sum of the coordinates is 3
Live demo
Your point_display could return a string composed of the 2 values:
std::string point_display()
{
return std::string{"("} + std::to_string(x)
+ "," + std::to_string(x) + ")";
}
Alternatively, as your question asks about returning 2 values, the function could return a pair:
std::pair<int,int> point_display ()
{
return {x,y};
}
and in main, you could do:
auto [x, y] = mypoint.point_display();
cout << "The position of the point is ("
<< x << "," << y << ")" << endl;
However, since the data members are public, you could just destructure the object and print out the values in main:
auto [x, y, radius] = mypoint;
cout << "The position of the point is ("
<< x << "," << y << ")" << endl;
If all you want to do is print the coordinates, you could have the method do it:
void point_display()
{
cout << "(" << x << ", " << y << ")";
}
...
cout<<"The position of the point is ";
mypoint.point_display();
cout << endl;
If you really want to return the coordinates, you could have separate accessors ("getters"):
int getX()
{
return x;
}
int getY()
{
return y;
}
or use references:
void getCoordinates(int &rx, int &ry)
{
rx = x;
ry = y;
}
...
int a, b;
mypoint.getCoordinates(a, b);
cout << a << " " << b << endl;

Coordinate conversion in c++

I am trying to convert different coordinate systems. From polar to rectangular and vice versa. My pol_to_rect()function is not working properly. It is giving very small values(~10^(-44)) after converting and also before converting. There might be some problem while using the sin() and cos() functions. The rect_to_pol() is working fine for positive values.
Edit - When I changed atan() to atan2() how can I incorporate other values of x and y.
#include <iostream>
#include <cmath>
using namespace std;
#define PI 3.1415926
class Polar; // Forward declaration
class Rectangular {
private:
float x, y;
public:
Rectangular() {} // default constructor
Rectangular(float mv_x, float mv_y) {
x = mv_x;
y = mv_y;
}
void showData() const;
Polar rect_to_pol();
float& get_x() {
return x;
}
float& get_y() {
return y;
}
};
void Rectangular::showData() const {
cout << "--Rectangular--" << endl;
cout << "x: " << x << "\t" <<"y: " << y << endl;
}
class Polar {
private:
float r;
float theta;
public:
Polar() {} // default constructor
Polar(float mv_r, float mv_theta) {
r = mv_r;
theta = mv_theta;
}
void showData();
Rectangular pol_to_rect();
float& get_r(){
return r;
}
float& get_theta() {
return theta;
}
};
void Polar::showData() {
cout << "--Polar--" << endl;
cout << "r:" << r << "\t" << "Theta(Radians):" << theta << endl;
}
Rectangular Polar::pol_to_rect() {
Rectangular temp;
temp.get_x() = r * cos(theta*(PI/180.0)); // in degrees
temp.get_y() = r * sin(theta*(PI/180.0));
return temp;
}
Polar Rectangular::rect_to_pol() {
Polar temp;
temp.get_r() = sqrt(pow(x, 2) + pow(y, 2));
temp.get_theta() = atan2(y, x);
return temp;
}
int main()
{
Rectangular r1(-1, -1), r2;
Polar p1(12.0, 30.0), p2;
r1.showData();
p2 = r1.rect_to_pol();
cout << "After Conversion (RECT TO POLAR)->" << endl;
p2.showData();
p1.showData();
r2 = p1.pol_to_rect();
cout << "After Conversion (POLAR TO RECT)" << endl;
r2.showData();
return 0;
}

apply_visitor does not change object

I have inherited from boost::static_visitor<> and defined a class as follows:
class move_visitor : public boost::static_visitor<> {
private:
double m_dx, m_dy;
public:
move_visitor() : m_dx(0.0), m_dy(0.0) {}
move_visitor(double dx, double dy) : m_dx(dx), m_dy(dy) {}
~move_visitor() {}
void operator () (Point &p) const {
p.X(p.X() + m_dx);
p.Y(p.Y() + m_dy);
}
void operator () (Circle &c) const {
Point center_point(c.CentrePoint().X() + m_dx, c.CentrePoint().Y() + m_dy);
c.CentrePoint(center_point);
}
void operator() (Line &l) const {
Point start(l.Start().X() + m_dx, l.Start().Y() + m_dy),
end(l.End().X() + m_dx, l.End().Y() + m_dy);
l.Start(start);
l.End(end);
}
};
This class is supposed to change the x and y position of some objects, Point, Line and Circle.
When I execute the following code:
int main()
{
typedef boost::variant<Point, Line, Circle> ShapeType;
Point p(1, 2);
Line l(p, p);
Circle c(p, 5);
ShapeType shape_variant;
std::cout << p << "\n\n"
<< l << "\n\n"
<< c << "\n\n";
shape_variant = p;
boost::apply_visitor(move_visitor(2, 2), shape_variant);
std::cout << p << std::endl;
shape_variant = l;
boost::apply_visitor(move_visitor(2, 2), shape_variant);
std::cout << std::endl << l << std::endl;
return 0;
}
p remains as 1, 2 and so does l. Why aren't my object changing after 'apply_visitor`?
You're modifying shape_variant, not p or l.
Try
std::cout << boost::get<Point>(shape_variant) << std::endl;
and
std::cout << boost::get<Line>(shape_variant) << std::endl;

How to display coordinates from class?

I am having issues displaying coordinates that are read into a class. This is my first time using classes so please be understanding!
Here is what I have so far:
#include <iostream>
using namespace std;
class Vector{
private:
float x;
float y;
public:
Vector(float f1, float f2)
{
x=f1;
y=f2;
}
Vector(){}
float display()
{
Vector v;
cout << "(" << v.x << "," << v.y << ")" << endl;
return 0;
}
};
int main()
{
Vector v1(0.5, 0.5);
cout << "v1 ";
v1.display();
system("pause");
return 0;
}
It prints
v1 (-1.07374e+008,-1.07374e+008)
Your problem is that you are not printing out the coordinates of the Vector you created in main() but a default created one in your function. Instead of
float display()
{
Vector v;
cout << "(" << v.x << "," << v.y << ")" << endl;
return 0;
}
You need
float display()
{
//Vector v; remove this
cout << "(" << x << "," << y << ")" << endl;
// no v.x no v.y
return 0;
}
I suggest you change the default constructor to
Vector() : x(0), y(0) {}
So it would have printed
v1 (0,0)
You should also change
Vector(float f1, float f2)
{
x=f1;
y=f2;
}
To
Vector(float f1, float f2) : x(f1), y(f2) {}
As it is a good habit to get into. This can save resources and CPU cycles when dealing with non POD types. For more information see Why should I prefer to use member initialization list?
the Vector v; line is a mistake. You are basically creating a new uninitialized vector instead of crating your own instance.
one correction would be:
int display()
{
cout << "(" << x << "," << y << ")" << endl;
return 0;
}
since x and y are member of this class