基于Qt GraphicView 解析 CIM/G 电力接线图文件

本文讲述了如何使用Qt的框架来渲染展示标准的CIM/G格式的图形文件,也就是公用信息模型(common
information model,CIM)中的G文件部分的内容。这是一种电力系统图形的交换规则,用于电网图形交换。
[by amjieker]

CIM/G 文件的特点

基于 CIM/G 的图形对象存储和交换格式应具备以下特征:
a) 详细说明如何关联图形对象和领域数据,领域数据和领域数据、图形对象和图形对象互相交换;
b) 支持与领域数据没有关联关系的图形对象的交换,例如纯粹的静态背景对象;
c) 支持在相同或不同的图形中同一领域对象的不同表现形式;
d) 支持在没有领域拓扑模型的情况下使用图形拓扑来描述电力设备的拓扑关系;
e) 支持按层或其他方式存储图形对象,支持基于不同缩放比例显示图形,支持以用户所关注的角
度显示或隐藏不同的图形对象;
f) 支持通过间隔模板图元定义和描述间隔设备;
g) 图形文件包括两类:一类是描述图形自身的文件,另一类是描述系统中图元、间隔、字体和颜
色等公用部分的文件。

CIM/G 组成元素及其关系

G 文件总体来看描述了 点、线、面的绘制以及其线条、填充的风格,和svg的描述定义类似。
G 文件可以包含有复炸图元的引用定义,通过引用属性devref将其进行连接使用
G 文件还描述了接线图的拓扑关系,通过端子连接线可以得到图的拓扑关系图 (拓扑图这个本文不做分析)

在这里插入图片描述

CIMG 文件 一般形式如下:

<?xml version='1.0' encoding='UTF-8'?>
<G bgi="" h="600" bgiw="0" bgc="255,255,255" bgf="0" GraphType="4" w="800"><Layer name="第0平面" show="1"><Bus id="33000001" y1="527.701" y2="527.701" app="100000" ls="1" x1="400.843" lc="192,0,192" x2="687.506" lw="4" voltype="220" keyid=""/><Bus id="33000002" y1="565.579" y2="565.579" app="100000" ls="1" x1="399.982" lc="192,0,192" x2="685.784" lw="4" voltype="220" keyid=""/><Disconnector x="491.081" id="37000001" y="422.701" tfr="rotate(180) scale(1,1)" app="100000" devref="#DZ.gld.icn.g:刀闸" voltype="220" color="#c000c0"/><Disconnector x="586.636" id="37000002" y="422.701" tfr="rotate(180) scale(1,1)" app="100000" devref="#DZ.gld.icn.g:刀闸" voltype="220" color="#c000c0"/><ConnectLine id="31000002" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="496.745,460.701 496.745,527.701" endWeldingSpotSize="4" link="0,0,37000001;1,1,33000001"/><ConnectLine id="31000003" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="592.3,460.701 592.3,565.579" endWeldingSpotSize="4" link="0,0,37000002;1,1,33000002"/><ConnectLine id="31000004" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="496.645,426.701 496.645,389.552 592.2,389.552 592.2,426.701" endWeldingSpotSize="4" link="0,1,37000001;1,1,37000002"/><CBreaker x="535.922" id="36000001" y="266.426" tfr="scale(2.19429,1.65516) rotate(0) " app="100000" devref="#DLQ.dlq.icn.g:断路器" voltype="220" color="#c000c0" p_RoundBox="0,0,10,36"/><GroundDisconnector x="606.196" id="38000001" y="309.439" tfr="rotate(270) scale(1,1)" app="100000" devref="#DDZ.jdd.icn.g:接地刀闸" voltype="220" color="#c000c0"/><GroundDisconnector x="607.814" id="38000003" y="212.884" tfr="rotate(270) scale(1,1)" app="100000" devref="#DDZ.jdd.icn.g:接地刀闸" voltype="220" color="#c000c0"/><GroundDisconnector x="609.535" id="38000004" y="117.469" tfr="rotate(270) scale(1,1)" app="100000" devref="#DDZ.jdd.icn.g:接地刀闸" voltype="220" color="#c000c0"/><ConnectLine id="31000005" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="540.922,307.267 540.922,388.244 540.922,389.44" endWeldingSpotSize="4" link="0,1,36000001;1,1,31000004"/><ConnectLine id="31000006" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="595.196,334.239 540.907,334.239" endWeldingSpotSize="4" link="0,0,38000001;1,1,31000005"/><Disconnector x="535.257" id="37000003" y="171.811" tfr="rotate(180) scale(1,1)" app="100000" devref="#DDZ.gld.icn.g:刀闸" voltype="220" color="#c000c0"/><ConnectLine id="31000007" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="541.089,209.811 540.922,262.909" endWeldingSpotSize="4" link="0,0,37000003;1,0,36000001"/><ConnectLine id="31000008" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="541.135,238.08 596.814,237.684" endWeldingSpotSize="4" link="0,0,31000007;1,0,38000003"/><EnergyConsumer id="42000001" startWeldingSpotSize="4" app="100000" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" voltype="" d="539.914,72.0344 539.914,113.139" endWeldingSpotSize="4" link="0,0,31000009" keyid=""/><ConnectLine id="31000009" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="539.914,113.139 540.822,175.811" endWeldingSpotSize="4" link="0,0,42000001;1,1,37000003"/><ConnectLine id="31000010" startWeldingSpotSize="4" showCrossPoint="1" ls="1" lc="192,0,192" lw="1" startWeldingSpot="0" endWeldingSpot="0" d="540.728,142.034 598.535,142.269" endWeldingSpotSize="4" link="0,0,31000009;1,0,38000004"/><polyline id="5000001" ls="1" lc="0,0,0" lw="1" d="52,86 243,86 243,568 49,568 49,85 52,85 52,84"/></Layer>
</G>

