(三)代码实现:Boustrophedon Cellular Decomposition Path Planning用珊格地图生成每个cell的覆盖路径

news2024/9/21 17:47:16

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
TODO:写完再整理

文章目录

  • 系列文章目录
  • 前言
  • 算法原理
    • 方法一:全地图进行牛耕覆盖步骤
    • 方法二:区域分解地图进行牛耕覆盖步骤
      • 凸多边形基于栅格地图的算法实现
  • 优缺点


前言

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!

本文先对Boustrophedon Cellular Decomposition Path Planning用珊格地图生成每个cell的覆盖路径做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章


提示:以下是本篇文章正文内容

算法原理

单元内的覆盖路径通过牛耕法来规划。当遇到障碍物的时候按照“左、下、上、右”4个固定的优先级顺序,使机器人在室内进行全覆盖的移动。

沿着一条直线穿过整个田地,然后转身,沿着与前一条路径相邻的新直线路径前进。通过重复这个过程,保证覆盖整个田地。
在这里插入图片描述
基于图形地图牛耕覆盖实现与基于栅格地图牛耕覆盖实现的核心原理都是一样的

全地图牛耕覆盖VS区域分解牛耕覆盖
全地图进行牛耕覆盖会出现死点,当进行了区域单圈分解后,cell是一个凸多边形,一般不会到达一个死点位置

方法一:全地图进行牛耕覆盖步骤

单元内的覆盖路径通过牛耕法来规划。当遇到障碍物的时候按照“左、下、上、右”4个固定的优先级顺序,使机器人在室内进行全覆盖的移动。直至到达死点位置。重新选择新的角点直到把非占据栅格都填满
回溯机制:
(a)栅格回溯列表建立:关键角点
(b)回溯点的选择:欧式距离、最优路径距离,其它方案

在这里插入图片描述
在这里插入图片描述

方法二:区域分解地图进行牛耕覆盖步骤

在这里插入图片描述

凸多边形基于栅格地图的算法实现


std::deque<std::deque<Point2D>> StaticPathPlanning(const cv::Mat& map, std::vector<CellNode>& cell_graph, const Point2D& start_point, int robot_radius, bool visualize_cells, bool visualize_path, int color_repeats=10)
{
    cv::Mat3b vis_map;
    cv::cvtColor(map, vis_map, cv::COLOR_GRAY2BGR);

    std::deque<std::deque<Point2D>> global_path;
    std::deque<Point2D> local_path;
    int corner_indicator = TOPLEFT;

    //计算连接每个cell中的路径local_path
    int start_cell_index = DetermineCellIndex(cell_graph, start_point).front();
    std::deque<Point2D> init_path = WalkInsideCell(cell_graph[start_cell_index], start_point, ComputeCellCornerPoints(cell_graph[start_cell_index])[TOPLEFT]);
    local_path.assign(init_path.begin(), init_path.end());

    std::deque<CellNode> cell_path = GetVisittingPath(cell_graph, start_cell_index);

    if(visualize_cells||visualize_path)
    {
        cv::namedWindow("map", cv::WINDOW_NORMAL);
        cv::imshow("map", vis_map);
    }

    if(visualize_cells)
    {
        std::cout<<"cell graph has "<<cell_graph.size()<<" cells."<<std::endl;
        for(int i = 0; i < cell_graph.size(); i++)
        {
            for(int j = 0; j < cell_graph[i].neighbor_indices.size(); j++)
            {
                std::cout<<"cell "<< i << "'s neighbor: cell "<<cell_graph[cell_graph[i].neighbor_indices[j]].cellIndex<<std::endl;
            }
        }

        for(const auto& cell : cell_graph)
        {
            DrawCells(vis_map, cell);
            cv::imshow("map", vis_map);
            cv::waitKey(500);
        }
    }

    std::deque<cv::Scalar> JetColorMap;
    InitializeColorMap(JetColorMap, color_repeats);

    if(visualize_path)
    {
        cv::circle(vis_map, cv::Point(start_point.x, start_point.y), 1, cv::Scalar(0, 0, 255), -1);
        for(const auto& point : init_path)
        {
            vis_map.at<cv::Vec3b>(point.y, point.x)=cv::Vec3b(uchar(JetColorMap.front()[0]),uchar(JetColorMap.front()[1]),uchar(JetColorMap.front()[2]));
            UpdateColorMap(JetColorMap);
            cv::imshow("map", vis_map);
            cv::waitKey(1);
        }
    }

    std::deque<Point2D> inner_path;
    std::deque<std::deque<Point2D>> link_path;
    Point2D curr_exit;
    Point2D next_entrance;

    std::deque<int> return_cell_path;
    std::deque<Point2D> return_path;

    for(int i = 0; i < cell_path.size(); i++)
    {
        计算单个cell中的覆盖路径
        inner_path = GetBoustrophedonPath(cell_graph, cell_path[i], corner_indicator, robot_radius);
        local_path.insert(local_path.end(), inner_path.begin(), inner_path.end());
        if(visualize_path)
        {
            for(const auto& point : inner_path)
            {
                vis_map.at<cv::Vec3b>(point.y, point.x)=cv::Vec3b(uchar(JetColorMap.front()[0]),uchar(JetColorMap.front()[1]),uchar(JetColorMap.front()[2]));
                UpdateColorMap(JetColorMap);
                cv::imshow("map", vis_map);
                cv::waitKey(1);
            }
        }

        cell_graph[cell_path[i].cellIndex].isCleaned = true;

        if(i < (cell_path.size()-1))
        {
            curr_exit = inner_path.back();
            next_entrance = FindNextEntrance(curr_exit, cell_path[i+1], corner_indicator);
            link_path = FindLinkingPath(curr_exit, next_entrance, corner_indicator, cell_path[i], cell_path[i+1]);

            // for debugging
//            std::cout<<std::endl;
//            for(int i = 0; i < link_path.front().size(); i++)
//            {
//                int idx = DetermineCellIndex(cell_graph, link_path.front()[i]).front();
//                std::cout<<"point lies in curr cell "<<idx<<std::endl;
//            }
//
//            for(int i = 0; i < link_path.back().size(); i++)
//            {
//                int idx = DetermineCellIndex(cell_graph, link_path.back()[i]).front();
//                std::cout<<"point lies in next cell "<<idx<<std::endl;
//            }
//            std::cout<<std::endl;


            local_path.insert(local_path.end(), link_path.front().begin(), link_path.front().end());
            global_path.emplace_back(local_path);
            local_path.clear();
            local_path.insert(local_path.end(), link_path.back().begin(), link_path.back().end());


            if(visualize_path)
            {
                for(const auto& point : link_path.front())
                {
//                    vis_map.at<cv::Vec3b>(point.y, point.x)=cv::Vec3b(255, 255, 255);
                    vis_map.at<cv::Vec3b>(point.y, point.x)=cv::Vec3b(uchar(JetColorMap.front()[0]),uchar(JetColorMap.front()[1]),uchar(JetColorMap.front()[2]));
                    UpdateColorMap(JetColorMap);
                    cv::imshow("map", vis_map);
                    cv::waitKey(1);
                }

                for(const auto& point: link_path.back())
                {
//                    vis_map.at<cv::Vec3b>(point.y, point.x)=cv::Vec3b(255, 255, 255);
                    vis_map.at<cv::Vec3b>(point.y, point.x)=cv::Vec3b(uchar(JetColorMap.front()[0]),uchar(JetColorMap.front()[1]),uchar(JetColorMap.front()[2]));
                    UpdateColorMap(JetColorMap);
                    cv::imshow("map", vis_map);
                    cv::waitKey(1);
                }

            }
        }
    }
    global_path.emplace_back(local_path);

    if(visualize_cells||visualize_path)
    {
        cv::waitKey(0);
    }

    return global_path;
}


