add item rotate property to propertyEditor
This commit is contained in:
parent
6f3f266838
commit
f1dcea6308
|
|
@ -62,7 +62,7 @@ protected:
|
|||
DesignerScene* m_pGraphicsScene;
|
||||
SelectorManager* m_pSelectorManager;
|
||||
StatusBar* m_pStatusBar;
|
||||
QPointer<FixedPortsModel> _pModel;
|
||||
FixedPortsModel* _pModel;
|
||||
DiagramMode _mode;
|
||||
QString _name;
|
||||
PowerEntity* _pEntity; //组态图拓扑对象
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ public:
|
|||
QWidget* getTopWidget();
|
||||
QPointF getTerminalPos(const QString& sTerminalId); //获取拓扑接线点在当前diagram中的位置
|
||||
ElectricConnectLineItem* getLineItemById(const QString& terminalId);
|
||||
void updateItemLinePort(QUuid,ModelFunctionType); //刷新连接item的线端点位置
|
||||
|
||||
void showModelDlg(const QString&,QUuid,GraphicsProjectModelItem*); //点击时显示指定模型的dlg、指定item的数据(模型名,对象Uuid,触发事件的item)
|
||||
void initialPropertyDlg(); //初始化属性设置dlg,每个模型拥各自的dlg
|
||||
|
|
@ -153,6 +154,7 @@ public Q_SLOTS:
|
|||
void onSignal_generateDiagram(const QString&); //生成工程组态信号
|
||||
void onSignal_openBayManager();
|
||||
void onDataTimerOut();
|
||||
void onSelectionChanged();
|
||||
private:
|
||||
void addPortsToItem_json(PortState,QJsonArray,GraphicsProjectModelItem*); //将json格式的port添加到item
|
||||
void autoSetModelName(GraphicsBaseModelItem*); //如果此页的工程模已被设置,将projectName更新到item
|
||||
|
|
|
|||
|
|
@ -18,14 +18,26 @@ public:
|
|||
QPainterPath getPoints(void) const { return m_points; }
|
||||
|
||||
void moveLine(QPointF); //鼠标点击拖动
|
||||
void calculatePath();
|
||||
void resetCurLine(){_curLine = QPoint();}
|
||||
void calculatePath();
|
||||
void generateAvoidancePath(const QPointF& start, const QPointF& end,const QList<QRectF>& obstacleShapes); // 使用形状进行避障
|
||||
double calculatePathLength(const QList<QPointF>& path);
|
||||
bool lineIntersectsRect(const QLineF& line, const QRectF& rect);
|
||||
bool isSegmentSafe(const QPointF& p1, const QPointF& p2,const QList<QRectF>& components);
|
||||
bool isPathSafe(const QList<QPointF>& path,const QList<QRectF>& components);
|
||||
bool segmentPenetratesComponent(const QLineF& segment,const QRectF& component);
|
||||
QRectF getTotalComponentsBounds(const QList<QRectF>& components);
|
||||
void collectRectilinearPaths(const QPointF& start, const QPointF& end,const QList<QRectF>& components,QMultiMap<double, QList<QPointF>>& paths);
|
||||
void addPathIfRectilinear(const QList<QPointF>& path,QMultiMap<double, QList<QPointF>>& paths);
|
||||
void collectBypassPaths(const QPointF& start, const QPointF& end,const QList<QRectF>& components,QMultiMap<double, QList<QPointF>>& paths);
|
||||
void generateForcedRectilinearBypass(const QPointF& start, const QPointF& end,const QList<QRectF>& components);
|
||||
QRectF findFirstBlockingComponent(const QPointF& start, const QPointF& end,const QList<QRectF>& components);
|
||||
|
||||
protected:
|
||||
virtual QPainterPath shape() const override;
|
||||
virtual QRectF boundingRect() const override;
|
||||
virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override;
|
||||
private:
|
||||
|
||||
protected:
|
||||
void initial();
|
||||
private:
|
||||
QPainterPath m_points;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include "propertyType/dataSourceType.h"
|
||||
//#include "graphicsItem/itemPort.h"
|
||||
|
||||
class FixedPortsModel;
|
||||
|
||||
enum ShapeType
|
||||
{
|
||||
T_undefined,
|
||||
|
|
@ -171,12 +173,35 @@ protected:
|
|||
class GraphicsBaseItem :public QObject, public AbstractShapeType<QGraphicsItem>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
public:
|
||||
enum RotateAngle {
|
||||
Angle_0 = 0,
|
||||
Angle_90 = 90,
|
||||
Angle_180 = 180,
|
||||
Angle_270 = 270
|
||||
};
|
||||
Q_ENUM(RotateAngle);
|
||||
|
||||
Q_PROPERTY(QString Name READ getName WRITE setName)
|
||||
Q_PROPERTY(QPointF Position READ getPosition WRITE setPosition)
|
||||
Q_PROPERTY(QRectF Size READ getSize WRITE setSize)
|
||||
Q_PROPERTY(RotateAngle Rotation READ getRotateAngle WRITE setRotateAngle)
|
||||
public:
|
||||
GraphicsBaseItem(QGraphicsItem *parent);
|
||||
GraphicsBaseItem(const GraphicsBaseItem&);
|
||||
virtual ~GraphicsBaseItem();
|
||||
virtual GraphicsBaseItem* clone() const = 0;
|
||||
|
||||
signals:
|
||||
void itemRotated(GraphicsBaseItem*);
|
||||
public:
|
||||
virtual QString getName() const;
|
||||
virtual void setName(QString);
|
||||
virtual QPointF getPosition() const;
|
||||
virtual void setPosition(QPointF);
|
||||
virtual QRectF getSize() const;
|
||||
virtual void setSize(QRectF);
|
||||
virtual RotateAngle getRotateAngle() const;
|
||||
virtual void setRotateAngle(RotateAngle);
|
||||
public:
|
||||
int addPort(PortState typ,QPointF vec,QString id = "",HandleType hType = T_lineInOut,PortPos pos = P_top,double dXPercent = 0,double dYPercent = 0); //新建,返回-1失败
|
||||
virtual void movePort(QString id,QPointF vec); //移动可动点
|
||||
|
|
@ -206,6 +231,7 @@ public:
|
|||
virtual bool hasDynamicText(const QString& tag);
|
||||
virtual void setDynamicLayoutRadius(qreal radius);
|
||||
virtual QMap<QString,HandleText*> getDynamicText() {return m_mapDynamicText;}
|
||||
void setHandle(FixedPortsModel* p){_pHandle = p;}
|
||||
|
||||
int collidesWithHandle(const QPointF& point)
|
||||
{
|
||||
|
|
@ -489,7 +515,10 @@ public slots:
|
|||
void onUpdateData(); //data发送的更新通知
|
||||
protected:
|
||||
void rearrangeDynamicText(); //重新设置动态数据的布局
|
||||
QList<QRectF> getComponentCollisionRects() const; //获取图所有碰撞矩形
|
||||
QList<QPainterPath> getObstacleShapes() const; //获取所有碰撞shape
|
||||
protected:
|
||||
FixedPortsModel* _pHandle;
|
||||
ModelProperty* _property;
|
||||
PowerEntity* _pEntity; //图元拓扑
|
||||
bool _itemChanged; //图元变化标志,判断是否需要保存
|
||||
|
|
@ -543,10 +572,8 @@ class GraphicsProjectModelItem : public GraphicsBaseItem //工程模item
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_PROPERTY(QString Name READ getName WRITE setName)
|
||||
Q_PROPERTY(QPointF Position READ getPosition WRITE setPosition)
|
||||
Q_PROPERTY(QRectF Size READ getSize WRITE setSize)
|
||||
Q_PROPERTY(DataSourceType DataSourceType READ getDataSourceType WRITE setDataSourceType)
|
||||
|
||||
public:
|
||||
GraphicsProjectModelItem(QGraphicsItem *parent);
|
||||
GraphicsProjectModelItem(const GraphicsProjectModelItem&);
|
||||
|
|
@ -595,12 +622,6 @@ public:
|
|||
}
|
||||
}
|
||||
public:
|
||||
QString getName() const;
|
||||
void setName(QString);
|
||||
QPointF getPosition() const;
|
||||
void setPosition(QPointF);
|
||||
QRectF getSize() const;
|
||||
void setSize(QRectF);
|
||||
DataSourceType getDataSourceType() const;
|
||||
void setDataSourceType(DataSourceType);
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public:
|
|||
QVariantMap properties() const { return m_properties; }
|
||||
DataState state() {return m_state;}
|
||||
void setState(DataState s) {m_state = s;}
|
||||
void setId(QString sId){m_uuid = sId;}
|
||||
|
||||
void setProperty(const QString& key, const QVariant& value);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ BaseDrawingPanel::BaseDrawingPanel(PowerEntity* pEntity,QWidget *parent,DiagramM
|
|||
,_pPropertyProxy(nullptr)
|
||||
{
|
||||
_pEntity = pEntity;
|
||||
_pModel = QPointer<FixedPortsModel>(new FixedPortsModel(pEntity));
|
||||
_pModel = new FixedPortsModel(pEntity);
|
||||
_pModel->setTopWidget(this);
|
||||
m_pSelectorManager = new SelectorManager(_pModel,this);
|
||||
m_pGraphicsScene = new DesignerScene(_pModel,this);
|
||||
|
|
@ -36,20 +36,7 @@ BaseDrawingPanel::BaseDrawingPanel(PowerEntity* pEntity,QWidget *parent,DiagramM
|
|||
m_pGraphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
||||
m_pGraphicsScene->setView(m_pGraphicsView);
|
||||
_pModel->setScene(m_pGraphicsScene);
|
||||
connect(m_pGraphicsScene, &DesignerScene::selectionChanged, this, [&](){
|
||||
QList<QGraphicsItem*> selectedItems = m_pGraphicsScene->selectedItems();
|
||||
if(_pModel){
|
||||
auto pCavas = _pModel->getCavas();
|
||||
if(pCavas){
|
||||
if(selectedItems.count() != 1) {
|
||||
_pModel->getCavas()->onTargetSelected(_pPropertyProxy);
|
||||
return;
|
||||
}
|
||||
GraphicsBaseItem *item = static_cast<GraphicsBaseItem*>(selectedItems.first());
|
||||
_pModel->getCavas()->onTargetSelected(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(m_pGraphicsScene, &DesignerScene::selectionChanged, _pModel, &FixedPortsModel::onSelectionChanged);
|
||||
|
||||
m_pStatusBar = new StatusBar(this);
|
||||
m_pStatusBar->setMaximumHeight(25);
|
||||
|
|
@ -77,8 +64,8 @@ BaseDrawingPanel::BaseDrawingPanel(PowerEntity* pEntity,QWidget *parent,DiagramM
|
|||
|
||||
BaseDrawingPanel::~BaseDrawingPanel()
|
||||
{
|
||||
if(_pModel)
|
||||
delete _pModel;
|
||||
//if(_pModel)
|
||||
// delete _pModel;
|
||||
if(_pPropertyProxy)
|
||||
delete _pPropertyProxy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ void DrawingPanel::loadNodes(QJsonObject obj)
|
|||
PowerConnection* pCon = TopologyManager::instance().connection(srcPortId.toString(),destPortId.toString());
|
||||
if(pCon)
|
||||
{
|
||||
pCon->setId(id.toString());
|
||||
QString srcItemId = pCon->fromComponent();
|
||||
QString destItemId = pCon->toComponent();
|
||||
//todo:从拓扑结构中查找port的id
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
#include "instance/dataAccessor.h"
|
||||
#include "graphicsItem/handleText.h"
|
||||
#include "bayMeasureDlg.h"
|
||||
#include "basePannelPropertyProxy.h"
|
||||
#include "global.h"
|
||||
|
||||
bool FixedPortsModel::_dataInitialised = false;
|
||||
|
|
@ -84,7 +85,7 @@ FixedPortsModel::FixedPortsModel(PowerEntity* pEntity)
|
|||
|
||||
FixedPortsModel::~FixedPortsModel()
|
||||
{
|
||||
|
||||
_cavas.clear();
|
||||
}
|
||||
|
||||
QMap<QUuid,itemPageInfo> FixedPortsModel::allNodePos() const
|
||||
|
|
@ -143,8 +144,18 @@ bool FixedPortsModel::addNodeItem(QUuid uuid,GraphicsProjectModelItem* pItem)
|
|||
return false;
|
||||
else
|
||||
{
|
||||
pItem->setHandle(this);
|
||||
_nodeItem.insert(uuid,pItem);
|
||||
connect(pItem,&GraphicsProjectModelItem::ifExist,this,&FixedPortsModel::onSignal_ifExits);
|
||||
connect(pItem,&GraphicsBaseItem::itemRotated,this,[this](GraphicsBaseItem* pBase){
|
||||
if(pBase){
|
||||
auto pPro = pBase->getProperty();
|
||||
QUuid uid = pPro->uuid();
|
||||
if(pPro->type() != 8){ //排除线
|
||||
updateItemLinePort(uid,ModelFunctionType::ProjectModel);
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -645,10 +656,18 @@ QString FixedPortsModel::addNodeItem(QUuid id,QPointF pos,double width,double he
|
|||
item->addPoint(pos);
|
||||
item->setProperty(pro); //绑定模型
|
||||
item->updateByProperty(); //使用模型更新自身
|
||||
//QString sModel = _projectModelName.value(id.toString());
|
||||
//item->setModelName(sModel);
|
||||
item->setHandle(this);
|
||||
_nodeItem.insert(id,item);
|
||||
connect(item,&GraphicsProjectModelItem::ifExist,this,&FixedPortsModel::onSignal_ifExits);
|
||||
connect(item,&GraphicsBaseItem::itemRotated,this,[this](GraphicsBaseItem* pBase){
|
||||
if(pBase){
|
||||
auto pPro = pBase->getProperty();
|
||||
QUuid uid = pPro->uuid();
|
||||
if(pPro->type() != 8){ //排除线
|
||||
updateItemLinePort(uid,ModelFunctionType::ProjectModel);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return pro->name();
|
||||
}
|
||||
|
|
@ -1610,6 +1629,19 @@ void FixedPortsModel::onDataTimerOut()
|
|||
}
|
||||
}
|
||||
|
||||
void FixedPortsModel::onSelectionChanged()
|
||||
{
|
||||
QList<QGraphicsItem*> selectedItems = _scene->selectedItems();
|
||||
if(_cavas){
|
||||
if(selectedItems.count() != 1) {
|
||||
_cavas->onTargetSelected(_widget->getPropertyProxy());
|
||||
return;
|
||||
}
|
||||
GraphicsBaseItem *item = static_cast<GraphicsBaseItem*>(selectedItems.first());
|
||||
_cavas->onTargetSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
void FixedPortsModel::startHttpRequest()
|
||||
{
|
||||
if(_timer)
|
||||
|
|
@ -1794,6 +1826,31 @@ ElectricConnectLineItem* FixedPortsModel::getLineItemById(const QString& termina
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void FixedPortsModel::updateItemLinePort(QUuid uid,ModelFunctionType type)
|
||||
{
|
||||
QList<PowerConnection*> lstCon = TopologyManager::instance().getConnectionsFor(uid.toString(),type); //获取item的所有连接
|
||||
for(auto &pCon:lstCon){
|
||||
QString baseFromComponentId = pCon->fromComponent();
|
||||
QString baseToComponentId = pCon->toComponent();
|
||||
QString baseFromTerId = pCon->fromTerminalId();
|
||||
QString baseToTerId = pCon->toTerminalId();
|
||||
|
||||
auto pLine = static_cast<ElectricConnectLineItem*>(nodeItem(QUuid(pCon->id())));
|
||||
if(pLine){
|
||||
if(uid.toString() == baseFromComponentId){
|
||||
QPointF posFrom = getTerminalPos(baseFromTerId);
|
||||
pLine->setStartPoint(posFrom);
|
||||
pLine->calculatePath();
|
||||
}
|
||||
else if(uid.toString() == baseToComponentId){
|
||||
QPointF posTo = getTerminalPos(baseToTerId);
|
||||
pLine->setEndPoint(posTo);
|
||||
pLine->calculatePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FixedPortsModel::showModelDlg(const QString& sName,QUuid uuid,GraphicsProjectModelItem* pItem)
|
||||
{
|
||||
modelStateInfo stateInfo = _modelStateInfo[sName];
|
||||
|
|
|
|||
|
|
@ -352,47 +352,341 @@ void ElectricConnectLineItem::moveLine(QPointF pos)
|
|||
|
||||
void ElectricConnectLineItem::calculatePath()
|
||||
{
|
||||
int n = m_lstPoints.size();
|
||||
/*for(int i = 0;i < n-1;++i)
|
||||
{
|
||||
if(m_lstPoints[i] == m_lstPoints[i+1])
|
||||
{
|
||||
if(i == 0) //头重复去除一个
|
||||
{
|
||||
m_lstPoints.removeAt(i+1);
|
||||
}
|
||||
else if((i+1 == n-1)) //尾重复去除一个
|
||||
{
|
||||
m_lstPoints.removeAt(i+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lstPoints.removeAt(i+1);
|
||||
m_lstPoints.removeAt(i);
|
||||
}
|
||||
qDebug()<<"reset";
|
||||
resetCurLine();
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
prepareGeometryChange();
|
||||
m_points.clear();
|
||||
m_pointsBoundingRect.clear();
|
||||
if (m_lstPoints.size() < 2) return;
|
||||
|
||||
if(m_lstPoints.size() == 2 && (m_lstPoints.first().x() != m_lstPoints.last().x()) && (m_lstPoints.first().y() != m_lstPoints.last().y()))
|
||||
{
|
||||
if(m_lstPoints.first().y() < m_lstPoints.last().y())
|
||||
m_lstPoints.insert(1,QPointF(m_lstPoints.first().x(),m_lstPoints.last().y()));
|
||||
else
|
||||
m_lstPoints.insert(1,QPointF(m_lstPoints.last().x(),m_lstPoints.first().y()));
|
||||
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);
|
||||
}
|
||||
m_points.moveTo(m_lstPoints.first());
|
||||
QPointF pLast = m_lstPoints.first();
|
||||
for(int i = 1;i <m_lstPoints.size();++i)
|
||||
{
|
||||
m_points.lineTo(m_lstPoints[i]);
|
||||
m_pointsBoundingRect.addRect(QRectF(QPointF(pLast.x()-1,pLast.y()-1),QPointF(m_lstPoints[i].x()+1,m_lstPoints[i].y()+1)));
|
||||
pLast = m_lstPoints[i];
|
||||
|
||||
// 验证路径
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 强制直角绕行
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "graphicsItem/handleText.h"
|
||||
#include "graphicsItem/itemPort.h"
|
||||
#include "baseProperty.h"
|
||||
#include "graphicsDataModel/fixedPortsModel.h"
|
||||
#include "dataBase.h"
|
||||
#include <QGraphicsScene>
|
||||
#include <QJsonArray>
|
||||
|
|
@ -13,6 +14,7 @@ GraphicsBaseItem::GraphicsBaseItem(QGraphicsItem *parent)
|
|||
: AbstractShapeType<QGraphicsItem>(parent)
|
||||
,_property(nullptr)
|
||||
,_pEntity(nullptr)
|
||||
,_pHandle(nullptr)
|
||||
{
|
||||
m_type = T_item;
|
||||
_itemChanged = false;
|
||||
|
|
@ -69,6 +71,69 @@ GraphicsBaseItem::~GraphicsBaseItem()
|
|||
}
|
||||
}
|
||||
|
||||
QString GraphicsBaseItem::getName() const
|
||||
{
|
||||
if(_property)
|
||||
return _property->name();
|
||||
return QString();
|
||||
}
|
||||
|
||||
void GraphicsBaseItem::setName(QString str)
|
||||
{
|
||||
if(_property)
|
||||
_property->setName(str);
|
||||
}
|
||||
|
||||
QPointF GraphicsBaseItem::getPosition() const
|
||||
{
|
||||
return pos();
|
||||
}
|
||||
|
||||
void GraphicsBaseItem::setPosition(QPointF pos)
|
||||
{
|
||||
setPos(pos);
|
||||
}
|
||||
|
||||
QRectF GraphicsBaseItem::getSize() const
|
||||
{
|
||||
return m_boundingRect;
|
||||
}
|
||||
|
||||
void GraphicsBaseItem::setSize(QRectF rec)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
m_boundingRect = rec;
|
||||
update();
|
||||
}
|
||||
|
||||
GraphicsBaseItem::RotateAngle GraphicsBaseItem::getRotateAngle() const
|
||||
{
|
||||
int nRotate = rotation();
|
||||
|
||||
// 标准化角度到 0-360 范围
|
||||
nRotate = nRotate % 360;
|
||||
if (nRotate < 0) nRotate += 360;
|
||||
|
||||
// 映射到最近的 90 度倍数
|
||||
int normalized = ((nRotate + 45) / 90) * 90 % 360;
|
||||
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<RotateAngle>();
|
||||
|
||||
// 检查标准化后的角度是否是有效的枚举值
|
||||
if (metaEnum.valueToKey(normalized) != nullptr) {
|
||||
return static_cast<RotateAngle>(normalized);
|
||||
}
|
||||
|
||||
return RotateAngle::Angle_0;
|
||||
}
|
||||
|
||||
void GraphicsBaseItem::setRotateAngle(RotateAngle angle)
|
||||
{
|
||||
int nAngle = static_cast<int>(angle);
|
||||
setRotation(nAngle);
|
||||
emit itemRotated(this);
|
||||
}
|
||||
|
||||
int GraphicsBaseItem::addPort(PortState typ,QPointF vec,QString id,HandleType hType,PortPos pos,double dXPercent,double dYPercent)
|
||||
{
|
||||
int ntagId = -1;
|
||||
|
|
@ -321,6 +386,56 @@ void GraphicsBaseItem::rearrangeDynamicText()
|
|||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
QList<QRectF> GraphicsBaseItem::getComponentCollisionRects() const
|
||||
{
|
||||
QList<QRectF> lst;
|
||||
if(_pHandle){
|
||||
auto mapItems = _pHandle->allItems();
|
||||
for(auto &pItem:mapItems){
|
||||
if (pItem == this) continue;
|
||||
ModelProperty* pPro = pItem->getProperty();
|
||||
if(pPro){
|
||||
if(pPro->type() == 8) continue; //排除线
|
||||
}
|
||||
QRectF bounds = pItem->boundingRect();
|
||||
bounds = pItem->mapRectToScene(bounds);
|
||||
lst.append(bounds);
|
||||
}
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
QList<QPainterPath> GraphicsBaseItem::getObstacleShapes() const
|
||||
{
|
||||
QList<QPainterPath> obstacles;
|
||||
|
||||
if (!scene()) {
|
||||
return obstacles;
|
||||
}
|
||||
if(_pHandle){
|
||||
auto mapItems = _pHandle->allItems();
|
||||
for(auto &pItem:mapItems){
|
||||
if (pItem == this) continue;
|
||||
ModelProperty* pPro = pItem->getProperty();
|
||||
if(pPro){
|
||||
if(pPro->type() == 8) continue; //排除线
|
||||
}
|
||||
|
||||
// 获取元件的形状(考虑旋转)
|
||||
QPainterPath shape = pItem->mapToScene(pItem->shape());
|
||||
|
||||
// 如果需要,可以稍微扩大形状
|
||||
QPainterPathStroker stroker;
|
||||
stroker.setWidth(10); // 扩大10像素作为安全距离
|
||||
QPainterPath expandedShape = stroker.createStroke(shape);
|
||||
|
||||
obstacles.append(expandedShape);
|
||||
}
|
||||
}
|
||||
|
||||
return obstacles;
|
||||
}
|
||||
/********************************基模****************************************/
|
||||
GraphicsBaseModelItem::GraphicsBaseModelItem(QGraphicsItem *parent)
|
||||
:GraphicsBaseItem(parent)
|
||||
|
|
@ -580,41 +695,6 @@ void GraphicsProjectModelItem::syncRotationDataFromParent(const double& data)
|
|||
m_dSyncRotationByParent += 360;
|
||||
}
|
||||
|
||||
QString GraphicsProjectModelItem::getName() const
|
||||
{
|
||||
if(_property)
|
||||
return _property->name();
|
||||
return QString();
|
||||
}
|
||||
|
||||
void GraphicsProjectModelItem::setName(QString str)
|
||||
{
|
||||
if(_property)
|
||||
_property->setName(str);
|
||||
}
|
||||
|
||||
QPointF GraphicsProjectModelItem::getPosition() const
|
||||
{
|
||||
return pos();
|
||||
}
|
||||
|
||||
void GraphicsProjectModelItem::setPosition(QPointF pos)
|
||||
{
|
||||
setPos(pos);
|
||||
}
|
||||
|
||||
QRectF GraphicsProjectModelItem::getSize() const
|
||||
{
|
||||
return m_boundingRect;
|
||||
}
|
||||
|
||||
void GraphicsProjectModelItem::setSize(QRectF rec)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
m_boundingRect = rec;
|
||||
update();
|
||||
}
|
||||
|
||||
DataSourceType GraphicsProjectModelItem::getDataSourceType() const
|
||||
{
|
||||
return _sourceType;
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ void MonitorPanel::loadNodes(QJsonObject obj)
|
|||
PowerConnection* pCon = TopologyManager::instance().connection(srcPortId.toString(),destPortId.toString());
|
||||
if(pCon)
|
||||
{
|
||||
pCon->setId(id.toString());
|
||||
QString srcItemId = pCon->fromComponent();
|
||||
QString destItemId = pCon->toComponent();
|
||||
//todo:从拓扑结构中查找port的id
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ void LinkMovingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, Designe
|
|||
}
|
||||
else
|
||||
{
|
||||
if(m_pMovingLine)
|
||||
m_pMovingLine->moveLine(ms_ptMouseLast);
|
||||
//if(m_pMovingLine)
|
||||
//m_pMovingLine->moveLine(ms_ptMouseLast); //暂时屏蔽移动线 260204
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ private slots:
|
|||
|
||||
void onAction_createEditor();
|
||||
void onAction_unloadEditor(const QString&);
|
||||
void onCavasItemSelected(QObject*);
|
||||
public:
|
||||
GraphicElementsPanel* graphicsElementsPanel() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -143,9 +143,7 @@ void CMainWindow::initializeDockUi()
|
|||
m_pPropertiesEditorView->setObject(m_pDiagramCavas);
|
||||
PropertyEditorDock->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
|
||||
this->addDockWidget(Qt::RightDockWidgetArea,PropertyEditorDock);
|
||||
connect(m_pDiagramCavas,&DiagramCavas::selectTarget,this,[&](QObject* obj){
|
||||
m_pPropertiesEditorView->setObject(obj);
|
||||
});
|
||||
connect(m_pDiagramCavas,&DiagramCavas::selectTarget,this,&CMainWindow::onCavasItemSelected);
|
||||
}
|
||||
|
||||
void CMainWindow::initializeAction()
|
||||
|
|
@ -356,6 +354,12 @@ void CMainWindow::onAction_unloadEditor(const QString& str)
|
|||
m_pDiagramCavas->onSignal_unloadProject(str);
|
||||
}
|
||||
|
||||
void CMainWindow::onCavasItemSelected(QObject* obj)
|
||||
{
|
||||
if(m_pPropertiesEditorView)
|
||||
m_pPropertiesEditorView->setObject(obj);
|
||||
}
|
||||
|
||||
GraphicElementsPanel* CMainWindow::graphicsElementsPanel() const
|
||||
{
|
||||
if(m_pGraphicElementsPanel)
|
||||
|
|
|
|||
Loading…
Reference in New Issue