c++ - Ramer-Douglas-Peucker 路径简化算法

标签 c++ algorithm debugging

我在阅读这里的文章后实现了一个路径简化算法:

http://losingfight.com/blog/2011/05/30/how-to-implement-a-vector-brush/

它非常适合我为我的游戏生成优化的关卡几何体。但是,我现在正在使用它来清理 a* 寻路路径,它有一个奇怪的边缘案例,失败得很惨。

这是它工作的屏幕截图 - 优化从红色圆圈到蓝色圆圈的路径。淡绿色线是 a* 输出,浅白色线是优化路径。

enter image description here

这是失败的截图:

enter image description here

这是我的代码。我将文章中的 ObjC 代码改编为 C++

备注:vec2fvecstd::vector< vec2<float> > ,而“real”只是一个 typedef 的 float 。

       void rdpSimplify( const vec2fvec &in, vec2fvec &out, real threshold )
{
    if ( in.size() <= 2 )
    {
        out = in;
        return;
    }

    //
    //  Find the vertex farthest from the line defined by the start and and of the path
    //

    real maxDist = 0;
    size_t maxDistIndex = 0;      
    LineSegment line( in.front(), in.back() );

    for ( vec2fvec::const_iterator it(in.begin()),end(in.end()); it != end; ++it )
    {
        real dist = line.distance( *it );
        if ( dist > maxDist )
        {
            maxDist = dist;
            maxDistIndex = it - in.begin();
        }
    }

    //
    //  If the farhtest vertex is greater than our threshold, we need to
    //  partition and optimize left and right separately
    //

    if ( maxDist > threshold )
    {
        //
        //  Partition 'in' into left and right subvectors, and optimize them
        //

        vec2fvec left( maxDistIndex+1 ),
                 right( in.size() - maxDistIndex ),
                 leftSimplified,
                 rightSimplified;

        std::copy( in.begin(), in.begin() + maxDistIndex + 1, left.begin() );
        std::copy( in.begin() + maxDistIndex, in.end(), right.begin() );

        rdpSimplify(left, leftSimplified, threshold );
        rdpSimplify(right, rightSimplified, threshold );

        //
        //  Stitch optimized left and right into 'out'
        //

        out.resize( leftSimplified.size() + rightSimplified.size() - 1 );
        std::copy( leftSimplified.begin(), leftSimplified.end(), out.begin());
        std::copy( rightSimplified.begin() + 1, rightSimplified.end(), out.begin() + leftSimplified.size() );
    }
    else
    {
        out.push_back( line.a );
        out.push_back( line.b );
    }
}

我真的不知道出了什么问题。我的狡猾感觉说它在 std::copy 调用中......在某些情况下我一定是在复制垃圾。

编辑: 我重写了算法,不再使用迭代器和 std::copy 等。它仍然以完全相同的方式失败。

       void rdpSimplify( const vec2fvec &in, vec2fvec &out, real threshold )
{
    if ( in.size() <= 2 )
    {
        out = in;
        return;
    }

    //
    //  Find the vertex farthest from the line defined by the start and and of the path
    //

    real maxDist = 0;
    size_t maxDistIndex = 0;      
    LineSegment line( in.front(), in.back() );

    for ( size_t i = 0, N = in.size(); i < N; i++ )
    {
        real dist = line.distance( in[i] );
        if ( dist > maxDist )
        {
            maxDist = dist;
            maxDistIndex = i;
        }
    }


    //
    //  If the farthest vertex is greater than our threshold, we need to
    //  partition and optimize left and right separately
    //

    if ( maxDist > threshold )
    {
        //
        //  Partition 'in' into left and right subvectors, and optimize them
        //


        vec2fvec left, right, leftSimplified, rightSimplified;
        for ( size_t i = 0; i < maxDistIndex + 1; i++ ) left.push_back( in[i] );
        for ( size_t i = maxDistIndex; i < in.size(); i++ ) right.push_back( in[i] );


        rdpSimplify(left, leftSimplified, threshold );
        rdpSimplify(right, rightSimplified, threshold );

        //
        //  Stitch optimized left and right into 'out'
        //

        out.clear();
        for ( size_t i = 0, N = leftSimplified.size(); i < N; i++ ) out.push_back(leftSimplified[i]);
        for ( size_t i = 1, N = rightSimplified.size(); i < N; i++ ) out.push_back( rightSimplified[i] );
    }
    else
    {
        out.push_back( line.a );
        out.push_back( line.b );
    }
}

最佳答案

我在您的代码中找不到任何错误。

一些尝试:

  • 添加一些调试打印语句来检查失败情况下的 maxDist。它应该非常低,但如果它出现很高,那么您就知道您的线段距离代码有问题。
  • 检查您看到的路径是否确实与您的算法返回的路径相匹配。如果不是,那么您的路径渲染可能有问题?当路径只有两个点时可能是一个错误?
  • 通过在算法开始时打印出所有坐标来检查您的输入路径是否符合您的预期。

只要稍微调查一下,应该不会花太长时间就可以找到问题的原因。几分钟后,盯着代码是一种非常糟糕的调试方式。

关于c++ - Ramer-Douglas-Peucker 路径简化算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6483423/

相关文章:

algorithm - 遍历位序列并找到每个设置位

algorithm - 这不是平衡二叉树吗?

c++ - CImg 和 fftw++ 的组合失败

c++ - C++ 中的快速按位问题

algorithm - 如何在 Scala 中的数据框中获取成对的 x 值?

ruby-on-rails - var_dump 并像 php 一样死去,在 ruby​​ on rails 中(在 ruby​​ on rails 中调试)

php - 如何防止IDE(PhpStorm)在编辑代码时写入数据库?还有一个幽灵变量

sql - cakephp 在执行前查看已编译的 SQL 查询

c++ - priority_queue 上的 reinterpret_cast 是否迭代底层 vector 非标准?

c++ - C++中的模板方法模式和长参数列表