std::vector<int> DetermineCellIndex(std::vector<CellNode>& cell_graph, const Point2D& point)
{
    std::vector<int> cell_index;

    for(int i = 0; i < cell_graph.size(); i++)
    {
        for(int j = 0; j < cell_graph[i].ceiling.size(); j++)
        {
            if(point.x ==  cell_graph[i].ceiling[j].x && point.y >= cell_graph[i].ceiling[j].y && point.y <= cell_graph[i].floor[j].y)
            {
                cell_index.emplace_back(int(i));
            }
        }

    }
    return cell_index;
}


std::deque<Point2D> WalkInsideCell(CellNode cell, const Point2D& start, const Point2D& end)
{
    std::deque<Point2D> inner_path = {start};

    int start_ceiling_index_offset = start.x - cell.ceiling.front().x;
    int first_ceiling_delta_y = cell.ceiling[start_ceiling_index_offset].y - start.y;
    int end_ceiling_index_offset = end.x - cell.ceiling.front().x;
    int second_ceiling_delta_y = end.y - cell.ceiling[end_ceiling_index_offset].y;

    int start_floor_index_offset = start.x - cell.floor.front().x;
    int first_floor_delta_y = cell.floor[start_floor_index_offset].y - start.y;
    int end_floor_index_offset = end.x - cell.floor.front().x;
    int second_floor_delta_y = end.y - cell.floor[end_floor_index_offset].y;

    if((abs(first_ceiling_delta_y)+abs(second_ceiling_delta_y)) < (abs(first_floor_delta_y)+abs(second_floor_delta_y))) //to ceiling
    {
        int first_increment_y = 0;
        if(first_ceiling_delta_y != 0)
        {
            first_increment_y = first_ceiling_delta_y / abs(first_ceiling_delta_y);

            for(int i = 1; i <= abs(first_ceiling_delta_y); i++)
            {
                inner_path.emplace_back(Point2D(start.x, start.y+(first_increment_y*i)));
            }
        }

        int delta_x = cell.ceiling[end_ceiling_index_offset].x - cell.ceiling[start_ceiling_index_offset].x;
        int increment_x = 0;
        if(delta_x != 0)
        {
            increment_x = delta_x / abs(delta_x);
        }
        for(int i = 0; i < abs(delta_x); i++)
        {
            // 提前转
            if((cell.ceiling[start_ceiling_index_offset+increment_x*(i+1)].y-cell.ceiling[start_ceiling_index_offset+increment_x*(i)].y>=2)
               &&(i+1 <= abs(delta_x))
               &&(i <= abs(delta_x)))
            {
                int delta = cell.ceiling[start_ceiling_index_offset+increment_x*(i+1)].y-cell.ceiling[start_ceiling_index_offset+increment_x*(i)].y;
                int increment = delta/abs(delta);
                for(int j = 0; j <= abs(delta); j++)
                {
                    inner_path.emplace_back(Point2D(cell.ceiling[start_ceiling_index_offset+increment_x*i].x, cell.ceiling[start_ceiling_index_offset+increment_x*i].y+increment*(j)));
                }
            }
            // 滞后转
            else if((cell.ceiling[start_ceiling_index_offset+increment_x*(i)].y-cell.ceiling[start_ceiling_index_offset+increment_x*(i+1)].y>=2)
                     &&(i<=abs(delta_x))
                     &&(i+1<=abs(delta_x)))
            {
                inner_path.emplace_back(cell.ceiling[start_ceiling_index_offset+increment_x*(i)]);

                int delta = cell.ceiling[start_ceiling_index_offset+increment_x*(i+1)].y-cell.ceiling[start_ceiling_index_offset+increment_x*(i)].y;

                int increment = delta/abs(delta);
                for(int k = 0; k <= abs(delta); k++)
                {
                    inner_path.emplace_back(Point2D(cell.ceiling[start_ceiling_index_offset+increment_x*(i+1)].x, cell.ceiling[start_ceiling_index_offset+increment_x*(i+1)].y+abs(delta)+increment*(k)));
                }
            }
            else
            {
                inner_path.emplace_back(cell.ceiling[start_ceiling_index_offset+(increment_x*i)]);
            }
        }

        int second_increment_y = 0;
        if(second_ceiling_delta_y!=0)
        {
            second_increment_y = second_ceiling_delta_y/abs(second_ceiling_delta_y);

            for(int i = 1; i <= abs(second_ceiling_delta_y); i++)
            {
                inner_path.emplace_back(Point2D(cell.ceiling[end_ceiling_index_offset].x, cell.ceiling[end_ceiling_index_offset].y+(second_increment_y*i)));
            }
        }

    }
    else // to floor
    {
        int first_increment_y = 0;
        if(first_floor_delta_y != 0)
        {
            first_increment_y = first_floor_delta_y / abs(first_floor_delta_y);

            for(int i = 1; i <= abs(first_floor_delta_y); i++)
            {
                inner_path.emplace_back(Point2D(start.x, start.y+(first_increment_y*i)));
            }
        }

        int delta_x = cell.floor[end_floor_index_offset].x - cell.floor[start_floor_index_offset].x;
        int increment_x = 0;
        if(delta_x != 0)
        {
            increment_x = delta_x / abs(delta_x);
        }
        for(int i = 0; i < abs(delta_x); i++)
        {
            //提前转
            if((cell.floor[start_floor_index_offset+increment_x*(i)].y-cell.floor[start_floor_index_offset+increment_x*(i+1)].y>=2)
               &&(i<=abs(delta_x))
               &&(i+1<=abs(delta_x)))
            {
                int delta = cell.floor[start_floor_index_offset+increment_x*(i+1)].y-cell.floor[start_floor_index_offset+increment_x*(i)].y;
                int increment = delta/abs(delta);
                for(int j = 0; j <= abs(delta); j++)
                {
                    inner_path.emplace_back(Point2D(cell.floor[start_floor_index_offset+increment_x*(i)].x, cell.floor[start_floor_index_offset+increment_x*(i)].y+increment*(j)));
                }
            }
            //滞后转
            else if((cell.floor[start_floor_index_offset+increment_x*(i+1)].y-cell.floor[start_floor_index_offset+increment_x*(i)].y>=2)
                    &&(i+1<=abs(delta_x))
                    &&(i<=abs(delta_x)))
            {
                inner_path.emplace_back(Point2D(cell.floor[start_floor_index_offset+increment_x*(i)].x, cell.floor[start_floor_index_offset+increment_x*(i)].y));

                int delta = cell.floor[start_floor_index_offset+increment_x*(i+1)].y-cell.floor[start_floor_index_offset+increment_x*(i)].y;

                int increment = delta/abs(delta);
                for(int k = 0; k <= abs(delta); k++)
                {
                    inner_path.emplace_back(Point2D(cell.floor[start_floor_index_offset+increment_x*(i+1)].x, cell.floor[start_floor_index_offset+increment_x*(i+1)].y-abs(delta) +increment*(k)));
                }
            }
            else
            {
                inner_path.emplace_back(cell.floor[start_floor_index_offset+(increment_x*i)]);
            }

        }

        int second_increment_y = 0;
        if(second_floor_delta_y!=0)
        {
            second_increment_y = second_floor_delta_y/abs(second_floor_delta_y);

            for(int i = 1; i <= abs(second_floor_delta_y); i++)
            {
                inner_path.emplace_back(Point2D(cell.floor[end_floor_index_offset].x, cell.floor[end_floor_index_offset].y+(second_increment_y*i)));
            }
        }
    }
    return inner_path;
}

