根据坐标

时间:2016-05-23 09:32:46

标签: c++ vector 2d contour

在我的软件中,我获得了存储在向量matrix中的2D轮廓点 我现在的任务是对这些点进行排序,以便获得轮廓。首先,我尝试了atan2函数,对常规案例有效。但是在非凸形轮廓的情况下,这不起作用。 因此,在谷歌查找并在此处回复之后,我现在尝试计算最近的点数。因此,我有一个计算两点之间距离的函数。

double distancepoints(vector<double> const& s1, vector<double> const& s2)
{
    return sqrt( (s1[0] - s2[0])*(s1[0] - s2[0]) + (s1[1] - s2[1])*(s1[1] - s2[1]) );
}

要找到我在函数中定义的最近点,该点的索引最接近预定的起点。

int closestpoint(vector<double> const& p, begin, end )
{
   double d=0;
   result = begin;
   while(begin != end)
   {
      double d2 = distancepoints(p, begin);
      if(d2 < d)
      {
        d = d2;
        result = begin;
      }
    }
    return result;
}

在这里,我不知道如何传递矢量的开始和结束。

如果我有下一个点的索引,我会将此点保存在向量Hull中,并将其从向量matrix中删除。这应该发生很长时间,直到matrix完全删除。

vector<vector<double> > matrix;
vector<vector<double> > hull;

int columns = 3;

const std::vector<LineSegment> &lss = slicesWithLineSegments[i];
rows = 2*lss.size();

matrix.resize(rows);

for(size_t i=0; i<matrix.size(); i++) {
    matrix[i].resize(columns);
}

for(size_t i=0; i<hull.size(); i++) {
    hull[i].resize(columns);
}

vector<vector<double> > startpoint;

for(size_t i=0; i<startpoint.size(); i++) {
    startpoint[i].resize(columns);
}

startpoint[0][0]=matrix[0][0];
startpoint[0][1]=matrix[0][1];
startpoint[0][2]=matrix[0][2];

matrix.erase(matrix.begin() );

while (matrix.size())
{
// Find next point (the one closest to p) and return index
int it = closestpoint( startpoint, matrix.begin(), matrix.end() );

// Store nearest point 
hull.push_back(std::vector<double>(3, 0));
r = hull.size()-1;
hull[r][0] = matrix[it][0];
hull[r][1] = matrix[it][1];
hull[r][2] = matrix[it][2];
// Our new p is the point we just found
startpoint = matrix[it];
// Remove the point we just found from the vector of points
matrix.erase(matrix[it]);
}

但不知怎的,我不只是为了编程这个功能。也许有人知道我做错了什么?

3 个答案:

答案 0 :(得分:1)

注意:我正在编写兼容C ++ 11的编译器。所以&gt;&gt;对模板完全有效;)

<强>第一

向量向量是一种非常低效的存储三维数据的方法。你应该考虑使用

std::vector<std::array<double, 3>>

而不是

std::vector<std::vector<double>>

我正在使用std :: array作为示例。如果单点需要std :: vector,只需使用此类型而不是std :: array

<强>第二

如果搜索nearst点,则无需计算平方根。比较平方距离将起作用。

double squareDistancePoints(const std::array<double, 3>& a, const std::array<double, 3>& b)
{
    return pow(a[0]-b[0], 2) + pow(a[1]-b[1], 2) + pow(a[2]-b[2], 2);
}

对于矢量点,这将是

double squareDistancePoints(const std::vector<double>& a, const std::vector<double>& b)
{
    assert(a.size() == b.size());
    double sum = 0;
    for(size_t i = 0; i < a.size(); ++i)
        sum += pow(a[i]-b[i], 2);
    return sum;
}

<强>第三

如果从“矩阵”中删除使用过的点,为什么要为“最近点”函数提供开始和结束迭代器?