绘制图元

通过 解析G文件的绘制描述,在图上绘制出对应的图形,并计算好其平移、旋转、等操作。

我的绘制思路是,基础图元直接使用现成的 GraphicItem来做这一件事情;而复杂图元 由于是由基础图元 组合而成,索性写一个 Itemloader 来加载复杂图元的内容,然后自己paint这些图元即可。(复杂图元还需要解决 图元状态的情况)

对于每一个图形都有共有的公共属性,而点、线、面都可以看成是一种派生关系。
在这里插入图片描述

复杂图元加载器定义

#include "QGraphicsRectItem"
#include "pugixml/pugixml.hpp"class ItemLoader: public QGraphicsRectItem
{public:typedef void (ItemLoader::*PaintEP)(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);ItemLoader(QString fileName, int sta = -1);void SetTfr(QString tfr);void SetSta(int sta);void SetVis(int vis);public:void PaintSelectBox(QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintCircle(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintPin(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintLine(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintRect(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintPolygon(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintPolyline(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintEllipsearc(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintCirclearc(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintEllipse(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);void PaintText(pugi::xml_node node, QPainter* painter, const QStyleOptionGraphicsItem *option, QWidget *widget);public:QRectF boundingRect() const;void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);private:pugi::xml_document m_doc;int m_height = 0, m_width = 0;int m_sta, m_vis = 1;double sx = 1, sy = 1;double route = 0;QString m_file;QTextCodec* m_encoding;
};

分发绘制函数


static QHash<QString, ItemLoader::PaintEP> dispatch {{"circle",      &ItemLoader::PaintCircle},{"pin",         &ItemLoader::PaintPin},{"line",        &ItemLoader::PaintLine},{"rect",        &ItemLoader::PaintRect},{"polygon",     &ItemLoader::PaintPolygon},{"polyline",    &ItemLoader::PaintPolyline},{"circlearc",   &ItemLoader::PaintCirclearc},{"ellipsearc",  &ItemLoader::PaintEllipsearc},{"ellipse",     &ItemLoader::PaintEllipsearc},{"Text",        &ItemLoader::PaintText},
};void ItemLoader::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{auto Gs = *m_doc.root().child("G").children().begin(); // 只取第一个auto layers = Gs.children("Layer");painter->setPen(pen());painter->setBrush(brush());if (m_vis)for (auto layer : layers){auto items = layer.children();for (auto item : items){QString name = item.name();int sta = item.attribute("sta").as_int();if (sta != m_sta && this->m_sta != -1) continue;if (dispatch.contains(name)){(this->*(dispatch[name]))(item, painter, option, widget);}else{qWarning() << "<<<<<<<<<< not find node painter -->" << name << m_file;}}}// painter->restore();PaintSelectBox(painter, option, widget);
}

绘制圆

在这里插入图片描述

void ItemLoader::PaintCircle(pugi::xml_node item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{double cx = item.attribute("cx").as_float();double cy = item.attribute("cy").as_float();double r = item.attribute("r").as_float();QPointF p(cx, cy);QString lc = item.attribute("lc").as_string(); // line colorQString fc = item.attribute("fc").as_string(); // fill colorauto t_pen = pen();auto t_brush = brush();if (!lc.isEmpty()) t_pen.setColor(parseColorString(lc));if (!fc.isEmpty()) t_brush.setColor(parseColorString(fc));painter->setPen(t_pen);painter->setBrush(t_brush);painter->drawEllipse(p, r, r);
}

绘制端子

在这里插入图片描述
在这里插入图片描述


void ItemLoader::PaintPin(pugi::xml_node item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{double cx = item.attribute("cx").as_float();double cy = item.attribute("cy").as_float();double r = item.attribute("r").as_float();QString lc = item.attribute("lc").as_string(); // line colorQString fc = item.attribute("fc").as_string(); // fill colorauto t_pen = pen();auto t_brush = brush();if (!lc.isEmpty()) t_pen.setColor(parseColorString(lc));if (!fc.isEmpty()) t_brush.setColor(parseColorString(fc));painter->setPen(t_pen);painter->setBrush(t_brush);QPointF p(cx, cy);painter->drawEllipse(p, r, r);
}

绘制直线

在这里插入图片描述

其实所有的图元都有旋转属性,但是其他图元在我使用的过程中没有遇见旋转,我就没管了,但是直线的旋转被用到了,所以下文中我处理了旋转

void ItemLoader::PaintLine(pugi::xml_node item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{double x1 = item.attribute("x1").as_float();double x2 = item.attribute("x2").as_float();double y1 = item.attribute("y1").as_float();double y2 = item.attribute("y2").as_float();QString lc = item.attribute("lc").as_string(); // line colorQString fc = item.attribute("fc").as_string(); // fill colorauto t_pen = pen();auto t_brush = brush();if (!lc.isEmpty()) t_pen.setColor(parseColorString(lc));if (!fc.isEmpty()) t_brush.setColor(parseColorString(fc));painter->setPen(t_pen);painter->setBrush(t_brush);QString text = item.attribute("tfr").as_string();double a, b, c;sscanf(text.toLocal8Bit().data(), "rotate(%lf) scale(%lf, %lf)", &a, &b, &c);if (!text.isEmpty()){QPointF p1(x1, y1), p2(x2, y2);painter->save();QPointF center = QRectF(p1, p2).center();painter->translate(center);painter->rotate(a);painter->scale(b, c);painter->drawLine(p1 - center, p2 - center);painter->restore();}else{painter->drawLine(QPointF(x1, y1), QPointF(x2, y2));}}

绘制矩形

在这里插入图片描述
在这里插入图片描述

void ItemLoader::PaintRect(pugi::xml_node item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{double x = item.attribute("x").as_float();double y = item.attribute("y").as_float();double w = item.attribute("w").as_float();double h = item.attribute("h").as_float();QString lc = item.attribute("lc").as_string(); // line colorQString fc = item.attribute("fc").as_string(); // fill colorauto t_pen = pen();auto t_brush = brush();if (item.attribute("lm")) t_pen.setStyle(Qt::PenStyle(item.attribute("lm").as_int()));if (item.attribute("fm")) t_brush.setStyle(Qt::BrushStyle(item.attribute("fm").as_int()));if (!lc.isEmpty()) t_pen.setColor(parseColorString(lc));if (!fc.isEmpty()) t_brush.setColor(parseColorString(fc));painter->setPen(t_pen);painter->setBrush(t_brush);painter->drawRect(QRectF(x, y, w, h));
}

绘制多边形

在这里插入图片描述

void ItemLoader::PaintPolygon(pugi::xml_node item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{QString d = item.attribute("d").as_string();auto ds = d.split(" ");if (ds.size() < 1){qDebug() << d << "null";return;}QPointF *list = new QPointF[ds.size()];for (int i = 0; i < ds.size(); i ++){QStringList now = ds[i].split(",");list[i] = QPointF(now[0].toDouble(), now[1].toDouble());}QString lc = item.attribute("lc").as_string(); // line colorQString fc = item.attribute("fc").as_string(); // fill colorauto t_pen = pen();auto t_brush = brush();if (!lc.isEmpty()) t_pen.setColor(parseColorString(lc));if (!fc.isEmpty()) t_brush.setColor(parseColorString(fc));painter->setPen(t_pen);painter->setBrush(t_brush);painter->drawPolygon(list, ds.size());delete[] list;
}

绘制折线

在这里插入图片描述
在这里插入图片描述

void ItemLoader::PaintPolyline(pugi::xml_node item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{QString d = item.attribute("d").as_string();auto ds = d.split(" ");QPointF *list = new QPointF[ds.size()];for (int i = 0; i < ds.size(); i ++){QStringList now = ds[i].split(",");list[i] = QPointF(now[0].toDouble(), now[1].toDouble());}QString lc = item.attribute("lc").as_string(); // line colorQString fc = item.attribute("fc").as_string(); // fill colorauto t_pen = pen();auto t_brush = brush();if (!lc.isEmpty()) t_pen.setColor(parseColorString(lc));if (!fc.isEmpty()) t_brush.setColor(parseColorString(fc));painter->setPen(t_pen);painter->setBrush(t_brush);painter->drawPolyline(list, ds.size());delete[] list;
}

绘制文本

在这里插入图片描述

void ItemLoader::PaintText(pugi::xml_node item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{double x = item.attribute("x").as_float();double y = item.attribute("y").as_float();QString lc = item.attribute("lc").as_string(); // line colorQString fc = item.attribute("fc").as_string(); // line colorint fs = item.attribute("fs").as_int(); // font sizeQString ff = m_encoding->toUnicode(item.attribute("ff").as_string());QString ts = m_encoding->toUnicode(item.attribute("ts").as_string());int ls = item.attribute("ls").as_int();int fm = item.attribute("fm").as_int();auto t_pen = pen();auto t_brush = brush();QFont f;f.setPixelSize(fs);f.setFamily(ff);t_pen.setColor(parseColorString(lc));t_pen.setStyle(Qt::PenStyle(ls));t_brush.setColor(parseColorString(fc));t_brush.setStyle(Qt::BrushStyle(fm));painter->setPen(t_pen);painter->setBrush(t_brush);painter->setFont(f);painter->drawText(x, y, ts);
}

处理变换矩阵

在这里插入图片描述
根据变换具体的描述,我们需要对图元的整体变换也做处理

由于是需要中心点旋转,所以要先平移到中心点旋转,然后在缩放,最后平移回来。

需要四个矩阵

分别是 t1、t2、s、r

[ 1 0 0 0 1 0 d x d y 1 ] \begin{equation} \left[ \begin{array}{ccc} 1&0&0\\ 0&1&0\\ dx&dy&1 \end{array} \right] \end{equation} 10dx01dy001

[ c o s ( α ∘ ) s i n ( α ∘ ) 0 − s i n ( α ∘ ) c o s ( α ∘ ) 0 0 0 1 ] \begin{equation} \left[ \begin{array}{ccc} cos(\alpha^{\circ})&sin(\alpha^{\circ})&0\\ -sin(\alpha^{\circ})&cos(\alpha^{\circ})&0\\ 0&0&1 \end{array} \right] \end{equation} cos(α)sin(α)0sin(α)cos(α)0001

[ s x 0 0 0 s y 0 0 0 1 ] \begin{equation} \left[ \begin{array}{ccc} sx&0&0\\ 0&sy&0\\ 0&0&1 \end{array} \right] \end{equation} sx000sy0001

[ 1 0 0 0 1 0 − d x − d y 1 ] \begin{equation} \left[ \begin{array}{ccc} 1&0&0\\ 0&1&0\\ -dx&-dy&1 \end{array} \right] \end{equation} 10dx01dy001

将四个变换矩阵连乘起来之后,就是我们最后的变换矩阵


void ItemLoader::SetTfr(QString tfr)
{if (tfr.isEmpty()) return;QStringList list = tfr.split(" ");if (list[0].contains("rotate")) tfr = list[1] + " " + list[0];sscanf(tfr.toLocal8Bit().data(), "scale(%lf,%lf) rotate(%lf)", &sx, &sy, &route);QRectF m_rect(0, 0, m_width,  m_height);qreal tx = m_rect.center().x();qreal ty = m_rect.center().y();qreal rad = route * (M_PI / 180);qreal co = qCos(rad);qreal so = qSin(rad);QMatrix t1(1, 0, 0, 1, tx, ty);QMatrix t2(1, 0, 0, 1, -tx, -ty);QMatrix r(co, so, -so, co, 0, 0);QMatrix s(sx, 0, 0, sy, 0, 0);setTransform(QTransform(t2 * (s * (r * t1))), true);
}

整体绘制

class GraphicsScene: public QGraphicsScene
{Q_OBJECT
public:GraphicsScene(QObject *parent = nullptr);void LoadItems(QString fileName);void LoadItems(QByteArray bta);void SetFontDir(QString fonts);void SetSymbols(QString symbols);void RenderBaseItem(pugi::xml_node node);void RenderByFile(pugi::xml_node node);public slots:void OnTimeOut();private:QString m_symbols = "symbols";QString m_fontDir = "fonts";pugi::xml_document m_doc;
};

/***@description: parse CIM-G file render*@version: 1.0*@author: amjieker*@copyright: Copyright (c) 2024 by amjieker, All Rights Reserved.
*/#include "GraphicsScene.h"
#include "QTextCodec"
#include "QGraphicsRectItem"
#include "QWheelEvent"
#include "QDebug"
#include "QMouseEvent"
#include <QtMath>
#include "ItemLoader.h"
#include "pugixml/pugixml.hpp"
#include "Global.h"
#include "QFontDatabase"
#include "sstream"
#include "QTimer"#pragma execution_character_set("utf-8")using namespace pugi;GraphicsScene::GraphicsScene(QObject *parent): QGraphicsScene(parent)
{auto timer = new QTimer;connect(timer, &QTimer::timeout, this, &GraphicsScene::OnTimeOut);timer->start(1000);
}void GraphicsScene::LoadItems(QString fileName)
{auto bta = g_fileLoader->ReadFile(fileName);LoadItems(bta);
}void GraphicsScene::LoadItems(QByteArray bta)
{auto res = m_doc.load_buffer(bta, bta.size(), parse_default | parse_declaration);auto G = m_doc.child("G");pugi::xml_node node = m_doc.first_child();m_encoding = QTextCodec::codecForName(node.attribute("encoding").as_string());double w = G.attribute("w").as_double();double h = G.attribute("h").as_double();QString bgc = G.attribute("bgc").as_string();setSceneRect(0, 0, w, h);auto layer = m_doc.child("G").child("Layer");setBackgroundBrush(parseColorString(bgc));auto items = layer.children();for (auto item : items){QString devRef = m_encoding->toUnicode(item.attribute("devref").value());if (devRef.isEmpty()){RenderBaseItem(item);}else{RenderByFile(item);}}
}void GraphicsScene::SetFontDir(QString fonts)
{m_fontDir = fonts;
}void GraphicsScene::SetSymbols(QString symbols)
{m_symbols = symbols;
}void GraphicsScene::RenderBaseItem(pugi::xml_node node)
{QString name = node.name();if (name == "ConnectLine" || name == "polyline"){QString d = node.attribute("d").as_string();QString lc = node.attribute("lc").as_string(); // line colorauto ds = d.split(" ");QList<QPointF> list;for (int i = 0; i < ds.size(); i ++){QStringList now = ds[i].split(",");list.append(QPointF(now[0].toDouble(), now[1].toDouble()));}for (int i = 1; i < list.size(); i ++){auto item = new QGraphicsLineItem;item->setLine(QLineF(list[i-1], list[i]));auto pen = item->pen();pen.setColor(parseColorString(lc));item->setPen(pen);addItem(item);}}else if (name == "Bus" || name == "line"){double x1 = node.attribute("x1").as_float();double x2 = node.attribute("x2").as_float();double y1 = node.attribute("y1").as_float();double y2 = node.attribute("y2").as_float();int lw = node.attribute("lw").as_int();QString lc = node.attribute("lc").as_string(); // line colorauto item = new QGraphicsLineItem;item->setLine(x1, y1, x2, y2);auto pen = item->pen();pen.setWidth(lw);pen.setColor(parseColorString(lc));item->setPen(pen);addItem(item);}else if (name == "rect"){    double x = node.attribute("x").as_float();double y = node.attribute("y").as_float();double w = node.attribute("w").as_float();double h = node.attribute("h").as_float();QString lc = node.attribute("lc").as_string(); // line colorQString fc = node.attribute("fc").as_string(); // fill colorauto item = new QGraphicsRectItem;auto t_pen = item->pen();auto t_brush = item->brush();if (!lc.isEmpty()) t_pen.setColor(parseColorString(lc));if (!fc.isEmpty()) t_brush.setColor(parseColorString(fc));item->setPen(t_pen);item->setBrush(t_brush);item->setRect(QRectF(x, y, w, h));addItem(item);}else if (name == "Text"){QString value = m_encoding->toUnicode(node.attribute("ts").as_string());double x = node.attribute("x").as_double();double y = node.attribute("y").as_double();QString lc = node.attribute("lc").as_string(); // line colorQString fc = node.attribute("fc").as_string(); // fill colorint fs = node.attribute("fs").as_int(); // font sizeQString ff = m_encoding->toUnicode(node.attribute("ff").as_string());QString ts = m_encoding->toUnicode(node.attribute("ts").as_string());int ls = node.attribute("ls").as_int();int fm = node.attribute("fm").as_int();auto item = new QGraphicsTextItem;if (lc.isEmpty()) lc = fc;item->setDefaultTextColor(parseColorString(lc));item->setPlainText(value);auto font = item->font();font.setPixelSize(fs - 1);font.setFamily(ff);item->setFont(font);item->setPos(QPointF(x, y));addItem(item);}else if (name == "DText"){QString value = m_encoding->toUnicode(node.attribute("ts").as_string());double x = node.attribute("x").as_double();double y = node.attribute("y").as_double();QString lc = node.attribute("lc").as_string(); // line colorQString fc = node.attribute("fc").as_string(); // line colorint fs = node.attribute("fs").as_int(); // font sizeQString PathName = node.attribute("PathName").as_string();auto item = new QGraphicsTextItem;item->setFlags(/*QGraphicsItem::ItemIsMovable | */QGraphicsItem::ItemIsSelectable);if (lc.isEmpty()) lc = fc;item->setDefaultTextColor(parseColorString(lc));item->setPlainText(value);auto font = item->font();font.setPixelSize(fs - 1);font.setFamily(tr("宋体"));item->setFont(font);item->setPos(QPointF(x, y));addItem(item);}else if (name == "poke"){double x = node.attribute("x").as_float();double y = node.attribute("y").as_float();double w = node.attribute("w").as_float();double h = node.attribute("h").as_float();QString lc = node.attribute("lc").as_string(); // line colorQString fc = node.attribute("fc").as_string(); // fill colorauto* item = new QGraphicsRectItem;auto t_pen = item->pen();auto t_brush = item->brush();if (!lc.isEmpty()) t_pen.setColor(parseColorString(lc));if (!fc.isEmpty()){auto col = parseColorString(fc);t_brush.setColor(col);t_brush.setStyle(Qt::SolidPattern);}item->setPen(Qt::NoPen);item->setBrush(t_brush);item->setRect(QRectF(x, y, w, h));addItem(item);}else{qDebug() << "unkown" << name;}
}void GraphicsScene::RenderByFile(pugi::xml_node node)
{double x = node.attribute("x").as_double();double y = node.attribute("y").as_double();QString lc = node.attribute("lc").as_string(); // line colorQString fc = node.attribute("fc").as_string(); // fill colorQString tfr = node.attribute("tfr").as_string();QString PathName = node.attribute("PathName").as_string();QString filePath = (node.attribute("devref").as_string());filePath = filePath.split(":").first();filePath = filePath.remove(0, 1);filePath = m_symbols + /*"symbols/"*/ + "/" + filePath;auto* item = new GraphItem::ItemLoader(filePath);item->setFlags(/*QGraphicsItem::ItemIsMovable | */QGraphicsItem::ItemIsSelectable);auto pen = item->pen();auto brush = item->brush();if (!lc.isEmpty()) pen.setColor(parseColorString(lc));if (!fc.isEmpty()) brush.setColor(parseColorString(fc));item->setPen(pen);item->setBrush(brush);item->setPos(x, y);item->SetTfr(tfr);addItem(item);
}

效果

成功展示G文件图形,并和后台的保持风格一致
在这里插入图片描述
在这里插入图片描述

后话

本文所实现的并不是G文件的全部定义,我只实现了基础部分我需要的,至于细枝末节,未展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/337913.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

⌈ 传知代码 ⌋ 命名实体识别

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

vue3组件传值---vue组件通过属性,事件和provide,inject进行传值

通过属性传值&#xff08;父传子&#xff09; vue的组件具有props自建属性&#xff08;自定义名称&#xff0c;类似于class&#xff0c;id的属性&#xff09;&#xff0c;通过这个属性&#xff0c;父组件可以向子组件传递参数&#xff0c;从而实现组件之间的信息传递&#xff0…

深入探讨npm、Yarn、pnpm和npx之间的区别

前端生态系统是一个快速发展的领域&#xff0c;充满了各种工具和技术。对于开发人员来说&#xff0c;跟上这些创新可能是一项艰巨的挑战。 在本文中&#xff0c;我们将深入探讨npm、Yarn、pnpm和npx之间的区别&#xff0c;帮助你理解每个工具的不同之处。 包管理器比较 npm …

原码一位乘法(计算机组成原理)

算法原理 每次将1位乘数所对应的部分积与原部分积的“累积和”相加&#xff0c;并移位 设置寄存器 存放部分积累积和、乘积高位存放被乘数存放乘数、乘积低位 法则 乘积的数值位俩数绝对值之积&#xff1b;符号位 位 俩数符号位进行异或&#xff0c;即 p x ⊕ y 步骤 设…

你认识nginx吗,nginx是做什么的,nginx可以做什么 --1)nginx介绍

一.Nginx 介绍 Nginx&#xff08;发音同engine x&#xff09;是一个异步框架的 Web 服务器&#xff0c;也可以用作反向代理&#xff0c;负载平衡器 和 HTTP 缓存。该软件由 Igor Sysoev 创建&#xff0c;并于2004年首次公开发布。同名公司成立于2011年&#xff0c;以提供支持。…

【原型模式】详解

一.概念 原型模式是一种创建型设计模式&#xff0c;它的主要思想是通过复制现有对象来创建新对象&#xff0c;而不是通过实例化一个类来创建。在原型模式中&#xff0c;我们称被复制的对象为原型&#xff08;Prototype&#xff09;&#xff0c;新创建的对象为克隆体&#xff0…

Redis缓存(笔记一:缓存介绍和数据库启动)

目录 1、NoSQL数据库简介 2、Redis介绍 3、Redis(win系统、linux系统中操作) 3.1 win版本Redis启动 3.2 linux版本Redis启动 1、NoSQL数据库简介 技术的分类&#xff1a;&#xff08;发展史&#xff09; 1、解决功能性的问题&#xff1a;Java、Jsp、RDBMS、Tomcat、HTML、…

IC开发——VCS基本用法

1. 简介 VCS是编译型verilog仿真器&#xff0c;处理verilog的源码过程如下&#xff1a; VCS先将verilog/systemverilog文件转化为C文件&#xff0c;在linux下编译链接生成可执行文件&#xff0c;在linux下运行simv即可得到仿真结果。 VCS使用步骤&#xff0c;先编译verilog源…

【计算机毕业设计】388微信小程序足球赛事及队伍管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

开发一个comfyui的自定义节点-支持输入中文prompt

文章目录 目标功能开发环境实现过程翻译中文CLIP编码拓展仓库地址完整代码目标功能 目前comfyui的prompt提示词输入节点 CLIP Text Encode 只支持输入英文的prompt,而有时候我们需要自己制定一些prompt,所以就得将我们想要的提示词翻译为英文后再复制粘贴到该节点的输入框中…

Java的JDK环境变量配置(Windows)

只写了需要配置的环境变量 注&#xff1a;从JDK1.5开始&#xff0c;配置Java环境变量时&#xff0c;不再需要配置CLASSPATH&#xff0c;只需要配置JAVA_HOME和Path 1、配置JAVA_HOME 找到自己的JDK位置&#xff0c;我这里是 C:\dev\java\jdk-17.0.119在环境变量-系统变量中&…

ubuntu系统下安装mysql的步骤详解

一、下载安装包 下载地址&#xff1a; https://dev.mysql.com/downloads/repo/apt 跳转到这个页面&#xff1a; 直接点击Download。 直接点击最下面的开始下载安装包即可。 二、将安装包下载到ubuntu系统中 先将用户切换成root用户&#xff0c;把下载好的安装包复制到桌面上&…

互联网简史-分久必合,合久必分

六一儿童节&#xff0c;给孩子们讲讲互联网的历史。 任何当代技术都是古老技术的重组&#xff0c;这是真的。我从电话网络开始&#xff0c;两幅图完事。电波可以承载语音作为最开始&#xff0c;后面的事自然而然&#xff1a; 说实话&#xff0c;网络这种事&#xff0c;它的 …

各大平台取消一年期免费SSL证书后,如何申请超长期免费SSL证书

一&#xff1a;为什么一定要用SSL证书 SSL证书是一种提供网络安全的协议&#xff0c;主要作用是提供对用户和服务器的认证以及确保传送的数据进行加密和隐藏&#xff0c;从而保证数据的完整性和安全性。网站安装SSL证书后就可以实现HTTPS访问&#xff0c;消除网站访问不安全提…

从0开始制作微信小程序

目录 前言 正文 需要事先准备的 需要事先掌握的 什么是uniapp 平台应用的分类方式 什么是TypeScript 创建项目 项目文件作用 源码地址 尾声 &#x1f52d; Hi,I’m Pleasure1234&#x1f331; I’m currently learning Vue.js,SpringBoot,Computer Security and so on.&#x1…

一、大模型推理

https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md https://github.com/hiyouga/LLaMA-Factory/blob/main/examples/README_zh.md 安装 v7.1 https://github.com/hiyouga/LLaMA-Factory/releases/tag/v0.7.1 git clone --depth 1 https://github.com/hiyoug…

TS38.300中的切换流程(很一般)

本文根据3GPP R18 TS 38.300第9.2.3节整理 切换(Handover)是移动终端(UE)进入RRC_CONNECTED状态后在不同服务小区(Cell)之间保持与网络联系唯一手段&#xff0c;期间首先通过控制面(C-Plane)进行无线测量、切换协商及触发等&#xff1b;为此3GPP在TS38.300中定义如下。 RAN系统…

【六一儿童节】的科技奇幻旅程:解锁【机器学习】与【人工智能】的无限创意

目录 一、机器学习与人工智能简介 二、六一儿童节的特殊意义 三、项目概述&#xff1a;智能绘画助手 四、技术栈和工具 五、数据准备 六、模型训练 1. 数据预处理 2. 构建和训练模型 七、智能绘画助手的实现 1. 搭建Flask应用 2. 客户端界面 八、扩展功能与优化 1…

【算法】贪心算法——柠檬水找零

题解&#xff1a;柠檬水找零(贪心算法) 目录 1.题目2.题解3.参考代码4.证明5.总结 1.题目 题目链接&#xff1a;LINK 2.题解 分情况讨论 贪心算法 当顾客为5元时&#xff0c;收下当顾客为10元时&#xff0c;收下10元并找回5元当顾客为20元时&#xff0c;收下20元并找回10…

Fastjson 反序列化漏洞[1.2.24-rce]

漏洞复现环境搭建请参考 http://t.csdnimg.cn/vSaaw kali切换jdk版本请参考 Kali安装JAVA8和切换JDK版本的详细过程_kali安装jdk8-CSDN博客 漏洞原理 Fastjson提供的com.sun.rowset.JdbcRowSetImpl类下的dataSourceName方法支持传入一个RMI/LDAP源&#xff0c;支持远程调用。…