std::vector<Point2D> ComputeCellCornerPoints(const CellNode& cell)
{

    Point2D topleft = cell.ceiling.front();
    Point2D bottomleft = cell.floor.front();
    Point2D bottomright = cell.floor.back();
    Point2D topright = cell.ceiling.back();

    // 按照TOPLEFT、BOTTOMLEFT、BOTTOMRIGHT、TOPRIGHT的顺序储存corner points(逆时针)
    std::vector<Point2D> corner_points = {topleft, bottomleft, bottomright, topright};

    return corner_points;
}

void InitializeColorMap(std::deque<cv::Scalar>& JetColorMap, int repeat_times)
{
    for(int i = 0; i <= 255; i++)
    {
        for(int j = 0; j < repeat_times; j++)
        {
            JetColorMap.emplace_back(cv::Scalar(0, i, 255));
        }
    }

    for(int i = 254; i >= 0; i--)
    {
        for(int j = 0; j < repeat_times; j++)
        {
            JetColorMap.emplace_back(cv::Scalar(0, 255, i));
        }
    }

    for(int i = 1; i <= 255; i++)
    {
        for(int j = 0; j < repeat_times; j++)
        {
            JetColorMap.emplace_back(cv::Scalar(i, 255, 0));
        }
    }

    for(int i = 254; i >= 0; i--)
    {
        for(int j = 0; j < repeat_times; j++)
        {
            JetColorMap.emplace_back(cv::Scalar(255, i, 0));
        }
    }

    for(int i = 1; i <= 255; i++)
    {
        for(int j = 0; j < repeat_times; j++)
        {
            JetColorMap.emplace_back(cv::Scalar(255, 0, i));
        }
    }

    for(int i = 254; i >= 1; i--)
    {
        for(int j = 0; j < repeat_times; j++)
        {
            JetColorMap.emplace_back(cv::Scalar(i, 0, 255));
        }
    }
}

