25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
5.8 KiB

  1. #ifndef PLCDOCUMENT_H
  2. #define PLCDOCUMENT_H
  3. #include "basedocument.h"
  4. #include "plcitems.h"
  5. #include <QGraphicsScene>
  6. #include <QGraphicsView>
  7. #include <QGraphicsLineItem>
  8. #include <QGraphicsRectItem>
  9. #include <QGraphicsEllipseItem>
  10. #include <QMap>
  11. #include <QSet>
  12. #include <QVector>
  13. #include <QDragEnterEvent>
  14. #include <QDragMoveEvent>
  15. #include <QDropEvent>
  16. #include <QMimeData>
  17. #include <QPair>
  18. const int DEFAULT_ROWS = 11;
  19. const int DEFAULT_COLUMNS = 24;
  20. const int DEFAULT_CELL_SIZE = 70;
  21. class PLCItem;
  22. class ConnectionLine;
  23. class PLCDocument : public BaseDocument
  24. {
  25. Q_OBJECT
  26. public:
  27. enum TerminalType
  28. {
  29. NoTerminal = 0,
  30. LeftTerminal,
  31. RightTerminal,
  32. RowTerminal
  33. };
  34. enum ConnectionSourceType
  35. {
  36. ConnectionNone, // 无连接
  37. ConnectionFromItem, // 起点是元件的端子
  38. ConnectionFromRowTerminal // 起点是行触点
  39. };
  40. explicit PLCDocument(QWidget *parent = nullptr);
  41. ~PLCDocument() override;
  42. QString title() const override;
  43. QGraphicsView *view() const { return m_view; }
  44. QGraphicsScene *scene() const { return m_scene; }
  45. bool saveToFile(const QString &filePath) override;
  46. bool loadFromFile(const QString &filePath) override;
  47. void createPLCItem(const QString &type, const QPointF &pos);
  48. void startConnection(PLCItem *startItem, TerminalType startTerminal);
  49. void startConnectionFromRowTerminal(int row);
  50. void clearCurrentConnection();
  51. bool tryEndConnection(PLCItem *endItem, TerminalType endTerminal);
  52. void setSimulationRunning(bool running);
  53. void resetSimulation();
  54. void setCurrentTool(const QString &tool) { m_currentTool = tool; }
  55. int rowCount() const { return m_rows; }
  56. int columnCount() const { return m_columns; }
  57. int cellSize() const { return m_cellSize; }
  58. QPointF snapToCellCenter(const QPointF &pos) const;
  59. QPointF constrainToTable(const QPointF &pos) const;
  60. void setTitle(const QString &title) { m_title = title; }
  61. void deleteSelectedItems();
  62. void copySelectedItem();
  63. void pasteItem();
  64. protected:
  65. bool eventFilter(QObject *obj, QEvent *event) override;
  66. void keyPressEvent(QKeyEvent* event) override;
  67. private slots:
  68. void handleSceneChanged();
  69. void onRowTerminalConnection();
  70. private:
  71. QList<ConnectionLine*> findConnectionsUnderItem(PLCItem* item) const;
  72. bool lineIntersectsRect(const QLineF& line, const QRectF& rect) const;
  73. bool splitConnection(ConnectionLine* originalLine, PLCItem* insertItem);
  74. bool isPointOnLineSegment(const QPointF& point, const QLineF& line) const;
  75. void createRealTable();
  76. TerminalType whichTerminal(const QPointF& scenePos, PLCItem* item) const;
  77. bool isTerminalUsed(PLCItem* item, TerminalType terminal) const;
  78. void handleItemPositionChange(PLCItem *item);
  79. bool isCellOccupied(int col, int row, PLCItem* excludeItem) const;
  80. void updateConnections();
  81. void createContextMenu(QPoint globalPos);
  82. PLCItem* createItemByType(PLCItem::ItemType type);
  83. void removeInvalidConnectionsForItem(PLCItem* movedItem);
  84. QList<PLCItem*> allPLCItems() const;
  85. // 新增:获取元件在连线上的位置比例(0-1)
  86. qreal getPositionRatioOnLine(PLCItem* item, ConnectionLine* line) const;
  87. QGraphicsScene *m_scene;
  88. QGraphicsView *m_view;
  89. QString m_currentTool;
  90. ConnectionSourceType m_connectionSourceType = ConnectionNone;
  91. PLCItem *m_connectionStartItem = nullptr;
  92. TerminalType m_startTerminal = NoTerminal;
  93. int m_connectionStartRow = -1;
  94. QGraphicsLineItem *m_tempLine = nullptr;
  95. QList<ConnectionLine*> m_connections;
  96. QMap<PLCItem*, QMap<TerminalType, bool>> terminalConnections;
  97. bool m_simulationRunning = false;
  98. QSet<PLCItem*> m_activeItems;
  99. int m_rows = DEFAULT_ROWS;
  100. int m_columns = DEFAULT_COLUMNS;
  101. int m_cellSize = DEFAULT_CELL_SIZE;
  102. QGraphicsRectItem* m_tableFrame = nullptr;
  103. QVector<QGraphicsLineItem*> m_horizontalLines;
  104. QVector<QGraphicsLineItem*> m_verticalLines;
  105. QString m_title;
  106. QVector<QGraphicsEllipseItem*> m_rowTerminals;
  107. QMap<QGraphicsEllipseItem*, int> m_rowTerminalMap;
  108. QMap<PLCItem*, QPointF> m_lastValidPositions;
  109. QSet<PLCItem*> m_processingItems;
  110. bool m_loadingFile = false;
  111. PLCItem* m_copiedItem = nullptr;
  112. };
  113. class ConnectionLine : public QGraphicsLineItem
  114. {
  115. public:
  116. ConnectionLine(
  117. PLCItem *startItem, PLCDocument::TerminalType startTerminal,
  118. PLCItem *endItem, PLCDocument::TerminalType endTerminal,
  119. QGraphicsItem *parent = nullptr
  120. );
  121. void updatePosition();
  122. PLCItem* startItem() const { return m_startItem; }
  123. PLCItem* endItem() const { return m_endItem; }
  124. PLCDocument::TerminalType startTerminal() const { return m_startTerminal; }
  125. PLCDocument::TerminalType endTerminal() const { return m_endTerminal; }
  126. void setRowTerminalTargetRow(int row) { m_rowTerminalTargetRow = row; }
  127. int rowTerminalTargetRow() const { return m_rowTerminalTargetRow; }
  128. void setRowTerminalSourceRow(int row) { m_rowTerminalSourceRow = row; }
  129. int rowTerminalSourceRow() const { return m_rowTerminalSourceRow; }
  130. void setStartTerminalPoint(const QPointF& point) { m_startTerminalPoint = point; }
  131. void setEndTerminalPoint(const QPointF& point) { m_endTerminalPoint = point; }
  132. // 新增:设置这条连线是否正在被处理
  133. void setProcessing(bool processing) { m_processing = processing; }
  134. bool isProcessing() const { return m_processing; }
  135. private:
  136. PLCItem *m_startItem;
  137. PLCDocument::TerminalType m_startTerminal;
  138. PLCItem *m_endItem;
  139. PLCDocument::TerminalType m_endTerminal;
  140. QPointF m_startTerminalPoint;
  141. QPointF m_endTerminalPoint;
  142. int m_rowTerminalTargetRow = -1;
  143. int m_rowTerminalSourceRow = -1;
  144. bool m_processing = false; // 用于防止递归处理
  145. };
  146. #endif // PLCDOCUMENT_H