基于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 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} 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 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文件的全部定义,我只实现了基础部分我需要的,至于细枝末节,未展示

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ai晚班车531

1.中央网信办等三部门&#xff1a;加快推进大模型、生成式人工智能标准研制。 2.中国石油与中国移动、华为、科大讯飞签署合作协议。 3.Opera浏览器与谷歌云合作&#xff0c;接入 Gemini 大模型。 4.谷歌 Gemini 加持Chromebook Plus。 5.英飞凌&#xff1a;开发 8kW和12kW…

《技术人求职之道》:从入职到离职,全方位解析求职艺术

一、引言二、内容&#xff1a;该求职专栏包含什么三、结果&#xff1a;通过该专栏你将收获什么四、说明&#xff1a;关于该专栏的一些问题解答五、后记 一、引言 求职&#xff0c;这是每个人职业生涯中必经的阶段&#xff0c;技术人亦不例外。上一个冬天的寒风已过&#xff0c…

获取 Bean 对象更加简单的方式

获取 bean 对象也叫做对象装配&#xff0c;是把对象取出来放到某个类中&#xff0c;有时候也叫对象注⼊。 对象装配&#xff08;对象注⼊&#xff09;即DI 实现依赖注入的方式有 3 种&#xff1a; 1. 属性注⼊ 2. 构造⽅法注⼊ 3. Setter 注⼊ 属性注入 属性注⼊是使⽤ Auto…

MySQL性能分析工具——EXPLAIN

性能分析工具——EXPLAIN 1、概述 定位了查询慢的SQL之后&#xff0c;我们就可以使用EXPLAIN或DESCRIBE工具做针对性的分析查询语句 。 DESCRIBE语句的使用方法与EXPLAIN语句是一样的&#xff0c;并且分析结果也是一样的。 MySQL中有专门负责优化SELECT语句的优化器模块&…

报表工具DataEase技术方案(二)

一、DataEase报表功能开发流程 1. 创建数据源 2. 创建数据集 可以创建多种来源的数据集&#xff0c;这里以SQL数据集为例。 数据集SQL中可以添加参数&#xff0c;仪表板展示数据时可以根据参数来筛选数据。 数据集添加计算字段 3. 创建仪表板 &#xff08;1&#xff09;组合…

关于Posix标准接口和Nuttx操作系统

基本介绍 主要参考&#xff1a; Linux 系统中的 POSIX 接口详细介绍_linux posix-CSDN博客 POSIX&#xff08;Portable Operating System Interface&#xff0c;可移植操作系统接口&#xff09;是由 IEEE&#xff08;Institute of Electrical and Electronics Engineers&#x…

LLVM入门教学——SanitizerCoverage插桩(Linux)

1、介绍 LLVM 的 SanitizerCoverage 是一种代码覆盖工具&#xff0c;设计用于支持基于 fuzzing 的测试和其他安全相关工具。SanitizerCoverage 在编译时插桩代码&#xff0c;以在运行时收集覆盖信息&#xff0c;从而帮助识别未覆盖的代码路径&#xff0c;提高测试的有效性和全…

详细介绍运算符重载函数,清晰明了

祝各位六一快乐~ 前言 1.为什么要进行运算符重载&#xff1f; C中预定义的运算符的操作对象只能是基本数据类型。但实际上&#xff0c;对于许多用户自定义类型&#xff08;例如类&#xff09;&#xff0c;也需要类似的运算操作。这时就必须在C中重新定义这些运算符&#xff…

摄影后期照片编辑工具:LrC2024 for Mac/win 中文激活版

LrC2024&#xff08;Lightroom Classic 2024&#xff09;是 Adobe 公司推出的一款专业级别的照片编辑和管理软件。它是 Lightroom Classic CC 的升级版&#xff0c;具有更多的功能和改进。 这款软件主要用于数字摄影师和摄影爱好者处理、编辑和管理他们的照片。它提供了一套强大…

锅炉智能制造工厂工业物联数字孪生平台,推进制造业数字化转型