//单个cell,boustrophedon生成覆盖路径
std::deque<Point2D> GetBoustrophedonPath(std::vector<CellNode>& cell_graph, CellNode cell, int corner_indicator, int robot_radius)
{
    int delta, increment;
    std::deque<Point2D> path;
    std::vector<Point2D> corner_points = ComputeCellCornerPoints(cell);
    std::vector<Point2D> ceiling, floor;
    ceiling.assign(cell.ceiling.begin(), cell.ceiling.end());
    floor.assign(cell.floor.begin(), cell.floor.end());
    if(cell_graph[cell.cellIndex].isCleaned)
    {
        if(corner_indicator == TOPLEFT)
        {
            path.emplace_back(corner_points[TOPLEFT]);
        }
        if(corner_indicator == TOPRIGHT)
        {
            path.emplace_back(corner_points[TOPRIGHT]);
        }
        if(corner_indicator == BOTTOMLEFT)
        {
            path.emplace_back(corner_points[BOTTOMLEFT]);
        }
        if(corner_indicator == BOTTOMRIGHT)
        {
            path.emplace_back(corner_points[BOTTOMRIGHT]);
        }
    }
    else
    {
        if(corner_indicator == TOPLEFT)
        {
            int x, y, y_start, y_end;
            bool reverse = false;

            for(int i = 0; i < ceiling.size(); i = i + (robot_radius+1))
            {
                x = ceiling[i].x;

                if(!reverse)
                {
                    y_start = ceiling[i].y;
                    y_end   = floor[i].y;

                    for(y = y_start; y <= y_end; y++)
                    {
                        path.emplace_back(Point2D(x, y));
                    }

                    if((std::abs(floor[i+1].y-floor[i].y)>=2)&&(i+1<floor.size()))
                    {
                        delta = floor[i+1].y-floor[i].y;
                        increment = delta/abs(delta);
                        for(int k = 1; k <= abs(delta); k++)
                        {
                            path.emplace_back(Point2D(floor[i].x, floor[i].y + increment * (k)));
                        }
                    }

                    if(robot_radius != 0)
                    {
                        for(int j = 1; j <= robot_radius+1; j++)
                        {
                            // 沿着floor从左往右
                            if( x+j >= floor.back().x)
                            {
                                i = i - (robot_radius - (j - 1));
                                break;
                            }

                            //提前转
                            else if((floor[i+(j)].y-floor[i+(j+1)].y>=2)
                               &&(j<=robot_radius+1)
                               &&(j+1<=robot_radius+1))
                            {
                                delta = floor[i+(j+1)].y-floor[i+(j)].y;
                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(floor[i+(j)].x, floor[i+(j)].y+increment*(k)));
                                }
                            }
                            //滞后转
                            else if((floor[i+(j+1)].y-floor[i+(j)].y>=2)
                                    &&(j+1<=robot_radius+1)
                                    &&(j<=robot_radius+1))
                            {
                                path.emplace_back(Point2D(floor[i+(j)].x, floor[i+(j)].y));

                                delta = floor[i+(j+1)].y-floor[i+(j)].y;

                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(floor[i+(j+1)].x, cell.floor[i+(j+1)].y-abs(delta) +increment*(k)));
                                }
                            }
                            else
                            {
                                path.emplace_back(floor[i+(j)]);
                            }

                        }
                    }

                    reverse = !reverse;
                }
                else
                {
                    y_start = floor[i].y;
                    y_end   = ceiling[i].y;

                    for (y = y_start; y >= y_end; y--)
                    {
                        path.emplace_back(Point2D(x, y));
                    }

                    if((std::abs(ceiling[i+1].y-ceiling[i].y)>=2)&&(i+1<ceiling.size()))
                    {
                        delta = ceiling[i+1].y-ceiling[i].y;
                        increment = delta/abs(delta);
                        for(int k = 1; k <= abs(delta); k++)
                        {
                            path.emplace_back(Point2D(ceiling[i].x, ceiling[i].y+increment*(k)));
                        }
                    }

                    if(robot_radius != 0)
                    {
                        for(int j = 1; j <= robot_radius+1; j++)
                        {
                            // 沿着ceiling从左往右
                            if(x+j >= ceiling.back().x)
                            {
                                i = i - (robot_radius - (j - 1));
                                break;
                            }

                            // 提前转
                            else if((ceiling[i+(j+1)].y-ceiling[i+(j)].y>=2)
                               &&(j+1 <= robot_radius+1)
                               &&(j <= robot_radius+1))
                            {
                                delta = ceiling[i+(j+1)].y-ceiling[i+(j)].y;
                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(ceiling[i+j].x, ceiling[i+j].y+increment*(k)));
                                }
                            }
                            // 滞后转
                            else if((ceiling[i+(j)].y-ceiling[i+(j+1)].y>=2)
                                    &&(j<=robot_radius+1)
                                    &&(j+1<=robot_radius+1))
                            {
                                path.emplace_back(ceiling[i+(j)]);

                                delta = ceiling[i+(j+1)].y-ceiling[i+(j)].y;

                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(ceiling[i+(j+1)].x, ceiling[i+(j+1)].y+abs(delta)+increment*(k)));
                                }
                            }
                            else
                            {
                                path.emplace_back(ceiling[i+j]);
                            }

                        }
                    }

                    reverse = !reverse;
                }
            }
        }

        if(corner_indicator == TOPRIGHT)
        {
            int x=0, y=0, y_start=0, y_end=0;
            bool reverse = false;

            for(int i = ceiling.size()-1; i >= 0; i=i-(robot_radius+1))
            {
                x = ceiling[i].x;

                if(!reverse)
                {
                    y_start = ceiling[i].y;
                    y_end   = floor[i].y;

                    for(y = y_start; y <= y_end; y++)
                    {
                        path.emplace_back(Point2D(x, y));
                    }

                    if((std::abs(floor[i-1].y-floor[i].y)>=2)&&(i-1>=0))
                    {
                        delta = floor[i-1].y-floor[i].y;
                        increment = delta/abs(delta);
                        for(int k = 1; k <= abs(delta); k++)
                        {
                            path.emplace_back(Point2D(floor[i].x, floor[i].y+increment*(k)));
                        }
                    }

                    if(robot_radius != 0)
                    {
                        for(int j = 1; j <= robot_radius+1; j++)
                        {
                            // 沿着floor从右往左
                            if(x-j <= floor.front().x)
                            {
                                i = i + (robot_radius - (j - 1));
                                break;
                            }
                            //提前转
                            else if((floor[i-(j)].y-floor[i-(j+1)].y>=2)
                               &&(j<=robot_radius+1)
                               &&(j+1<=robot_radius+1))
                            {
                                delta = floor[i-(j+1)].y-floor[i-(j)].y;
                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(floor[i-(j)].x, floor[i-(j)].y+increment*(k)));
                                }
                            }
                            //滞后转
                            else if((floor[i-(j+1)].y-floor[i-(j)].y>=2)
                                    &&(j+1<=robot_radius+1)
                                    &&(j<=robot_radius+1))
                            {
                                path.emplace_back(Point2D(floor[i-(j)].x, floor[i-(j)].y));

                                delta = floor[i-(j+1)].y-floor[i-(j)].y;

                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(floor[i-(j+1)].x, cell.floor[i-(j+1)].y-abs(delta) +increment*(k)));
                                }
                            }
                            else
                            {
                                path.emplace_back(floor[i-(j)]);
                            }
                        }
                    }

                    reverse = !reverse;
                }
                else
                {
                    y_start = floor[i].y;
                    y_end   = ceiling[i].y;

                    for (y = y_start; y >= y_end; y--)
                    {
                        path.emplace_back(Point2D(x, y));
                    }

                    if((std::abs(ceiling[i-1].y-ceiling[i].y)>=2)&&(i-1>=0))
                    {
                        delta = ceiling[i-1].y-ceiling[i].y;
                        increment = delta/abs(delta);
                        for(int k = 1; k <= abs(delta); k++)
                        {
                            path.emplace_back(Point2D(ceiling[i].x, ceiling[i].y+increment*(k)));
                        }
                    }

                    if(robot_radius != 0)
                    {
                        for(int j = 1; j <= robot_radius+1; j++)
                        {
                            // 沿着ceiling从右往左
                            if( x-j <= ceiling.front().x)
                            {
                                i = i + (robot_radius - (j - 1));
                                break;
                            }
                            // 提前转
                            else if((ceiling[i-(j+1)].y-ceiling[i-(j)].y>=2)
                               &&(j+1 <= robot_radius+1)
                               &&(j <= robot_radius+1))
                            {
                                delta = ceiling[i-(j+1)].y-ceiling[i-(j)].y;
                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(ceiling[i-j].x, ceiling[i-j].y+increment*(k)));
                                }
                            }
                            // 滞后转
                            else if((ceiling[i-(j)].y-ceiling[i-(j+1)].y>=2)
                                    &&(j<=robot_radius+1)
                                    &&(j+1<=robot_radius+1))
                            {
                                path.emplace_back(ceiling[i-(j)]);

                                delta = ceiling[i-(j+1)].y-ceiling[i-(j)].y;

                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(ceiling[i-(j+1)].x, ceiling[i-(j+1)].y+abs(delta)+increment*(k)));
                                }
                            }
                            else
                            {
                                path.emplace_back(ceiling[i-j]);
                            }
                        }
                    }

                    reverse = !reverse;
                }
            }
        }

        if(corner_indicator == BOTTOMLEFT)
        {
            int x=0, y=0, y_start=0, y_end=0;
            bool reverse = false;

            for(int i = 0; i < ceiling.size(); i=i+(robot_radius+1))
            {
                x = ceiling[i].x;

                if(!reverse)
                {
                    y_start = floor[i].y;
                    y_end   = ceiling[i].y;

                    for(y = y_start; y >= y_end; y--)
                    {
                        path.emplace_back(Point2D(x, y));
                    }

                    if((std::abs(ceiling[i+1].y-ceiling[i].y)>=2)&&(i+1<ceiling.size()))
                    {
                        delta = ceiling[i+1].y-ceiling[i].y;
                        increment = delta/abs(delta);
                        for(int k = 1; k <= abs(delta); k++)
                        {
                            path.emplace_back(Point2D(ceiling[i].x, ceiling[i].y+increment*(k)));
                        }
                    }

                    if(robot_radius != 0)
                    {
                        for(int j = 1; j <= robot_radius+1; j++)
                        {
                            // 沿着ceiling从左往右
                            if(x+j >= ceiling.back().x)
                            {
                                i = i - (robot_radius - (j - 1));
                                break;
                            }
                            // 提前转
                            else if((ceiling[i+(j+1)].y-ceiling[i+(j)].y>=2)
                               &&(j+1 <= robot_radius+1)
                               &&(j <= robot_radius+1))
                            {
                                delta = ceiling[i+(j+1)].y-ceiling[i+(j)].y;
                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(ceiling[i+j].x, ceiling[i+j].y+increment*(k)));
                                }
                            }
                                // 滞后转
                            else if((ceiling[i+(j)].y-ceiling[i+(j+1)].y>=2)
                                    &&(j<=robot_radius+1)
                                    &&(j+1<=robot_radius+1))
                            {
                                path.emplace_back(ceiling[i+(j)]);

                                delta = ceiling[i+(j+1)].y-ceiling[i+(j)].y;

                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(ceiling[i+(j+1)].x, ceiling[i+(j+1)].y+abs(delta)+increment*(k)));
                                }
                            }
                            else
                            {
                                path.emplace_back(ceiling[i+j]);
                            }
                        }
                    }

                    reverse = !reverse;
                }
                else
                {
                    y_start = ceiling[i].y;
                    y_end   = floor[i].y;

                    for (y = y_start; y <= y_end; y++)
                    {
                        path.emplace_back(Point2D(x, y));
                    }

                    if((std::abs(floor[i+1].y-floor[i].y)>=2)&&(i+1<floor.size()))
                    {
                        delta = floor[i+1].y-floor[i].y;
                        increment = delta/abs(delta);
                        for(int k = 1; k <= abs(delta); k++)
                        {
                            path.emplace_back(Point2D(floor[i].x, floor[i].y+increment*(k)));
                        }
                    }

                    if(robot_radius != 0)
                    {
                        for(int j = 1; j <= robot_radius+1; j++)
                        {
                            // 沿着floor从左往右
                            if(x+j >= floor.back().x)
                            {
                                i = i - (robot_radius - (j - 1));
                                break;
                            }

                            //提前转
                            else if((floor[i+(j)].y-floor[i+(j+1)].y>=2)
                               &&(j<=robot_radius+1)
                               &&(j+1<=robot_radius+1))
                            {
                                delta = floor[i+(j+1)].y-floor[i+(j)].y;
                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(floor[i+(j)].x, floor[i+(j)].y+increment*(k)));
                                }
                            }
                                //滞后转
                            else if((floor[i+(j+1)].y-floor[i+(j)].y>=2)
                                    &&(j+1<=robot_radius+1)
                                    &&(j<=robot_radius+1))
                            {
                                path.emplace_back(Point2D(floor[i+(j)].x, floor[i+(j)].y));

                                delta = floor[i+(j+1)].y-floor[i+(j)].y;

                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(floor[i+(j+1)].x, cell.floor[i+(j+1)].y-abs(delta) +increment*(k)));
                                }
                            }
                            else
                            {
                                path.emplace_back(floor[i+(j)]);
                            }
                        }
                    }

                    reverse = !reverse;
                }
            }
        }

        if(corner_indicator == BOTTOMRIGHT)
        {
            int x=0, y=0, y_start=0, y_end=0;
            bool reverse = false;

            for(int i = ceiling.size()-1; i >= 0; i=i-(robot_radius+1))
            {
                x = ceiling[i].x;

                if(!reverse)
                {
                    y_start = floor[i].y;
                    y_end   = ceiling[i].y;

                    for(y = y_start; y >= y_end; y--)
                    {
                        path.emplace_back(Point2D(x, y));
                    }

                    if((std::abs(ceiling[i-1].y-ceiling[i].y)>=2)&&(i-1>=0))
                    {
                        delta = ceiling[i-1].y-ceiling[i].y;
                        increment = delta/abs(delta);
                        for(int k = 1; k <= abs(delta); k++)
                        {
                            path.emplace_back(Point2D(ceiling[i].x, ceiling[i].y+increment*(k)));
                        }
                    }

                    if(robot_radius != 0)
                    {
                        for(int j = 1; j <= robot_radius+1; j++)
                        {
                            // 沿着ceiling从右往左
                            if(x-j <= ceiling.front().x)
                            {
                                i = i + (robot_radius - (j - 1));
                                break;
                            }
                            // 提前转
                            else if((ceiling[i-(j+1)].y-ceiling[i-(j)].y>=2)
                               &&(j+1 <= robot_radius+1)
                               &&(j <= robot_radius+1))
                            {
                                delta = ceiling[i-(j+1)].y-ceiling[i-(j)].y;
                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(ceiling[i-j].x, ceiling[i-j].y+increment*(k)));
                                }
                            }
                                // 滞后转
                            else if((ceiling[i-(j)].y-ceiling[i-(j+1)].y>=2)
                                    &&(j<=robot_radius+1)
                                    &&(j+1<=robot_radius+1))
                            {
                                path.emplace_back(ceiling[i-(j)]);

                                delta = ceiling[i-(j+1)].y-ceiling[i-(j)].y;

                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(ceiling[i-(j+1)].x, ceiling[i-(j+1)].y+abs(delta)+increment*(k)));
                                }
                            }
                            else
                            {
                                path.emplace_back(ceiling[i-j]);
                            }

                        }
                    }

                    reverse = !reverse;
                }
                else
                {
                    y_start = ceiling[i].y;
                    y_end   = floor[i].y;

                    for (y = y_start; y <= y_end; y++)
                    {
                        path.emplace_back(Point2D(x, y));
                    }

                    if((std::abs(floor[i-1].y-floor[i].y)>=2)&&(i-1>=0))
                    {
                        delta = floor[i-1].y-floor[i].y;
                        increment = delta/abs(delta);
                        for(int k = 1; k <= abs(delta); k++)
                        {
                            path.emplace_back(Point2D(floor[i].x, floor[i].y+increment*(k)));
                        }
                    }

                    if(robot_radius != 0)
                    {
                        for(int j = 1; j <= robot_radius+1; j++)
                        {
                            // 沿着floor从右往左
                            if(x-j <= floor.front().x)
                            {
                                i = i + (robot_radius - (j - 1));
                                break;
                            }
                            //提前转
                            else if((floor[i-(j)].y-floor[i-(j+1)].y>=2)
                               &&(j<=robot_radius+1)
                               &&(j+1<=robot_radius+1))
                            {
                                delta = floor[i-(j+1)].y-floor[i-(j)].y;
                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(floor[i-(j)].x, floor[i-(j)].y+increment*(k)));
                                }
                            }
                                //滞后转
                            else if((floor[i-(j+1)].y-floor[i-(j)].y>=2)
                                    &&(j+1<=robot_radius+1)
                                    &&(j<=robot_radius+1))
                            {
                                path.emplace_back(Point2D(floor[i-(j)].x, floor[i-(j)].y));

                                delta = floor[i-(j+1)].y-floor[i-(j)].y;

                                increment = delta/abs(delta);
                                for(int k = 0; k <= abs(delta); k++)
                                {
                                    path.emplace_back(Point2D(floor[i-(j+1)].x, cell.floor[i-(j+1)].y-abs(delta) +increment*(k)));
                                }
                            }
                            else
                            {
                                path.emplace_back(floor[i-(j)]);
                            }

                        }
                    }

                    reverse = !reverse;
                }
            }
        }
    }

    return path;
}

