本文讲述了如何使用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 color
QString fc = item.attribute("fc").as_string(); // fill color
auto 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 color
QString fc = item.attribute("fc").as_string(); // fill color
auto 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 color
QString fc = item.attribute("fc").as_string(); // fill color
auto 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 color
QString fc = item.attribute("fc").as_string(); // fill color
auto 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 color
QString fc = item.attribute("fc").as_string(); // fill color
auto 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 color
QString fc = item.attribute("fc").as_string(); // fill color
auto 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 color
QString fc = item.attribute("fc").as_string(); // line color
int fs = item.attribute("fs").as_int(); // font size
QString 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} 10−dx01−dy001
将四个变换矩阵连乘起来之后,就是我们最后的变换矩阵
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 color
auto 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 color
auto 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 color
QString fc = node.attribute("fc").as_string(); // fill color
auto 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 color
QString fc = node.attribute("fc").as_string(); // fill color
int fs = node.attribute("fs").as_int(); // font size
QString 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 color
QString fc = node.attribute("fc").as_string(); // line color
int fs = node.attribute("fs").as_int(); // font size
QString 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 color
QString fc = node.attribute("fc").as_string(); // fill color
auto* 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 color
QString fc = node.attribute("fc").as_string(); // fill color
QString 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文件的全部定义,我只实现了基础部分我需要的,至于细枝末节,未展示