<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Qt圖形連線功能升級:支持多拐點(diǎn)和顏色區(qū)分


      摘要:本文在Qt圖形框架中擴(kuò)展了連線功能,實(shí)現(xiàn)了給連線添加多個拐點(diǎn)并使用不同顏色繪制的效果。該實(shí)現(xiàn)優(yōu)化了連線的可視化效果,提升了代碼可擴(kuò)展性,為復(fù)雜圖形編輯工具的開發(fā)提供了參考。


      關(guān)鍵詞:QGraphicsPathItem、拐點(diǎn)、QPainterPath、顏色設(shè)置、Qt圖形框架、連線


      完整代碼見最后。


      在上一篇文章的基礎(chǔ)上繼續(xù)實(shí)現(xiàn)兩個功能:

      • 給連線添加多個拐點(diǎn)
      • 使用不同的顏色給連線上色

      添加代碼:

      
      // 連線類,描述連線
      class CustomPath : public QGraphicsPathItem
      {
      public:
          CustomPath(QGraphicsItem *start, QGraphicsItem *end, QGraphicsItem *parent = nullptr);
          void updatePosition();   // 刷新連線
      
          void addPoint(CustomPoint *point);   // 設(shè)置拐點(diǎn)
      
      protected:
          void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
      
      private:
          QGraphicsItem *mStartItem = nullptr;  // 起點(diǎn)
          QGraphicsItem *mEndItem = nullptr;    // 終點(diǎn)
      
          QList<CustomPoint *> mPointList;     // 拐點(diǎn)列表
      
          QPainterPath mPath1;  // 連線1
          QPainterPath mPath2;  // 連線2
      
          QPointF getOffset(const QPointF &p1, const QPointF &p2);
          QLineF calculateAngleBisector(const QPointF& start, const QPointF& mid, const QPointF& end);
          QPointF calculateBisectorPoint(const QLineF &l1, const QLineF &bisector_line, const QPointF &p);
          bool calculateLineIsIntersect(const QPointF &start1, const QPointF &end1, const QPointF &start2, const QPointF &end2);
      
      };
      
      void CustomPath::addPoint(CustomPoint *point)
      {
          mPointList.append(point);
      }
      
      void CustomPath::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
      {
          painter->save();
          // 用不同的畫筆繪制連線
          painter->setPen(QPen(Qt::blue, 2.0));
          painter->drawPath(mPath1);
          painter->setPen(QPen(Qt::red, 2.0));
          painter->drawPath(mPath2);
      
          painter->restore();
      }
      
      void CustomPath::updatePosition()
      {
      
          QPointF start = mStartItem->pos();
          QPointF end = mEndItem->pos();
      
          QPointF start_offset = getOffset(start, mPointList.first()->pos());
          QPointF start_p1 = start + start_offset;
          QPointF start_p2 = start - start_offset;
      
          mPath1.clear();
          mPath2.clear();
          mPath1.moveTo(start_p1);
          mPath2.moveTo(start_p2);
      
          QList<QPointF> points;
          points.append(start);
          for (int i = 0, size = mPointList.size(); i < size; ++i) {
              points.append(mPointList.at(i)->pos());
          }
          points.append(end);
      
          Q_ASSERT(points.size() >= 3);
          // 記錄拐點(diǎn)的偏移點(diǎn)的位置
          QPointF next_start_p1 = start_p1, next_start_p2 = start_p2;
          // 每個拐點(diǎn)都只繪制前半段
          for (int i = 1, size = points.size(); i < size - 1; ++i) {
              QPointF temp_start = points.at(i-1), temp_point = points.at(i), temp_end = points.at(i+1);
              // 計(jì)算角平分線
              QLineF bisector_line = calculateAngleBisector(temp_start, temp_point, temp_end);
              QLineF start_line(temp_start, temp_point);
              // 計(jì)算交點(diǎn)
              QPointF p1_bst_itst = calculateBisectorPoint(start_line, bisector_line, next_start_p1);
              QPointF p2_bst_itst = calculateBisectorPoint(start_line, bisector_line, next_start_p2);
              // 判斷是否交叉
              if (calculateLineIsIntersect(next_start_p1, p1_bst_itst, next_start_p2, p2_bst_itst)) {
                  // 如果交叉
                  mPath1.lineTo(p2_bst_itst);
                  mPath2.lineTo(p1_bst_itst);
      
                  next_start_p1 = p2_bst_itst;
                  next_start_p2 = p1_bst_itst;
              } else {
                  mPath1.lineTo(p1_bst_itst);
                  mPath2.lineTo(p2_bst_itst);
      
                  next_start_p1 = p1_bst_itst;
                  next_start_p2 = p2_bst_itst;
              }
          }
      
          QPointF end_offset = getOffset(mPointList.last()->pos(), end);
          QPointF end_p1 = end + end_offset;
          QPointF end_p2 = end - end_offset;
          // 最后的一段
          if (calculateLineIsIntersect(next_start_p1, end_p1, next_start_p2, end_p2)) {
              // 如果交叉
              mPath1.lineTo(end_p2);
              mPath2.lineTo(end_p1);
          } else {
              mPath1.lineTo(end_p1);
              mPath2.lineTo(end_p2);
          }
      
          QPainterPath path;
          path.addPath(mPath1);
          path.addPath(mPath2);
      
          setPath(path);
      }
      
          QGraphicsScene *scene = new QGraphicsScene(this);
          ui->graphicsView->setScene(scene);
      
          CustomItem *item_start = new CustomItem;
          item_start->setPos(100, 100);
          scene->addItem(item_start);
      
          CustomItem *item_end = new CustomItem;
          item_end->setPos(200, 200);
          scene->addItem(item_end);
      
          CustomPath *path = new CustomPath(item_start, item_end);
          item_start->addPath(path);
          item_end->addPath(path);
          scene->addItem(path);
          // 添加拐點(diǎn)圖形
          CustomPoint *point1 = new CustomPoint(path);
          point1->setPos(100, 150);
          path->addPoint(point1);
          point1->setPathItem(path);
      
          CustomPoint *point2 = new CustomPoint(path);
          point2->setPos(150, 100);
          path->addPoint(point2);
          point2->setPathItem(path);
      
          path->updatePosition();
      
      

      在這段代碼中,

      • CustomPath添加了拐點(diǎn)列表QList<CustomPoint *>,用于多拐點(diǎn)的存儲;

      • 添加了QPainterPath 的兩條連線,用于不同的畫筆繪制;

      • 重寫paint()函數(shù);

      • 對應(yīng)拐點(diǎn)列表,修改updatePosition()函數(shù),對每個拐點(diǎn)進(jìn)行計(jì)算,刷新連線;

      • 添加測試代碼,添加第二個拐點(diǎn);


      效果如下:
      ????可見,兩條線的顏色在視覺上是有互換的情況的。本人能力有限,歡迎各位交流討論。
      image


      完整代碼:

      • mainwindow.h
      點(diǎn)擊折疊或展開代碼
      #ifndef MAINWINDOW_H
      #define MAINWINDOW_H
      
      #include <QMainWindow>
      #include <QtWidgets>
      
      QT_BEGIN_NAMESPACE
      namespace Ui { class MainWindow; }
      QT_END_NAMESPACE
      
      
      class CustomPath;
      class CustomPoint;
      // 圖形類,描述起點(diǎn)和終點(diǎn)
      class CustomItem : public QGraphicsRectItem
      {
      public:
         CustomItem(QGraphicsItem *parent = nullptr);
         void addPath(CustomPath *path);
      
      protected:
         QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
      
      private:
         QList<CustomPath *> mPathList; // 連線列表
      };
      // 連線類,描述連線
      class CustomPath : public QGraphicsPathItem
      {
      public:
         CustomPath(QGraphicsItem *start, QGraphicsItem *end, QGraphicsItem *parent = nullptr);
         void updatePosition();   // 刷新連線
      
         void addPoint(CustomPoint *point);   // 設(shè)置拐點(diǎn)
      
      protected:
         void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
      
      private:
         QGraphicsItem *mStartItem = nullptr;  // 起點(diǎn)
         QGraphicsItem *mEndItem = nullptr;    // 終點(diǎn)
      
         QList<CustomPoint *> mPointList;     // 拐點(diǎn)列表
      
         QPainterPath mPath1;  // 連線1
         QPainterPath mPath2;  // 連線2
      
      
         QPointF getOffset(const QPointF &p1, const QPointF &p2);
         QLineF calculateAngleBisector(const QPointF& start, const QPointF& mid, const QPointF& end);
         QPointF calculateBisectorPoint(const QLineF &l1, const QLineF &bisector_line, const QPointF &p);
         bool calculateLineIsIntersect(const QPointF &start1, const QPointF &end1, const QPointF &start2, const QPointF &end2);
      
      };
      // 拐點(diǎn)類
      class CustomPoint : public QGraphicsEllipseItem
      {
      public:
         CustomPoint(QGraphicsItem *parent = nullptr);
         void setPathItem(CustomPath *pathItem);
      
      protected:
         QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
      
      private:
         CustomPath *mPathItem = nullptr;   // 拐點(diǎn)所屬連線
      };
      
      class MainWindow : public QMainWindow
      {
         Q_OBJECT
      
      public:
         MainWindow(QWidget *parent = nullptr);
         ~MainWindow();
      
      private:
         Ui::MainWindow *ui;
      
         void initGraphics();
      };
      #endif // MAINWINDOW_H
      
      
      

      • mainwindow.cpp
      點(diǎn)擊折疊或展開代碼
      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      
      
      
      MainWindow::MainWindow(QWidget *parent)
         : QMainWindow(parent)
         , ui(new Ui::MainWindow)
      {
         ui->setupUi(this);
      
         initGraphics();
      }
      
      MainWindow::~MainWindow()
      {
         delete ui;
      }
      
      void MainWindow::initGraphics()
      {
         QGraphicsScene *scene = new QGraphicsScene(this);
         ui->graphicsView->setScene(scene);
      
         CustomItem *item_start = new CustomItem;
         item_start->setPos(100, 100);
         scene->addItem(item_start);
      
         CustomItem *item_end = new CustomItem;
         item_end->setPos(200, 200);
         scene->addItem(item_end);
      
         CustomPath *path = new CustomPath(item_start, item_end);
         item_start->addPath(path);
         item_end->addPath(path);
         scene->addItem(path);
         // 添加拐點(diǎn)圖形
         CustomPoint *point1 = new CustomPoint(path);
         point1->setPos(100, 150);
         path->addPoint(point1);
         point1->setPathItem(path);
      
         CustomPoint *point2 = new CustomPoint(path);
         point2->setPos(150, 100);
         path->addPoint(point2);
         point2->setPathItem(path);
      
         path->updatePosition();
      
      }
      
      
      CustomItem::CustomItem(QGraphicsItem *parent) : QGraphicsRectItem(parent)
      {
         // 設(shè)置形狀
         setRect(-5, -5, 10, 10);
         // 設(shè)置顏色
         setBrush(Qt::black);
         // 設(shè)置可移動
         setFlag(QGraphicsItem::ItemIsMovable, true);
         // 設(shè)置可發(fā)送幾何變動,可在itemChange中進(jìn)行檢測
         setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
      }
      // 添加連線
      void CustomItem::addPath(CustomPath *path)
      {
         mPathList.append(path);
      }
      
      QVariant CustomItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
      {
         switch (change) {
         // 當(dāng)位置變動時,刷新連線
         case QGraphicsItem::ItemPositionHasChanged:
         {
             for (int i = 0, size = mPathList.size(); i < size; ++i) {
                 mPathList.at(i)->updatePosition();
             }
         }
      
         default:
             break;
         }
      
         return QGraphicsItem::itemChange(change, value);
      }
      
      CustomPath::CustomPath(QGraphicsItem *start, QGraphicsItem *end, QGraphicsItem *parent)
         : QGraphicsPathItem(parent), mStartItem(start), mEndItem(end)
      {
         // 設(shè)置繪制畫筆,顏色黑色,筆寬為1
         setPen(QPen(Qt::black, 1));
      }
      
      QPointF CustomPath::getOffset(const QPointF &p1, const QPointF &p2)
      {
         QPointF dp = p1 - p2;
         QPointF offset;
         // 根據(jù)差值判斷
         if (dp.x() * dp.y() >= 0) {
             // 設(shè)置偏移量
             offset = QPointF(-5, 5);
         } else {
             offset = QPointF(5, 5);
         }
         return offset;
      }
      
      void CustomPath::updatePosition()
      {
      
         QPointF start = mStartItem->pos();
         QPointF end = mEndItem->pos();
      
         QPointF start_offset = getOffset(start, mPointList.first()->pos());
         QPointF start_p1 = start + start_offset;
         QPointF start_p2 = start - start_offset;
      
         mPath1.clear();
         mPath2.clear();
         mPath1.moveTo(start_p1);
         mPath2.moveTo(start_p2);
      
         QList<QPointF> points;
         points.append(start);
         for (int i = 0, size = mPointList.size(); i < size; ++i) {
             points.append(mPointList.at(i)->pos());
         }
         points.append(end);
      
         Q_ASSERT(points.size() >= 3);
         QPointF next_start_p1 = start_p1, next_start_p2 = start_p2;
         for (int i = 1, size = points.size(); i < size - 1; ++i) {
             QPointF temp_start = points.at(i-1), temp_point = points.at(i), temp_end = points.at(i+1);
             // 計(jì)算角平分線
             QLineF bisector_line = calculateAngleBisector(temp_start, temp_point, temp_end);
             QLineF start_line(temp_start, temp_point);
             // 計(jì)算交點(diǎn)
             QPointF p1_bst_itst = calculateBisectorPoint(start_line, bisector_line, next_start_p1);
             QPointF p2_bst_itst = calculateBisectorPoint(start_line, bisector_line, next_start_p2);
             // 判斷是否交叉
             if (calculateLineIsIntersect(next_start_p1, p1_bst_itst, next_start_p2, p2_bst_itst)) {
                 // 如果交叉
                 mPath1.lineTo(p2_bst_itst);
                 mPath2.lineTo(p1_bst_itst);
      
                 next_start_p1 = p2_bst_itst;
                 next_start_p2 = p1_bst_itst;
             } else {
                 mPath1.lineTo(p1_bst_itst);
                 mPath2.lineTo(p2_bst_itst);
      
                 next_start_p1 = p1_bst_itst;
                 next_start_p2 = p2_bst_itst;
             }
         }
      
         QPointF end_offset = getOffset(mPointList.last()->pos(), end);
         QPointF end_p1 = end + end_offset;
         QPointF end_p2 = end - end_offset;
      
         if (calculateLineIsIntersect(next_start_p1, end_p1, next_start_p2, end_p2)) {
             // 如果交叉
             mPath1.lineTo(end_p2);
             mPath2.lineTo(end_p1);
         } else {
             mPath1.lineTo(end_p1);
             mPath2.lineTo(end_p2);
         }
      
         QPainterPath path;
         path.addPath(mPath1);
         path.addPath(mPath2);
      
         setPath(path);
      }
      
      void CustomPath::addPoint(CustomPoint *point)
      {
         mPointList.append(point);
      }
      
      void CustomPath::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
      {
         painter->save();
      
         painter->setPen(QPen(Qt::blue, 2.0));
         painter->drawPath(mPath1);
         painter->setPen(QPen(Qt::red, 2.0));
         painter->drawPath(mPath2);
      
         painter->restore();
      }
      
      // 計(jì)算角平分線
      QLineF CustomPath::calculateAngleBisector(const QPointF &start, const QPointF &mid, const QPointF &end)
      {
         // 計(jì)算向量A和B
         QPointF vectorA = start - mid;
         QPointF vectorB = end - mid;
      
         // 歸一化向量A和B
         qreal lengthA = std::hypot(vectorA.x(), vectorA.y());
         qreal lengthB = std::hypot(vectorB.x(), vectorB.y());
         QPointF unitA = vectorA / lengthA;
         QPointF unitB = vectorB / lengthB;
      
         // 計(jì)算角平分線向量
         QPointF bisector = unitA + unitB;
      
         // 如果共線則向量為零,需要使用垂線
         if (bisector.isNull()) {
             bisector = QPointF(-unitA.y(), unitA.x());
         }
      
         // 歸一化角平分線向量
         qreal lengthBisector = std::hypot(bisector.x(), bisector.y());
         QPointF unitBisector = bisector / lengthBisector;
      
         // 從中點(diǎn)出發(fā),沿角平分線方向繪制一條直線
         QPointF bisectorEnd = mid + unitBisector * 100; // 100為長度,可根據(jù)需要調(diào)整
         QPointF bisectorEnd_n = mid - unitBisector * 100;
         return QLineF(bisectorEnd_n, bisectorEnd);
         //    return unitBisector;
      }
      // 計(jì)算過p點(diǎn)的l1的平行線與bisector_line的交點(diǎn)
      QPointF CustomPath::calculateBisectorPoint(const QLineF &l1, const QLineF &bisector_line, const QPointF &p)
      {
         // 起點(diǎn)到拐點(diǎn)連線的向量
         QPointF lp(l1.p2() - l1.p1());
         qreal length = std::hypot(lp.x(), lp.y());
         QPointF unit = lp / length;
      
         // 過偏移點(diǎn)的平行線
         QLineF line(p, p+unit*100);
      
         // 計(jì)算交點(diǎn)
         QPointF intersection;
         QLineF::IntersectType type = line.intersects(bisector_line, &intersection);
         return intersection;
      }
      // 判斷是否交叉
      bool CustomPath::calculateLineIsIntersect(const QPointF &start1, const QPointF &end1,
                                                     const QPointF &start2, const QPointF &end2)
      {
         QLineF line1(start1, end1);
         QLineF line2(start2, end2);
         QPointF intersection;
         QLineF::IntersectType type = line1.intersects(line2, &intersection);
         if (type == QLineF::BoundedIntersection && ! intersection.isNull()) {
             return true;
         } else {
             return false;
         }
      }
      
      CustomPoint::CustomPoint(QGraphicsItem *parent)
         : QGraphicsEllipseItem(parent)
      {
         // 設(shè)置圖形為圓形
         setRect(-2, -2, 4, 4);
         setBrush(Qt::black);
         setFlag(QGraphicsItem::ItemIsMovable, true);
         setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
      }
      
      QVariant CustomPoint::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
      {
         switch (change) {
         case QGraphicsItem::ItemPositionHasChanged:
         {
             // 當(dāng)拐點(diǎn)位置發(fā)生變化,刷新連線
             if (mPathItem) {
                 mPathItem->updatePosition();
             }
         }
      
         default:
             break;
         }
      
         return QGraphicsItem::itemChange(change, value);
      }
      
      void CustomPoint::setPathItem(CustomPath *pathItem)
      {
         mPathItem = pathItem;
      }
      
      
      

      posted @ 2025-03-02 19:50  薄暮知秋  閱讀(183)  評論(0)    收藏  舉報
      /*http://www.rzrgm.cn/lingr7/p/15651906.html*/ /*自動顯示目錄導(dǎo)航*/
      主站蜘蛛池模板: 久久综合国产一区二区三区| 视频一区二区 国产视频| 精品国产乱码久久久久app下载| 色综合色狠狠天天综合网| 北岛玲亚洲一区二区三区| 国内少妇偷人精品视频| 一本大道久久香蕉成人网| 国产精品黄色精品黄色大片| 国产永久免费高清在线| 国内自拍偷拍福利视频看看| 精品国产色情一区二区三区| 国产精品视频亚洲二区| 尤物国精品午夜福利视频| 视频二区国产精品职场同事| 国产亚洲欧洲AⅤ综合一区| 久久天天躁夜夜躁狠狠85| 野花社区www视频日本| 国产99青青成人A在线| 成人午夜福利精品一区二区| 亚洲免费成人av一区| 美女裸体十八禁免费网站| 特黄做受又粗又大又硬老头 | 国产精品久久久久久亚洲色| 18禁在线永久免费观看| 亚洲中文字幕综合小综合| 成人国产精品一区二区网站公司| 久久月本道色综合久久| 人妻在线中文字幕| 午夜福利一区二区三区在线观看| 免费观看激色视频网站| 日韩av一区二区三区不卡| 四房播色综合久久婷婷| 麻豆妓女爽爽一区二区三| 亚洲成亚洲成网中文字幕| 国精偷拍一区二区三区| 成年女人碰碰碰视频播放| 中文字幕人妻丝袜美腿乱| 中文字幕亚洲综合久久2020| 欧美成人精品高清在线播放| 2021最新国产精品网站| 久久精品亚洲国产成人av|