优缺点

牛耕覆盖算法在空旷环境能够提供漂亮的覆盖路径,但在复杂,混乱的环境中规划路径有些混乱。覆盖率偏高。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2152930.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows系统文件夹中的文件名排序

一天张三、李四的同事周五接到王哥的一个任务需求&#xff0c;有一个文件夹&#xff0c;里面有许多图片文件&#xff0c;网页访问某个分类展示文件的时候&#xff0c;王哥希望文件名的展示顺序可以按照Windows资源管理器中文件名升序排序的方式展示。 网站图片目录中有如下图片…

程序遇到问题错误bug时的13种解决方法途径总结以及之前的一些具体例子

目录 1 信心--没有解决不了的bug 2 耐心、不要着急、静下心来、用脑思考 2.1 开始解决问题前不要着急&#xff0c;先思考 2.2 在解决问题的过程中也不要着急&#xff0c;要冷静思考 3 网络搜索 4 大模型问答&#xff1a;必应、kimi、通义千问、文心一言 5 看芯片手册、S…

0921VGG网络实现

深度学习之VGG网络搭建 1.VGG动机2.VGG架构3.代码4.结论1.VGG动机 随着卷积网络在计算机视觉领域的快速发展,越来越多的研究人员开始通过改变模型的网络结构在提高在图像识别任务中的精度,例如使用更小的卷积核和步长[2]。基于类似的想法,论文作者提出可以尝试通过改变卷积…