std::vector<std::array<double, 3>>::const_iterator closestPoint(const std::array<double, 3>& point, const std::vector<std::array<double, 3>>& matrix)
{
    return std::min_element(matrix.begin(), matrix.end(), [=](const auto& a, const auto& b) { 
        return squareDistancePoints(point, a) < squareDistancePoints(point, b); 
    });
}

所以你根本不需要nearestPoint()函数。你需要的是标准库中的std :: min_element。这种方式有点慢,因为最佳点的距离是多次计算的,但如果你的sqrt()足够快,这段代码也会足够快。

这里有一个更快但更长的版本:

std::vector<std::array<double, 3>>::const_iterator closestPoint(const std::array<double, 3>& point, const std::vector<std::array<double, 3>>& matrix)
{
    double bestDistance = DBL_MAX;
    auto bestIt = matrix.end();

    for(auto it = matrix.begin(); it != matrix.end(); ++it)
    {
        const auto distance = squareDistancePoints(point, *it);
        if (distance < bestDistance)
        {
            bestDistance = distance;
            bestIt = it;
        }  
    }

    return bestIt;
}

示例

std::vector<std::array<double, 3>> matrix;
std::vector<std::array<double, 3>> hull;

... // populate matrix

// Add first point to hull
hull.push_back(matrix.back());
matrix.pop_back();

// Add additional points to hull
while(!matrix.empty())
{
    auto it = closestPoint(hull.back(), matrix);
    hull.push_back(*it);
    matrix.erase(it);
}

内联示例 不使用nearestPoint()函数,因为这个 需要一个需要开始和结束迭代器的nearestPoint()函数。

std::vector<std::array<double, 3>> points;

... // populate points with matrix data

for(auto it = points.begin(); it != points.end(); ++it)
{
    auto bestIt = points.end();
    double bestSquareDistance = DBL_MAX;
    for(auto nextIt = it + 1; nextIt != points.end(); ++nextIt)
    {
        const auto squareDistance = squareDistancePoints(*it, *nextIt);
        if (squareDistance < bestSquareDistance)
        {
             bestSquareDistance = squareDistance;
             bestIt = nextIt;
        }
    }
    if (bestIt != points.end())
        std::swap(*(it+1), *bestIt);
}

简短内联示例 (简短但非常低效;可用于小组积分)

std::vector<std::array<double, 3>> points;

... // populate points with matrix data

for(auto it = points.begin(); it != points.end() && it+1 != points.end(); ++it)
    std::sort(it+1, points.end(), [=](const auto& a, const auto& b) {
        return squareDistancePoints(*it, a) < squareDistancePoints(*it, b);
    });

// vector 'points' now contains all hull points in correct order

完整示例 我创建了一个小样本程序,用于对2D矩形的点进行排序。您可以在http://ideone.com/OeCpdG

找到它

答案 1 :(得分:0)

因此,让我们添加一些typedef来简化代码:

typedef std::vector<double> Point;   // I still think std::array<double,3>
                                     // would be better here.
typedef std::vector<Point> PointList;

size_t closestpoint( const Point& p, const PointList& plist)
{
    if (plist.empty())
    {
        throw ???;  // Call is meaningless if plist is empty.
    }
    size_t result = 0;
    double best = distancepoints( p, plist[result] );
    for (size_t i = 1; i < plist.size(); i++)
    {
         const double dist = distancepoints( p, plist[i] );
         if (dist < best)
         {
             result = i;
             best = dist;
         }
    }
    return result;
 }

电话是:

    size_t it = closestpoint(startpoint, matrix);

答案 2 :(得分:0)

我建议(警告:未经测试)

int closestpoint (std::vector<std::vector<double> > const & p,
                  std::vector<std::vector<double> >::const_iterator & it, 
                  std::vector<std::vector<double> >::const_iterator & end )
{
   double d=DBL_MAX;
   int  result=0;
   for (int i = 0 ; it != end ; ++it, ++i)
   {
      double d2 = distancepoints(p, *it);
      if(d2 < d)
      {
        d      = d2;
        result = i;
      }
    }
    return result;
}