DiagramDesigner/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp

693 lines
24 KiB
C++
Raw Normal View History

2024-12-07 17:24:36 +08:00
#include "graphicsItem/electricConnectLineItem.h"
#include <QGraphicsScene>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
2024-12-07 17:24:36 +08:00
ElectricConnectLineItem::ElectricConnectLineItem(QGraphicsItem *parent)
: GraphicsProjectModelItem(parent)
2025-11-14 19:31:09 +08:00
{
initial();
}
ElectricConnectLineItem::ElectricConnectLineItem(const ElectricConnectLineItem& obj)
: GraphicsProjectModelItem(obj)
{
initial();
m_lstPoints = obj.m_lstPoints;
}
ElectricConnectLineItem::~ElectricConnectLineItem()
{
}
ElectricConnectLineItem* ElectricConnectLineItem::clone() const
{
return new ElectricConnectLineItem(*this);
}
void ElectricConnectLineItem::initial()
2024-12-07 17:24:36 +08:00
{
m_boundingRect = QRectF();
2024-12-07 17:24:36 +08:00
m_pen = QPen(Qt::black);
m_brush = QBrush(Qt::NoBrush);
setHandleVisible(false);
setFunctionHandleIfShow(false);
setFunctionHandleEnaable(false);
m_lstPoints.push_back(QPointF()); //起点
m_lstPoints.push_back(QPointF()); //终点
_curLine = QPoint();
2024-12-07 17:24:36 +08:00
}
void ElectricConnectLineItem::setStartPoint(const QPointF& p)
{
int n = m_lstPoints.size();
if(n)
{
if(n >2)
{
if(m_lstPoints[0].x() == m_lstPoints[1].x()) //相邻点在垂直方向,水平移动,否则垂直移动
{
m_lstPoints[1].setX(p.x());
}
else
{
m_lstPoints[1].setY(p.y());
}
}
m_lstPoints[0] = p;
}
}
void ElectricConnectLineItem::setEndPoint(const QPointF& p)
{
int n = m_lstPoints.size();
if(n)
{
if(n >2)
{
if(m_lstPoints[n-1].x() == m_lstPoints[n-2].x()) //相邻点在垂直方向,水平移动,否则垂直移动
{
m_lstPoints[n-2].setX(p.x());
}
else
{
m_lstPoints[n-2].setY(p.y());
}
}
m_lstPoints[n-1] = p;
}
}
QPainterPath ElectricConnectLineItem::shape() const
2024-12-07 17:24:36 +08:00
{
QPainterPath path;
//path.addPath(m_points);
path.addPath(m_pointsBoundingRect);
2024-12-07 17:24:36 +08:00
return path;
}
QRectF ElectricConnectLineItem::boundingRect() const
{
return m_boundingRect;
}
2024-12-07 17:24:36 +08:00
void ElectricConnectLineItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
if (option->state & QStyle::State_Selected)
{
painter->setPen(Qt::red);
}
else
{
2025-12-03 18:27:49 +08:00
if(_curMonitorStateEnable){ //当前状态被设置
painter->setPen(QPen(_curMonitorStateColor));
}
else
painter->setPen(m_pen);
}
2024-12-07 17:24:36 +08:00
painter->setBrush(m_brush);
painter->drawPath(m_points);
}
void ElectricConnectLineItem::moveLine(QPointF pos)
{
QPointF delta = pos - m_lastPoint;
if(_curLine.isNull())
{
if(m_lstPoints.size() > 1)
{
int n = m_lstPoints.size();
for(int i = 0;i < m_lstPoints.size() -1;++i)
{
QPointF p1 = m_lstPoints[i];
QPointF p2 = m_lstPoints[i+1];
if(p1.x() == p2.x() && abs(p1.x() - pos.x()) < 2) //在相同竖线
{
if(p1.y() > p2.y())
{
if(pos.y() > p2.y() && pos.y() < p1.y()) //在竖线上
{
if(i == 0 ) //起点是连接点,创建复制点
{
m_lstPoints.prepend(p1);
m_lstPoints.prepend(p1);
i+=2;
if(m_lstPoints.size() < 6) //补齐后端
{
m_lstPoints.append(m_lstPoints.last());
}
}
if(i+1 == n-1) //终点是连接点,创建复制点
{
m_lstPoints.append(p2);
m_lstPoints.append(p2);
m_lstPoints[i+1] = p2;
if(m_lstPoints.size() < 6) //补齐前端,移动后至少6个点
{
m_lstPoints.prepend(m_lstPoints.first());
i+=1;
}
}
//qDebug() << 1 <<" "<<i;
_curLine = QPoint(i,1);
break;
}
}
else if(p1.y() < p2.y())
{
if(pos.y() < p2.y() && pos.y() > p1.y()) //在竖线上
{
if(i == 0) //起点是连接点,创建复制点
{
m_lstPoints.prepend(p1);
m_lstPoints.prepend(p1);
i+=2;
if(m_lstPoints.size() < 6) //补齐后端
{
m_lstPoints.append(m_lstPoints.last());
}
}
if(i+1 == n-1) //终点是连接点,创建复制点
{
m_lstPoints.append(p2);
m_lstPoints.append(p2);
m_lstPoints[i+1] = p2;
if(m_lstPoints.size() < 6) //补齐前端
{
m_lstPoints.prepend(m_lstPoints.first());
i+=1;
}
}
//qDebug() << 2 <<" "<<i;
_curLine = QPoint(i,1);
break;
}
}
}
else if(p1.y() == p2.y() && abs(p1.y() - pos.y()) < 2) //在相同横线
{
if(p1.x() > p2.x())
{
if(pos.x() > p2.x() && pos.x() < p1.x())
{
if(i == 0) //起点是连接点,创建复制点
{
m_lstPoints.prepend(p1);
m_lstPoints.prepend(p1);
i+=2;
if(m_lstPoints.size() < 6) //补齐后端
{
m_lstPoints.append(m_lstPoints.last());
}
}
if(i+1 == n-1) //终点是连接点,创建复制点
{
m_lstPoints.append(p2);
m_lstPoints.append(p2);
if(m_lstPoints.size() < 6) //补齐前端,移动后至少6个点
{
m_lstPoints.prepend(m_lstPoints.first());
i+=1;
}
}
//qDebug() << 3 <<" "<<i;
_curLine = QPoint(i,-1);
break;
}
}
else if(p1.x() < p2.x())
{
if(pos.x() < p2.x() && pos.x() > p1.x())
{
if(i == 0) //起点是连接点,创建复制点
{
m_lstPoints.prepend(p1);
m_lstPoints.prepend(p1);
i+=2;
m_lstPoints[i] = p1;
if(m_lstPoints.size() < 6) //补齐后端
{
m_lstPoints.append(m_lstPoints.last());
}
}
if(i+1 == n-1) //终点是连接点,创建复制点
{
m_lstPoints.append(p2);
m_lstPoints.append(p2);
if(m_lstPoints.size() < 6) //补齐前端
{
m_lstPoints.prepend(m_lstPoints.first());
i+=1;
}
}
//qDebug() << 4 <<" "<<i;
_curLine = QPoint(i,-1);
break;
}
}
}
}
}
}
else
{
int n = _curLine.x();
//qDebug() << n <<" "<<_curLine.y();
//if(m_lstPoints.size() > 3)
{
if(_curLine.y() == 1) //竖线
{
if(n == 0) //起点是原点
{
QPointF p(0,delta.y()); //原点不动
m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只竖直移动
m_lstPoints[n +2] = m_lstPoints[n +2] + p; //第三个点只竖直移动
}
else if(n == 1)
{
QPointF p(delta.x(),0);
m_lstPoints[n] += p; //第一个点只水平移动
m_lstPoints[n +1] += p; //第二个点只水平移动
}
else if(n == m_lstPoints.size()-2) //起点是倒数第二个点
{
QPointF p(0,delta.y());
m_lstPoints[n] += p; //起点只上下移动
m_lstPoints[n-1] += p; //上个点只竖直移动
}
else if(n == m_lstPoints.size()-3) //起点是倒数第三个点
{
QPointF py(0,delta.y());
QPointF px(delta.x(),0);
m_lstPoints[n-1] += py; //上个点只垂直移动
m_lstPoints[n] += delta; //起点任意动
m_lstPoints[n+1] += px; //第二个点只水平移动
}
else
{
m_lstPoints[n -1].setY(m_lstPoints[n ].y());
m_lstPoints[n] += delta;
m_lstPoints[n +1] += delta;
m_lstPoints[n +2].setY(m_lstPoints[n +1].y());
}
}
else //横线
{
if(n == 0) //起点是原点
{
QPointF p(delta.x(),0); //原点不动
m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只水平移动
m_lstPoints[n +2] = m_lstPoints[n +2] + p; //第三个点只水平移动
}
else if(n == 1)
{
QPointF p(0,delta.y());
m_lstPoints[n] = m_lstPoints[n] + p; //第一个点只竖直移动
m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只竖直移动
}
else if(n == m_lstPoints.size()-2) //起点是倒数第二个点
{
QPointF p(delta.x(),0);
m_lstPoints[n] += p; //起点水平移动
m_lstPoints[n-1] += p; //上个点只水平移动
}
else if(n == m_lstPoints.size()-3) //起点是倒数第三个点
{
QPointF py(0,delta.y());
QPointF px(delta.x(),0);
m_lstPoints[n-1] += px; //上个点只水平移动
m_lstPoints[n] += delta; //起点任意动
m_lstPoints[n+1] += py; //第二个点只上下移动
}
else
{
m_lstPoints[n -1].setX(m_lstPoints[n].x());
m_lstPoints[n] += delta;
m_lstPoints[n +1] += delta;
m_lstPoints[n +2].setX(m_lstPoints[n +1].x());
}
}
}
calculatePath();
}
m_lastPoint = pos;
}
2024-12-07 17:24:36 +08:00
void ElectricConnectLineItem::calculatePath()
{
if (m_lstPoints.size() < 2) return;
QPointF start = m_lstPoints.first();
QPointF end = m_lstPoints.last();
qDebug() << "\n=== calculatePath ===";
qDebug() << "Start:" << start << "End:" << end;
// 创建新路径
m_points = QPainterPath();
m_points.moveTo(start);
qDebug() << "Initialized path, current position:" << m_points.currentPosition();
// 获取元件
QList<QRectF> components = getComponentCollisionRects();
qDebug() << "Found" << components.size() << "components";
// 检查起点终点距离
qDebug() << "Distance:" << QLineF(start, end).length();
// 如果距离很近,直接连接
if (QLineF(start, end).length() < 10) {
qDebug() << "Points are very close, direct connection";
m_points.lineTo(end);
} else {
// 生成路径
generateAvoidancePath(start, end, components);
}
// 验证路径
qDebug() << "After generation - Path element count:" << m_points.elementCount();
qDebug() << "After generation - Current position:" << m_points.currentPosition();
if (m_points.elementCount() <= 1) {
qWarning() << "Path has only" << m_points.elementCount() << "elements! Adding direct line";
m_points.lineTo(end);
}
// 确保路径结束于终点
if (m_points.currentPosition() != end) {
qWarning() << "Path does not end at destination! Adding final segment";
qDebug() << "Expected end:" << end << "Actual end:" << m_points.currentPosition();
m_points.lineTo(end);
}
update();
m_boundingRect = m_points.boundingRect();
prepareGeometryChange();
qDebug() << "Final path bounds:" << m_boundingRect;
qDebug() << "=== calculatePath end ===\n";
}
// 使用形状进行避障
void ElectricConnectLineItem::generateAvoidancePath(const QPointF& start, const QPointF& end,
const QList<QRectF>& components)
{
qDebug() << "=== generateAvoidancePath (rectilinear) ===";
m_points = QPainterPath();
m_points.moveTo(start);
// 生成候选路径列表,按长度排序
QMultiMap<double, QList<QPointF>> candidatePaths;
// 1. 收集所有可能的直角路径
collectRectilinearPaths(start, end, components, candidatePaths);
// 2. 选择最短的安全路径
for (auto it = candidatePaths.begin(); it != candidatePaths.end(); ++it) {
const QList<QPointF>& path = it.value();
if (isPathSafe(path, components)) {
qDebug() << " Selected path with length" << it.key() << ":" << path;
// 绘制路径
for (int i = 1; i < path.size(); i++) {
m_points.lineTo(path[i]);
}
return;
}
}
2024-12-07 17:24:36 +08:00
// 3. 所有路径都失败,使用强制绕行
qDebug() << " All rectilinear paths failed, using forced bypass";
generateForcedRectilinearBypass(start, end, components);
}
// 计算路径长度
double ElectricConnectLineItem::calculatePathLength(const QList<QPointF>& path)
{
double length = 0;
for (int i = 0; i < path.size() - 1; i++) {
length += QLineF(path[i], path[i+1]).length();
}
return length;
}
// 单一线段与矩形相交检测
bool ElectricConnectLineItem::lineIntersectsRect(const QLineF& line, const QRectF& rect)
{
// 检查端点是否在矩形内
if (rect.contains(line.p1()) || rect.contains(line.p2())) {
return true;
}
// 检查是否与矩形的边相交
QLineF edges[4] = {
QLineF(rect.topLeft(), rect.topRight()),
QLineF(rect.topRight(), rect.bottomRight()),
QLineF(rect.bottomRight(), rect.bottomLeft()),
QLineF(rect.bottomLeft(), rect.topLeft())
};
QPointF intersection;
for (int i = 0; i < 4; i++) {
if (line.intersects(edges[i], &intersection) == QLineF::BoundedIntersection) {
return true;
}
}
return false;
}
// 辅助方法实现
bool ElectricConnectLineItem::isSegmentSafe(const QPointF& p1, const QPointF& p2,
const QList<QRectF>& components)
{
QLineF segment(p1, p2);
for (const QRectF& component : components) {
if (segmentPenetratesComponent(segment, component)) {
return false;
}
}
return true;
}
bool ElectricConnectLineItem::isPathSafe(const QList<QPointF>& path,
const QList<QRectF>& components)
{
for (int i = 0; i < path.size() - 1; i++) {
if (!isSegmentSafe(path[i], path[i+1], components)) {
return false;
}
}
return true;
}
// 检查线段是否穿透元件
bool ElectricConnectLineItem::segmentPenetratesComponent(const QLineF& segment,
const QRectF& component)
{
// 检查线段端点是否在元件内
bool p1Inside = component.contains(segment.p1());
bool p2Inside = component.contains(segment.p2());
if (p1Inside && p2Inside) {
// 线段完全在元件内
return true;
}
// 获取与元件的交点
int intersectionCount = 0;
QLineF edges[4] = {
QLineF(component.topLeft(), component.topRight()),
QLineF(component.topRight(), component.bottomRight()),
QLineF(component.bottomRight(), component.bottomLeft()),
QLineF(component.bottomLeft(), component.topLeft())
};
QPointF intersection;
for (int i = 0; i < 4; i++) {
if (segment.intersects(edges[i], &intersection) == QLineF::BoundedIntersection) {
intersectionCount++;
}
}
// 如果线段与元件有2个或更多交点说明穿透了元件
return intersectionCount >= 2;
}
// 获取所有元件的总边界
QRectF ElectricConnectLineItem::getTotalComponentsBounds(const QList<QRectF>& components)
{
if (components.isEmpty()) {
return QRectF();
}
QRectF total = components.first();
for (int i = 1; i < components.size(); i++) {
total = total.united(components[i]);
}
return total;
}
// 收集所有可能的直角路径
void ElectricConnectLineItem::collectRectilinearPaths(const QPointF& start, const QPointF& end,
const QList<QRectF>& components,
QMultiMap<double, QList<QPointF>>& paths)
{
// 2段路径
QPointF turn1(start.x(), end.y()); // 水平-垂直
QPointF turn2(end.x(), start.y()); // 垂直-水平
addPathIfRectilinear({start, turn1, end}, paths);
addPathIfRectilinear({start, turn2, end}, paths);
// 3段路径
double midX = (start.x() + end.x()) / 2;
double midY = (start.y() + end.y()) / 2;
// 水平-垂直-水平
addPathIfRectilinear({start,
QPointF(start.x(), midY),
QPointF(end.x(), midY),
end}, paths);
// 垂直-水平-垂直
addPathIfRectilinear({start,
QPointF(midX, start.y()),
QPointF(midX, end.y()),
end}, paths);
// 4段路径绕行
collectBypassPaths(start, end, components, paths);
}
// 添加路径(如果是直角)
void ElectricConnectLineItem::addPathIfRectilinear(const QList<QPointF>& path,
QMultiMap<double, QList<QPointF>>& paths)
{
// 检查是否所有线段都是水平或垂直
for (int i = 0; i < path.size() - 1; i++) {
if (path[i].x() != path[i+1].x() && path[i].y() != path[i+1].y()) {
return; // 不是直角
}
}
double length = calculatePathLength(path);
paths.insert(length, path);
}
// 收集绕行路径
void ElectricConnectLineItem::collectBypassPaths(const QPointF& start, const QPointF& end,
const QList<QRectF>& components,
QMultiMap<double, QList<QPointF>>& paths)
{
if (components.isEmpty()) return;
// 获取所有元件的总边界
QRectF totalBounds = getTotalComponentsBounds(components);
if (!totalBounds.isValid()) return;
const double clearance = 20.0;
QRectF expanded = totalBounds.adjusted(-clearance, -clearance, clearance, clearance);
// 从上方绕行
addPathIfRectilinear({start,
QPointF(start.x(), expanded.top()),
QPointF(end.x(), expanded.top()),
end}, paths);
// 从下方绕行
addPathIfRectilinear({start,
QPointF(start.x(), expanded.bottom()),
QPointF(end.x(), expanded.bottom()),
end}, paths);
// 从左方绕行
addPathIfRectilinear({start,
QPointF(expanded.left(), start.y()),
QPointF(expanded.left(), end.y()),
end}, paths);
// 从右方绕行
addPathIfRectilinear({start,
QPointF(expanded.right(), start.y()),
QPointF(expanded.right(), end.y()),
end}, paths);
2024-12-07 17:24:36 +08:00
}
// 强制直角绕行
void ElectricConnectLineItem::generateForcedRectilinearBypass(const QPointF& start, const QPointF& end,
const QList<QRectF>& components)
{
qDebug() << " In generateForcedRectilinearBypass";
// 找到阻挡的元件
QRectF blocking = findFirstBlockingComponent(start, end, components);
if (blocking.isValid()) {
qDebug() << " Blocking component:" << blocking;
// 从上方或下方绕过
const double clearance = 15.0;
double bypassY = (start.y() < blocking.center().y()) ?
blocking.top() - clearance : blocking.bottom() + clearance;
QList<QPointF> path = {start,
QPointF(start.x(), bypassY),
QPointF(end.x(), bypassY),
end};
qDebug() << " Forced bypass path:" << path;
for (int i = 1; i < path.size(); i++) {
m_points.lineTo(path[i]);
}
} else {
// 没有阻挡,使用简单的直角路径
qDebug() << " No blocking component, using simple orthogonal path";
QPointF turnPoint = (qAbs(start.x() - end.x()) < qAbs(start.y() - end.y())) ?
QPointF(end.x(), start.y()) : QPointF(start.x(), end.y());
m_points.lineTo(turnPoint);
m_points.lineTo(end);
}
}
// 找到第一个阻挡的元件
QRectF ElectricConnectLineItem::findFirstBlockingComponent(const QPointF& start, const QPointF& end,
const QList<QRectF>& components)
{
QLineF line(start, end);
for (const QRectF& rect : components) {
if (lineIntersectsRect(line, rect)) {
return rect;
}
}
return QRectF();
}