【设计模式】创建型模式(三):单例模式

创建型模式&#xff08;三&#xff09;&#xff1a;单例模式 1.概念2.案例3.实现方式3.1 懒汉式&#xff0c;线程不安全3.2 懒汉式&#xff0c;线程安全3.3 饿汉式3.4 双检锁/双重校验锁&#xff08;DCL&#xff0c;Double-Checked Locking&#xff09;3.5 登记式/静态内部类3.…

俄罗斯OZON新生儿产品好不好卖,OZON新生儿产品

Top1 遥控水球坦克 Танк на радиоуправлении стреляющий орбизами PANAWEALTH 商品id&#xff1a;1384249985 月销量&#xff1a;692 欢迎各位OZON卖家朋友点击这里选品&#xff1a; &#x1f449; D。DDqbt。COm/74rD 遥控射击水…

【项目管理进阶】风险问题

前言 各位盆友&#xff0c;你们期待的项目管理进阶系列有新的消息&#xff0c;请注意查收&#xff0c;并反馈哦~ 在参加项目的过程中&#xff0c;你是否面临或参加过类似如下的场面&#xff1a; 为了立项&#xff0c;先调研市场、技术、社会、组织内部的现状为了科学的管理项目…

如何使用Claude进行Android App开发 —— 基于Jetpack和Compose的电影App实例

