【QT】QGraphicsPathItem自动寻路画线连接QGraphicsRectItem方块(非最优路线)

效果展示

自动寻路连线

工具

QT Creator 4.3.0
QGraphicsPathItem 画路径
QGraphicsRectItem 画方块
QGraphicsView QGraphicsScene 视图画板

概述

本文描述的连线方式与曼哈顿连线类似,仅包含水平和垂直方向的线,但不是最优路线
尝试过用Astar算法去连接两个方块,但由于我的视图设置的无限大,而我又不想设置太大的网格,尽管我限制了寻路的范围,但是连接两个方块还是计算了三分钟,改善了Astar算法后寻路的计算时间还是不可接受,理清了自己的需求后,我需要的是不要最优但接近最优的路线,这样能节省很大的计算量。基本是感觉不到路径计算的时间。
寻路方式及原理很简单,傻瓜式寻路,基本思想是从起点出发,假设先水平走,水平遇障垂直走,垂直走时检测水平是否仍有障碍,无障后继续水平走直到接近终点的水平坐标附近再切换到垂直走,然后和水平走原理相同。
也可以这么理解,就是哪有障碍物往哪走。遇到障碍物就绕开,那么什么时候认为寻路成功呢,当然不需要傻乎乎的走到终点,而是每一步计算完毕后以起点坐标和终点坐标画一个矩形。
在这里插入图片描述
当红色路线无障碍物或黑色路线无障碍物时,就可以判断寻路成功了
当然这种寻路方式有一定的前提条件:方块与方块之间要有足够的间隔,不能完全堵死,要给线留出通过空间,所以方块与方块之间要有碰撞检测功能。
当然,方块堵死话任何寻路算法都没办法,方块之间留空隙,是为了让寻路更快捷。

方块

画方块(QGraphicsRectItem)就不在这里叙述了,这里主要展示方块间碰撞检测的距离:

void logic_block::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
   
    setCursor(Qt::ArrowCursor);  // 设置鼠标样式为箭头
    QGraphicsRectItem::mouseReleaseEvent(event);
    // 获取当前块的边界矩形
    QRectF currentRect = sceneBoundingRect();
    // 遍历所有块
    QList<QGraphicsItem*> allBlocks = scene()->items();
    foreach (QGraphicsItem* item, allBlocks) {
   
        if (item == this || (child_group_list.contains(item)) == true)
            continue;

        if (item->type() >= QGraphicsItem::UserType + BLOCK_TYPE_LOGIC) {
   
            // 获取其他块的边界矩形
            QRectF otherRect = item->sceneBoundingRect();
            // 判断是否与其他块及其周围一定距离范围内重叠
            if (currentRect.intersects(otherRect.adjusted(-BLOCK_SPCING, -BLOCK_SPCING, BLOCK_SPCING, BLOCK_SPCING))) {
   
                // 重叠处理,将块移回原位
                setPos(originalPos);
                break;
            }
        }
    }
}

BLOCK_SPCING是方块本身再往外一段空间,相当于虚拟了一个大矩形,这个大矩形每条边都距离方块BLOCK_SPCING距离,这里我设置的BLOCK_SPCING大小为40

#define LOGIC_BLOCK_WIDTH      50   //逻辑块的宽度
#define LOGIC_BLOCK_HEIGHT     100  //逻辑块的高度
#define CONDITION_BLOCK_WIDTH  80   //条件块的宽度
#define CONDITION_BLOCK_HEIGHT 20   //条件块的高度
#define CONNECT_POINT_WIDTH    10   //块上连接点的大小
#define CONNECT_POINT_HEIGHT   10
#define BLOCK_SPCING           (CONNECT_POINT_WIDTH * 4)  //块之间的最小距离  防止块的碰撞与重叠

连接点

我在每个方块上都添加了输入连接点和输出连接点,输出只能与输入连接点连接。相同属性的连接点无法互连。当然这是我项目需求上的限制,本文只描述连接点的作用。

连线

我们用QGraphicsPathItem画线,用QPainterPath给线设置起点与各个节点

QPainterPath path;
    path.moveTo(start_point);
    path.lineTo(probe_point);
    setPath(path);

有必要提醒的是,每次想要重新划线设置路径时,一定要重新新建QPainterPath 变量,否则无法消除原来的线段,目前没找到QPainterPath 类的线段清除手段。
那么现在开始寻路吧
当我们获取到起点和终点时,就有了目标:
1.起步选向:用起点和终点画一个矩形,矩形有两个横边和两个竖边,如果边与其他快有重叠,则记这个边为障碍边,那么横边和竖边的障碍边的情况都分辨有0/1/2三种情况,那我们那边障碍边比较多,我们往那个方向走。

path_info.longitudinal_intersect_num = 0;
    path_info.transverse_intersect_num   = 0;
    QPointF rect_point1(probe_end_point.x(), probe_start_point.y());  //矩形的其他点,此点与起点组成横线
    QPointF rect_point2(probe_start_point.x(), probe_end_point.y());  //矩形的其他点,此点与起点组成纵线
    QLineF  transversse_line1(probe_start_point, rect_point1);        //与起点相连的横线
    QLineF  transversse_line2(rect_point2, probe_end_point);          //与终点相连的横线
    QLineF  longitudinal_line1(probe_start_point, rect_point2);       //与起点相连的纵线
    QLineF  longitudinal_line2(rect_point1, probe_end_point);         //与终点相连的纵线
    path_info.transversse_line1_is_none  = true;                      //横向线与纵向线是否无遮挡
    path_info.transversse_line2_is_none  = true;
    path_info.longitudinal_line1_is_none = true;
    path_info.longitudinal_line2_is_none = true;
    /* 判断四条线有几条线与其他块相交 */
    if (check_line_intersects_rect(transversse_line1)) {
   
        path_info.transverse_intersect_num
  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值