在制造业快速发展的今天&#xff0c;数字化转型已经成为企业提升竞争力的关键途径。锅炉智能制造工厂工业物联数字孪生平台&#xff0c;作为一种创新的技术解决方案&#xff0c;正以其独特的优势&#xff0c;为制造业的数字化转型提供强大动力。锅炉智能制造工厂工业物联数字孪…

【网络研究观】-20240531

战争揭开美国武器优势的面纱 随着俄军在哈尔科夫地区稳步推进&#xff0c;乌克兰战争对美国国防机器而言是一场灾难&#xff0c;这一点越来越明显&#xff0c;这不仅是因为我们的援助未能挽救乌克兰的撤退和可能的失败。更重要的是&#xff0c;这场战争无情地暴露了我们国防体…

我用大模型校稿出书的经验心得

1. 第一本AI校稿的书 我的新书《云计算行业进阶指南》已经出版&#xff0c;本书使用了大模型进行AI校对书稿。 在本文稿发布前&#xff0c;我问了好几个AI&#xff0c;AI都说“还没有出版书籍宣称自己使用了AI校稿”&#xff0c;因此我可以说&#xff1a; 本书是第一本公开宣称…

Docker搭建Redis主从 + Redis哨兵模式(一主一从俩哨兵)

我这里是搭建一主一从&#xff0c;俩哨兵&#xff0c;准备两台服务器&#xff0c;分别安装docker 我这里有两台centos服务器 主服务器IP&#xff1a;192.168.252.134 从服务器IP&#xff1a;192.168.252.135 1.两台服务器分别拉取redis镜像 docker pull redis 2.查看镜像 d…

编写备份MySQL 脚本

目录 环境准备 增量备份 增量备份和差异备份 完整代码如下 测试脚本是否正常 星期天运行脚本&#xff08;完全备份&#xff09; 星期一运备份脚本&#xff08;增量备份&#xff09; 星期二备份数据&#xff08;其他天--增量备份&#xff09; 星期三备份数据&#xff08;差异备…

cobalt strike基础测试

下载链接4.3&#xff1a;https://pan.baidu.com/s/1E_0t30tFWRiE5aJ7F-ZDPg 链接4.0&#xff1a;https://pan.baidu.com/s/1SkMmDem3l6bePqIDgUz2mA 提取码&#xff1a;burp 一、简介&#xff1a; cobalt strike(简称CS)是一款团队作战渗透测试神器&#xff0c;分为客户端…

C++笔试强训day37

目录 1.旋转字符串 2.合并k个已排序的链表 3.滑雪 1.旋转字符串 链接https://www.nowcoder.com/practice/80b6bb8797644c83bc50ac761b72981c?tpId196&tqId37172&ru/exam/oj 如果 A 字符串能够旋转之后得到 B 字符串的话&#xff0c;在 A 字符串倍增之后的新串中&am…

linux驱动学习(二)之点灯

需要板子一起学习的可以这里购买&#xff08;含资料&#xff09;&#xff1a;点击跳转 如何实现对硬件控制 分析硬件原理图&#xff08;开发板的原理图&#xff09;----> 分析硬件的控制方法 ---> 控制硬件时&#xff0c;所要用到的寄存器 ----> 了解控制硬件寄存器的…

关于如何在Arch Linux上编写自己的第一个module

前一段时间一直想深入学习编写一个module插入到自己的内核当中&#xff0c;但是网上的资料基本上全都针对的Ubuntu和Debian等流行的Linux发行版&#xff0c;这里打算简单的记录一波博客。 啥是Module?(着急可不看) 众所周知&#xff1a;现代宏内核架构的操作系统都会借鉴微内核…

【stableDiffusion】HuggingFace模型下载(只要知道url,就直接开始下载)

一、方法 有人说&#xff0c;那我怎么知道 huggingface 上面我想要的资源的url&#xff0c;去哪儿找啊&#xff1f; 那就涉及到一些魔法手段了&#xff0c;或者你能在其他人的博客或者百度上搜索到合适的url。 我这个办法是用来节约我的魔法的流量的。 1.迅雷 1.1 打开迅雷&…

【Kotlin】简单介绍与使用kotlin

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Kotlin ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 特点 变量和常量 数据类型和类型推断 函数 字符串模板 条件表达式 空安全 when 表达式 循环 我的其他博客 前言 Kotlin是…