如何使用Claude进行Android App开发 —— 基于Jetpack和Compose的电影App实例 近年来&#xff0c;人工智能&#xff08;AI&#xff09;在软件开发中的应用越来越广泛&#xff0c;帮助开发者在设计、编码、测试和优化中提高生产效率。Claude是Anthropic开发的一款强大的AI助手&…

Redis的三种持久化方法详解

Redis持久化机制详解 | JavaGuide Redis 不同于 Memcached 的很重要一点就是&#xff0c;Redis 支持持久化&#xff0c;而且支持 3 种持久化方式: 快照&#xff08;snapshotting&#xff0c;RDB&#xff09;只追加文件&#xff08;append-only file, AOF&#xff09;RDB 和 A…

Vue使用axios二次封装、解决跨域问题

1、什么是 axios 在实际开发过程中&#xff0c;浏览器通常需要和服务器端进行数据交互。而 Vue.js 并未提供与服务器端通信的接口。从 Vue.js 2.0 版本之后&#xff0c;官方推荐使用 axios 来实现 Ajax 请求。axios 是一个基于 promise 的 HTTP 客户端。 关于 promise 的详细介…

C++:类和对象OJ题

目录 一、求123...n 二、计算日期到天数的转换 三、日期差值 四、打印日期 一、求123...n 这里先把题目链接放在这里求123.....n 描述&#xff1a; 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&#xff08;A?B:C…

