给定R2中的两个相交线段(AB和CD),找到应用于CD的最小幅度的平移,使其不再与AB相交。
我尝试过的。我计算每条线上每个点到相反线的距离。然后我选择4个值中的最小值并将其应用于线的垂线。但是,我计算的翻译往往是错误的方向。我该如何解决这个问题?
#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;
}
答案 0 :(得分:0)
你的想法会奏效。你只需要像@Tommy提到的签名距离函数。此外,请注意,您还必须获得右垂直方向,具体取决于距离函数中的符号约定。
答案 1 :(得分:-1)
你有正确的方法。从关于Minkowski和的推理出发,最短的分离矢量将垂直于其中一条线,并且足够长以将其中一个端点推到另一条线的表面。
然而,您的DistanceFromPoint
会返回无符号距离:它始终为零或正数。然后,每行使用一个垂直线乘以。所以你应该在50%的时间里走错路,因为你的距离没有任何迹象。
您可能更愿意重新安排,尤其是因为它会节省您的一些平方根:
...因为如果您n
单位沿轴q
嵌入,那么解决这个问题的方法就是沿-n
移动q
个单位;所以选择最少n
。