鸿萌数据恢复服务: 修复 Windows, Mac, 手机中 “SD 卡无法读取”错误

天津鸿萌科贸发展有限公司从事数据安全服务二十余年&#xff0c;致力于为各领域客户提供专业的数据恢复、数据备份解决方案与服务&#xff0c;并针对企业面临的数据安全风险&#xff0c;提供专业的相关数据安全培训。 公司是多款国际主流数据恢复软件的授权代理商&#xff0c;为…

老年人养生之道:岁月静好,健康常伴

老年人养生之道&#xff1a;岁月静好&#xff0c;健康常伴 随着年岁的增长&#xff0c;老年人更需注重养生&#xff0c;以维持身心的和谐与健康&#xff0c;享受幸福晚年。养生不仅是一种生活态度&#xff0c;更是一种智慧的选择&#xff0c;它涵盖了饮食、运动、心理、社交等…

搜索引擎onesearch3实现解释和升级到Elasticsearch v8系列(一)-概述

简介 此前的专栏介绍Onesearch1.0和2.0&#xff0c;详情参考4 参考资料&#xff0c;本文解释onesearch 3.0&#xff0c;从Elasticsearch6升级到Elasticsearch8代码实现 &#xff0c;Elasticsearch8 废弃了high rest client&#xff0c;使用新的ElasticsearchClient&#xff0c;…

Hash入门-通过线性探测解决哈希冲突

unordered_set void test_unordered_set() {unordered_set<int> us;us.insert(4);us.insert(2);us.insert(1);us.insert(5);us.insert(6);us.insert(2);us.insert(2);//去重unordered_set<int>::iterator it us.begin();while (it ! us.end()){cout << *it…

Springboot使用ThreadPoolTaskScheduler轻量级多线程定时任务框架

简介&#xff1a; Spring注解定时任务使用不是很灵活&#xff0c;如果想要灵活的配置定时任务&#xff0c;可以使用xxl-job 或者 quartz等定时任务框架&#xff0c;但是过于繁琐&#xff0c;可能成本较大。所以可以使用ThreadPoolTaskScheduler来灵活处理定时任务 ThreadPoolT…

人工智能开发实战辅助诊断应用解析

内容导读 项目分析预备知识项目实战 一、项目分析 1、提出问题 随着人们生活水平的提升和健康意识的增强&#xff0c;民众定期进行身体健康体检已成为常态&#xff0c;这种早期的疾病检测和筛查可以及早发现身体里已经出现的异常体征信息&#xff0c;做出正确诊断和有效处理…

分布式系统的概念与设计模式

概念 定义&#xff1a;分布式系统是指将数据和计算任务分散到多个独立的计算机上&#xff0c;这些计算机通过网络进行通信和协作&#xff0c;共同对外提供服务。分布式系统不仅提高了系统的可靠性和可扩展性&#xff0c;还增强了系统的并发处理能力和数据管理能力。 特点&…

内存:生成式AI带来全新挑战与机遇

之前小编也写过多篇AI存储相关的文章&#xff0c;包括AI背景与分层存储的分析&#xff0c;以及AI存储重点从训练转向推理等内容。具体参考&#xff1a; 深度剖析&#xff1a;AI存储架构的挑战与解决方案 存储正式迈入超大容量SSD时代&#xff01; 这可能是最清晰的AI存储数据…

多线程篇七

多线程篇七 若笔者理解有误&#xff0c;欢迎交流指正⭐ 定时器 什么是定时器 听到定时器&#xff0c;首先想到的是“闹钟”.到一个设置好的时间之后就执行某个指定好的代码.(在实际开发中非常常用&#xff0c;如网络通信【邮件发送】) 你在抢演唱会门票&#xff0c;已经到了…

使用madExcept检测内存泄漏

代码异常堆栈跟踪&#xff1a;Mad Except 一、安装 官网 运行&#xff0c;选择madExcept5然后安装。 输入yes继续 二、使用 新建一个VCL项目 在project中多了一项设置 选择OK后会发现项目多了几个引用单元。 此时运行程序&#xff0c;再退出&#xff0c;会显示没有任何内存…