mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-07 20:34:14 +02:00
Add an option to export symbols as DXF blocks (#1339)
With "DXF : symboles en blocs" ticked in the export dialog, or --dxf-blocks on the command line, each symbol definition a folio uses is written once as a DXF block and every placed symbol as an INSERT of it. A CAD program then selects, counts and replaces a symbol as one object. The block is drawn by the same code as a symbol drawn in full, as if the symbol sat unturned at the folio's origin, which is DXF (0, sheetHeight): that is the block's base point, so the INSERT carries the symbol's position and quarter-turn and nothing else. Blocks have to come before any entity, so the export collects them first and dxfBegin() writes them in its BLOCKS section. Entities in a block keep their own layers. Off by default; with it off the file is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -331,7 +331,8 @@ int exportImages(QETProject &project, const QString &format,
|
||||
/// One DXF file per diagram, written by the same code as the export dialog
|
||||
/// (DxfExport) with the dialog's default options -- the export settings of
|
||||
/// the preferences -- so both give the same file.
|
||||
int exportDxf(QETProject &project, const QString &out_dir, bool showTerminals)
|
||||
int exportDxf(QETProject &project, const QString &out_dir, bool showTerminals,
|
||||
bool dxfBlocks)
|
||||
{
|
||||
const QList<Diagram *> diagrams = project.diagrams();
|
||||
if (diagrams.isEmpty()) {
|
||||
@@ -344,6 +345,8 @@ int exportDxf(QETProject &project, const QString &out_dir, bool showTerminals)
|
||||
properties.format = QStringLiteral("DXF");
|
||||
if (showTerminals)
|
||||
properties.draw_terminals = true;
|
||||
if (dxfBlocks)
|
||||
properties.dxf_blocks = true;
|
||||
|
||||
int index = 0;
|
||||
bool has_images = false;
|
||||
@@ -982,6 +985,7 @@ int run(const QStringList &args)
|
||||
// collected below.
|
||||
QStringList filtered = args;
|
||||
const bool showTerminals = filtered.removeAll("--show-terminals") > 0;
|
||||
const bool dxfBlocks = filtered.removeAll("--dxf-blocks") > 0;
|
||||
// --no-slaves and --no-junctions leave rows out of --export-bom.
|
||||
const bool includeSlaves = filtered.removeAll("--no-slaves") == 0;
|
||||
const bool includeJunctions = filtered.removeAll("--no-junctions") == 0;
|
||||
@@ -1038,7 +1042,7 @@ int run(const QStringList &args)
|
||||
if (format == "pdf")
|
||||
return exportPdf(project, output, showTerminals);
|
||||
if (format == "dxf")
|
||||
return exportDxf(project, output, showTerminals);
|
||||
return exportDxf(project, output, showTerminals, dxfBlocks);
|
||||
if (format == "cables" || format == "wires")
|
||||
return exportCsv(project, format, output);
|
||||
if (format == "bom")
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace CLIExport {
|
||||
qelectrotech --export-pdf <project.qet> <output.pdf> [--show-terminals]
|
||||
qelectrotech --export-png <project.qet> <output_dir> [--show-terminals]
|
||||
qelectrotech --export-svg <project.qet> <output_dir> [--show-terminals]
|
||||
qelectrotech --export-dxf <project.qet> <output_dir> [--show-terminals]
|
||||
qelectrotech --export-dxf <project.qet> <output_dir> [--show-terminals] [--dxf-blocks]
|
||||
qelectrotech --export-cables <project.qet> <output.csv>
|
||||
qelectrotech --export-wires <project.qet> <output.csv>
|
||||
qelectrotech --export-bom <project.qet> <output.csv> [--no-slaves] [--no-junctions]
|
||||
@@ -66,6 +66,8 @@ namespace CLIExport {
|
||||
does; off by default, matching the GUI export dialog's
|
||||
default. For DXF, draws the terminal markers. Has no effect on
|
||||
the list export modes.
|
||||
--dxf-blocks: write each symbol as a DXF block, placed with one
|
||||
INSERT per use, so a CAD program selects it as one object.
|
||||
cables: wiring list (one row per conductor) as CSV.
|
||||
wires: list of distinct wire numbers as CSV.
|
||||
bom: bill of materials (one row per element) as CSV.
|
||||
|
||||
+156
-2
@@ -68,7 +68,16 @@ Createdxf::~Createdxf()
|
||||
/* Header section of every DXF file.
|
||||
@param layers : the layers the entities will be written on, declared in
|
||||
the LAYER table beside layer "0", which every DXF has. */
|
||||
void Createdxf::dxfBegin (const QString& fileName, const QStringList &layers)
|
||||
/**
|
||||
@brief Createdxf::dxfBegin
|
||||
Write the header, the tables with @a layers, and the BLOCKS section,
|
||||
then open the ENTITIES section. @a writeBlocks, if given, is called
|
||||
inside the BLOCKS section to write the block definitions
|
||||
(dxfBlockBegin(), the entities, dxfBlockEnd()): a block has to be
|
||||
defined before any entity, so before anything is drawn.
|
||||
*/
|
||||
void Createdxf::dxfBegin (const QString& fileName, const QStringList &layers,
|
||||
const std::function<void()> &writeBlocks)
|
||||
{
|
||||
layer = QStringLiteral("0");
|
||||
|
||||
@@ -276,17 +285,162 @@ void Createdxf::dxfBegin (const QString& fileName, const QStringList &layers)
|
||||
To_Dxf << "SECTION" << "\r\n";
|
||||
To_Dxf << 2 << "\r\n";
|
||||
To_Dxf << "BLOCKS" << "\r\n";
|
||||
file.close();
|
||||
}
|
||||
if (writeBlocks)
|
||||
writeBlocks();
|
||||
QFile entities(fileName);
|
||||
if (entities.open(QFile::Append)) {
|
||||
QTextStream To_Dxf(&entities);
|
||||
To_Dxf << 0 << "\r\n";
|
||||
To_Dxf << "ENDSEC" << "\r\n";
|
||||
To_Dxf << 0 << "\r\n";
|
||||
To_Dxf << "SECTION" << "\r\n";
|
||||
To_Dxf << 2 << "\r\n";
|
||||
To_Dxf << "ENTITIES" << "\r\n";
|
||||
file.close();
|
||||
entities.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Createdxf::dxfBlockBegin
|
||||
Start the definition of block @a name, with its base point at @a x,
|
||||
@a y. Only inside dxfBegin()'s writeBlocks; every entity written until
|
||||
dxfBlockEnd() belongs to the block.
|
||||
@param hasAttributes : the block has attribute definitions
|
||||
*/
|
||||
void Createdxf::dxfBlockBegin(const QString &fileName,
|
||||
const QString &name,
|
||||
double x,
|
||||
double y,
|
||||
bool hasAttributes)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (!file.open(QFile::Append))
|
||||
return;
|
||||
QTextStream To_Dxf(&file);
|
||||
To_Dxf << 0 << "\r\n";
|
||||
To_Dxf << "BLOCK" << "\r\n";
|
||||
To_Dxf << 8 << "\r\n";
|
||||
To_Dxf << "0" << "\r\n";
|
||||
To_Dxf << 2 << "\r\n";
|
||||
To_Dxf << name << "\r\n";
|
||||
To_Dxf << 70 << "\r\n";
|
||||
To_Dxf << (hasAttributes ? 2 : 0) << "\r\n";
|
||||
To_Dxf << 10 << "\r\n";
|
||||
To_Dxf << x << "\r\n";
|
||||
To_Dxf << 20 << "\r\n";
|
||||
To_Dxf << y << "\r\n";
|
||||
To_Dxf << 30 << "\r\n";
|
||||
To_Dxf << 0.0 << "\r\n";
|
||||
file.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Createdxf::dxfBlockEnd
|
||||
End the block started by dxfBlockBegin().
|
||||
*/
|
||||
void Createdxf::dxfBlockEnd(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (!file.open(QFile::Append))
|
||||
return;
|
||||
QTextStream To_Dxf(&file);
|
||||
To_Dxf << 0 << "\r\n";
|
||||
To_Dxf << "ENDBLK" << "\r\n";
|
||||
To_Dxf << 8 << "\r\n";
|
||||
To_Dxf << "0" << "\r\n";
|
||||
file.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Createdxf::drawInsert
|
||||
Place block @a name at @a x, @a y, turned counter-clockwise by
|
||||
@a rotation degrees, on the current layer, followed by its
|
||||
@a attributes.
|
||||
*/
|
||||
void Createdxf::drawInsert(const QString &fileName,
|
||||
const QString &name,
|
||||
double x,
|
||||
double y,
|
||||
double rotation,
|
||||
const QList<Attribute> &attributes)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (!file.open(QFile::Append))
|
||||
return;
|
||||
QTextStream To_Dxf(&file);
|
||||
To_Dxf << 0 << "\r\n";
|
||||
To_Dxf << "INSERT" << "\r\n";
|
||||
To_Dxf << 8 << "\r\n";
|
||||
To_Dxf << layer << "\r\n";
|
||||
if (!attributes.isEmpty()) {
|
||||
To_Dxf << 66 << "\r\n";
|
||||
To_Dxf << 1 << "\r\n";
|
||||
}
|
||||
To_Dxf << 2 << "\r\n";
|
||||
To_Dxf << name << "\r\n";
|
||||
To_Dxf << 10 << "\r\n";
|
||||
To_Dxf << x << "\r\n";
|
||||
To_Dxf << 20 << "\r\n";
|
||||
To_Dxf << y << "\r\n";
|
||||
To_Dxf << 30 << "\r\n";
|
||||
To_Dxf << 0.0 << "\r\n";
|
||||
To_Dxf << 50 << "\r\n";
|
||||
To_Dxf << rotation << "\r\n";
|
||||
for (const Attribute &attribute : attributes) {
|
||||
To_Dxf << 0 << "\r\n";
|
||||
To_Dxf << "ATTRIB" << "\r\n";
|
||||
To_Dxf << 8 << "\r\n";
|
||||
To_Dxf << layer << "\r\n";
|
||||
To_Dxf << 62 << "\r\n";
|
||||
To_Dxf << entityColour(attribute.colour) << "\r\n";
|
||||
To_Dxf << 10 << "\r\n";
|
||||
To_Dxf << attribute.x << "\r\n";
|
||||
To_Dxf << 20 << "\r\n";
|
||||
To_Dxf << attribute.y << "\r\n";
|
||||
To_Dxf << 30 << "\r\n";
|
||||
To_Dxf << 0.0 << "\r\n";
|
||||
To_Dxf << 40 << "\r\n";
|
||||
To_Dxf << attribute.height << "\r\n";
|
||||
To_Dxf << 1 << "\r\n";
|
||||
To_Dxf << singleLine(attribute.text) << "\r\n";
|
||||
To_Dxf << 2 << "\r\n";
|
||||
To_Dxf << attribute.tag << "\r\n";
|
||||
To_Dxf << 70 << "\r\n";
|
||||
To_Dxf << (attribute.invisible ? 1 : 0) << "\r\n";
|
||||
To_Dxf << 50 << "\r\n";
|
||||
To_Dxf << attribute.rotation << "\r\n";
|
||||
To_Dxf << 41 << "\r\n";
|
||||
To_Dxf << attribute.xScaleW << "\r\n";
|
||||
}
|
||||
if (!attributes.isEmpty()) {
|
||||
To_Dxf << 0 << "\r\n";
|
||||
To_Dxf << "SEQEND" << "\r\n";
|
||||
To_Dxf << 8 << "\r\n";
|
||||
To_Dxf << layer << "\r\n";
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Createdxf::blockName
|
||||
@return @a name as a block or attribute name an R10 reader accepts:
|
||||
upper case, only A-Z, 0-9, _, - and $, at most 31 characters
|
||||
*/
|
||||
QString Createdxf::blockName(const QString &name)
|
||||
{
|
||||
QString result;
|
||||
for (const QChar c : name.toUpper()) {
|
||||
const ushort u = c.unicode();
|
||||
const bool ok = (u >= 'A' && u <= 'Z') || (u >= '0' && u <= '9')
|
||||
|| u == '_' || u == '-' || u == '$';
|
||||
result += ok ? c : QChar('_');
|
||||
}
|
||||
return result.left(31);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Createdxf::dxfEnd
|
||||
End Section of every DXF File
|
||||
|
||||
+30
-1
@@ -22,6 +22,8 @@
|
||||
#include <QtCore>
|
||||
#include <QtWidgets>
|
||||
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
@brief The Createdxf class
|
||||
This class exports the project to DXF Format
|
||||
@@ -31,8 +33,35 @@ class Createdxf
|
||||
public:
|
||||
Createdxf();
|
||||
~Createdxf();
|
||||
static void dxfBegin (const QString&, const QStringList &layers = QStringList());
|
||||
static void dxfBegin (const QString&, const QStringList &layers = QStringList(),
|
||||
const std::function<void()> &writeBlocks = {});
|
||||
static void dxfEnd(const QString&);
|
||||
static void dxfBlockBegin(const QString &fileName,
|
||||
const QString &name,
|
||||
double x,
|
||||
double y,
|
||||
bool hasAttributes = false);
|
||||
static void dxfBlockEnd(const QString &fileName);
|
||||
/// One attribute of a placed block, in DXF units
|
||||
struct Attribute
|
||||
{
|
||||
QString tag;
|
||||
QString text;
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
double height = 0;
|
||||
double rotation = 0;
|
||||
double xScaleW = 1;
|
||||
int colour = 0;
|
||||
bool invisible = false;
|
||||
};
|
||||
static void drawInsert(const QString &fileName,
|
||||
const QString &name,
|
||||
double x,
|
||||
double y,
|
||||
double rotation,
|
||||
const QList<Attribute> &attributes = {});
|
||||
static QString blockName(const QString &name);
|
||||
// you can add more functions to create more drawings.
|
||||
static void drawCircle(
|
||||
const QString&,
|
||||
|
||||
+186
-109
@@ -42,6 +42,125 @@
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
Draw the drawing of @a elmt's definition: its static texts, lines,
|
||||
rectangles, circles, polygons and arcs, and its terminals when
|
||||
@a draw_terminals, as if it were placed at @a elem_pos_x,
|
||||
@a elem_pos_y and turned @a rotation_angle degrees. Used for every
|
||||
symbol drawn in full, and once per block for a block's content.
|
||||
*/
|
||||
void drawSymbol(const QString &file_path, Element *elmt,
|
||||
qreal elem_pos_x, qreal elem_pos_y,
|
||||
double rotation_angle, bool draw_terminals)
|
||||
{
|
||||
using namespace DxfExport;
|
||||
ElementPictureFactory::primitives primitives = ElementPictureFactory::instance()->getPrimitives(elmt->location());
|
||||
|
||||
Createdxf::layer = Layer::SymbolTexts;
|
||||
for(QGraphicsSimpleTextItem *text : primitives.m_texts)
|
||||
{
|
||||
qreal fontSize = text->font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = text->font().pixelSize();
|
||||
|
||||
qreal x = elem_pos_x + text->pos().x();
|
||||
qreal y = elem_pos_y + text->pos().y();
|
||||
|
||||
qreal angle = text -> rotation() + rotation_angle;
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
|
||||
QPointF transformed_point = DxfExport::rotation_transformed(x, y, elem_pos_x, elem_pos_y, -rotation_angle);
|
||||
x = transformed_point.x() - ydir * fontSize * 0.5;
|
||||
y = transformed_point.y() - xdir * fontSize * 0.5;
|
||||
QStringList lines = text->text().split('\n');
|
||||
qreal offset = fontSize * 1.6;
|
||||
for (QString line : lines)
|
||||
{
|
||||
if (line.size() > 0 && line != "_" ) {
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize, 360 - angle, 0, 0.72);
|
||||
}
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
Createdxf::layer = Layer::Symbols;
|
||||
for (QLineF line : primitives.m_lines)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QLineF l = t.map(line);
|
||||
Createdxf::drawLine(file_path, l, 0);
|
||||
}
|
||||
|
||||
for (QRectF rect : primitives.m_rectangles)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QRectF r = t.mapRect(rect);
|
||||
Createdxf::drawRectangle(file_path,r,0);
|
||||
}
|
||||
|
||||
for (QRectF circle_rect : primitives.m_circles)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QPointF c = t.map(QPointF(circle_rect.center().x(),circle_rect.center().y()));
|
||||
Createdxf::drawCircle(file_path,c,circle_rect.width()/2,0);
|
||||
}
|
||||
|
||||
for (QVector<QPointF> polygon : primitives.m_polygons)
|
||||
{
|
||||
if (polygon.size() == 0)
|
||||
continue;
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QPolygonF poly = t.map(polygon);
|
||||
if(poly.isClosed())
|
||||
Createdxf::drawPolygon(file_path,poly,0);
|
||||
else
|
||||
Createdxf::drawPolyline(file_path,poly,0);
|
||||
}
|
||||
|
||||
// Draw arcs and ellipses
|
||||
for (QVector<qreal> arc : primitives.m_arcs)
|
||||
{
|
||||
if (arc.size() == 0)
|
||||
continue;
|
||||
qreal x = (elem_pos_x + arc.at(0));
|
||||
qreal y = (elem_pos_y + arc.at(1));
|
||||
qreal w = arc.at(2);
|
||||
qreal h = arc.at(3);
|
||||
qreal startAngle = arc.at(4);
|
||||
qreal spanAngle = arc .at(5);
|
||||
QRectF r(x,y,w,h);
|
||||
QPointF hotspot(elem_pos_x,elem_pos_y);
|
||||
Createdxf::drawArcEllipse(file_path, r, startAngle, spanAngle, hotspot, rotation_angle, 0);
|
||||
}
|
||||
if (draw_terminals) {
|
||||
Createdxf::layer = Layer::Terminals;
|
||||
// Draw terminals
|
||||
QList<Terminal *> list_terminals = elmt->terminals();
|
||||
QColor col("red");
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
foreach(Terminal *tp, list_terminals) {
|
||||
QPointF c = t.map(QPointF(tp->dock_elmt_.x(),tp->dock_elmt_.y()));
|
||||
Createdxf::drawCircle(file_path,c,3.0,Createdxf::dxfColor(col));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Nothing would be drawn for @a elmt (its definition is missing)
|
||||
bool drawsNothing(Element *elmt, bool draw_terminals)
|
||||
{
|
||||
const ElementPictureFactory::primitives p =
|
||||
ElementPictureFactory::instance()->getPrimitives(elmt->location());
|
||||
return p.m_lines.isEmpty() && p.m_rectangles.isEmpty()
|
||||
&& p.m_circles.isEmpty() && p.m_polygons.isEmpty()
|
||||
&& p.m_arcs.isEmpty() && p.m_texts.isEmpty()
|
||||
&& (!draw_terminals || elmt->terminals().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DxfExport::folioSize
|
||||
@return the size of @a diagram as exported with @a properties: its border
|
||||
@@ -88,19 +207,6 @@ void DxfExport::write(Diagram *diagram, int width, int height,
|
||||
Createdxf::xScale = scale;
|
||||
Createdxf::yScale = scale;
|
||||
|
||||
Createdxf::dxfBegin(file_path, Layer::all());
|
||||
|
||||
//Each kind of content on its own layer (discussion #1071). The
|
||||
//border's title block switches to Layer::TitleBlock itself, see
|
||||
//BorderTitleBlock::drawDxf().
|
||||
Createdxf::layer = Layer::Border;
|
||||
//Add project elements (lines, rectangles, circles, texts) to dxf file
|
||||
if (properties.draw_border) {
|
||||
QRectF rect(Diagram::margin,Diagram::margin,width,height);
|
||||
Createdxf::drawRectangle(file_path,rect,0);
|
||||
}
|
||||
diagram -> border_and_titleblock.drawDxf(file_path, 0);
|
||||
|
||||
// Build the lists of elements.
|
||||
QList<Element *> list_elements;
|
||||
QList<Conductor *> list_conductors;
|
||||
@@ -169,6 +275,58 @@ void DxfExport::write(Diagram *diagram, int width, int height,
|
||||
}
|
||||
}
|
||||
|
||||
//Symbols as blocks: one block per symbol definition the folio
|
||||
//uses, named after its file and numbered in the order first met,
|
||||
//so a repeat export is identical. A block has to be written before
|
||||
//any entity, so they are all collected first.
|
||||
QHash<QString, QString> block_names; // location -> block name
|
||||
QList<Element *> block_models; // one placed symbol per block
|
||||
if (properties.dxf_blocks) {
|
||||
QSet<QString> used;
|
||||
for (Element *elmt : std::as_const(list_elements)) {
|
||||
const QString key = elmt -> location().toString();
|
||||
if (block_names.contains(key)
|
||||
|| drawsNothing(elmt, properties.draw_terminals))
|
||||
continue;
|
||||
QString file_name = elmt -> location().fileName();
|
||||
if (file_name.endsWith(QLatin1String(".elmt")))
|
||||
file_name.chop(5);
|
||||
const QString base = Createdxf::blockName(
|
||||
QStringLiteral("QET_") + file_name);
|
||||
QString name = base;
|
||||
for (int i = 2 ; used.contains(name) ; ++i) {
|
||||
const QString suffix = QStringLiteral("_%1").arg(i);
|
||||
name = base.left(31 - suffix.size()) + suffix;
|
||||
}
|
||||
used << name;
|
||||
block_names.insert(key, name);
|
||||
block_models << elmt;
|
||||
}
|
||||
}
|
||||
|
||||
//A block is drawn as if its symbol sat unturned at the folio's
|
||||
//origin, which is DXF (0, sheetHeight); that is its base point.
|
||||
Createdxf::dxfBegin(file_path, Layer::all(), [&]() {
|
||||
for (Element *model : std::as_const(block_models)) {
|
||||
Createdxf::dxfBlockBegin(file_path,
|
||||
block_names.value(model -> location().toString()),
|
||||
0, Createdxf::sheetHeight);
|
||||
drawSymbol(file_path, model, 0, 0, 0, properties.draw_terminals);
|
||||
Createdxf::dxfBlockEnd(file_path);
|
||||
}
|
||||
});
|
||||
|
||||
//Each kind of content on its own layer (discussion #1071). The
|
||||
//border's title block switches to Layer::TitleBlock itself, see
|
||||
//BorderTitleBlock::drawDxf().
|
||||
Createdxf::layer = Layer::Border;
|
||||
//Add project elements (lines, rectangles, circles, texts) to dxf file
|
||||
if (properties.draw_border) {
|
||||
QRectF rect(Diagram::margin,Diagram::margin,width,height);
|
||||
Createdxf::drawRectangle(file_path,rect,0);
|
||||
}
|
||||
diagram -> border_and_titleblock.drawDxf(file_path, 0);
|
||||
|
||||
// Draw shapes
|
||||
Createdxf::layer = Layer::Shapes;
|
||||
foreach (QetShapeItem *qsi, list_shapes) qsi->toDXF(file_path, qsi->pen());
|
||||
@@ -179,105 +337,24 @@ void DxfExport::write(Diagram *diagram, int width, int height,
|
||||
gti->toDXF(file_path);
|
||||
}
|
||||
|
||||
//Draw elements
|
||||
//Draw elements: each one in full, or as an INSERT of its block
|
||||
foreach(Element *elmt, list_elements)
|
||||
{
|
||||
double rotation_angle = elmt -> orientation() * 90;
|
||||
const double rotation_angle = elmt -> orientation() * 90;
|
||||
const qreal elem_pos_x = elmt -> pos().x();
|
||||
const qreal elem_pos_y = elmt -> pos().y();
|
||||
|
||||
qreal elem_pos_x = elmt -> pos().x();
|
||||
qreal elem_pos_y = elmt -> pos().y();// - (diagram -> margin / 2);
|
||||
|
||||
ElementPictureFactory::primitives primitives = ElementPictureFactory::instance()->getPrimitives(elmt->location());
|
||||
|
||||
Createdxf::layer = Layer::SymbolTexts;
|
||||
for(QGraphicsSimpleTextItem *text : primitives.m_texts)
|
||||
{
|
||||
qreal fontSize = text->font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = text->font().pixelSize();
|
||||
|
||||
qreal x = elem_pos_x + text->pos().x();
|
||||
qreal y = elem_pos_y + text->pos().y();
|
||||
|
||||
qreal angle = text -> rotation() + rotation_angle;
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
|
||||
QPointF transformed_point = rotation_transformed(x, y, elem_pos_x, elem_pos_y, -rotation_angle);
|
||||
x = transformed_point.x() - ydir * fontSize * 0.5;
|
||||
y = transformed_point.y() - xdir * fontSize * 0.5;
|
||||
QStringList lines = text->text().split('\n');
|
||||
qreal offset = fontSize * 1.6;
|
||||
for (QString line : lines)
|
||||
{
|
||||
if (line.size() > 0 && line != "_" ) {
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize, 360 - angle, 0, 0.72);
|
||||
}
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
Createdxf::layer = Layer::Symbols;
|
||||
for (QLineF line : primitives.m_lines)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QLineF l = t.map(line);
|
||||
Createdxf::drawLine(file_path, l, 0);
|
||||
}
|
||||
|
||||
for (QRectF rect : primitives.m_rectangles)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QRectF r = t.mapRect(rect);
|
||||
Createdxf::drawRectangle(file_path,r,0);
|
||||
}
|
||||
|
||||
for (QRectF circle_rect : primitives.m_circles)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QPointF c = t.map(QPointF(circle_rect.center().x(),circle_rect.center().y()));
|
||||
Createdxf::drawCircle(file_path,c,circle_rect.width()/2,0);
|
||||
}
|
||||
|
||||
for (QVector<QPointF> polygon : primitives.m_polygons)
|
||||
{
|
||||
if (polygon.size() == 0)
|
||||
continue;
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QPolygonF poly = t.map(polygon);
|
||||
if(poly.isClosed())
|
||||
Createdxf::drawPolygon(file_path,poly,0);
|
||||
else
|
||||
Createdxf::drawPolyline(file_path,poly,0);
|
||||
}
|
||||
|
||||
// Draw arcs and ellipses
|
||||
for (QVector<qreal> arc : primitives.m_arcs)
|
||||
{
|
||||
if (arc.size() == 0)
|
||||
continue;
|
||||
qreal x = (elem_pos_x + arc.at(0));
|
||||
qreal y = (elem_pos_y + arc.at(1));
|
||||
qreal w = arc.at(2);
|
||||
qreal h = arc.at(3);
|
||||
qreal startAngle = arc.at(4);
|
||||
qreal spanAngle = arc .at(5);
|
||||
QRectF r(x,y,w,h);
|
||||
QPointF hotspot(elem_pos_x,elem_pos_y);
|
||||
Createdxf::drawArcEllipse(file_path, r, startAngle, spanAngle, hotspot, rotation_angle, 0);
|
||||
}
|
||||
if (properties.draw_terminals) {
|
||||
Createdxf::layer = Layer::Terminals;
|
||||
// Draw terminals
|
||||
QList<Terminal *> list_terminals = elmt->terminals();
|
||||
QColor col("red");
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
foreach(Terminal *tp, list_terminals) {
|
||||
QPointF c = t.map(QPointF(tp->dock_elmt_.x(),tp->dock_elmt_.y()));
|
||||
Createdxf::drawCircle(file_path,c,3.0,Createdxf::dxfColor(col));
|
||||
}
|
||||
const QString block = block_names.value(elmt -> location().toString());
|
||||
if (block.isEmpty()) {
|
||||
drawSymbol(file_path, elmt, elem_pos_x, elem_pos_y,
|
||||
rotation_angle, properties.draw_terminals);
|
||||
} else {
|
||||
Createdxf::layer = Layer::Symbols;
|
||||
//QElectroTech turns a symbol clockwise, DXF counter-clockwise
|
||||
Createdxf::drawInsert(file_path, block,
|
||||
elem_pos_x * Createdxf::xScale,
|
||||
Createdxf::sheetHeight - elem_pos_y * Createdxf::yScale,
|
||||
std::fmod(360 - rotation_angle, 360));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ ExportProperties::ExportProperties() :
|
||||
draw_terminal_names(false),
|
||||
draw_bg_transparent(false),
|
||||
draw_colored_conductors(true),
|
||||
dxf_blocks(false),
|
||||
exported_area(QET::BorderArea)
|
||||
{
|
||||
}
|
||||
@@ -77,6 +78,8 @@ void ExportProperties::toSettings(QSettings &settings,
|
||||
draw_bg_transparent);
|
||||
settings.setValue(prefix % "drawcoloredconductors",
|
||||
draw_colored_conductors);
|
||||
settings.setValue(prefix % "dxfblocks",
|
||||
dxf_blocks);
|
||||
settings.setValue(prefix % "area",
|
||||
QET::diagramAreaToString(exported_area));
|
||||
}
|
||||
@@ -115,6 +118,8 @@ void ExportProperties::fromSettings(QSettings &settings,
|
||||
draw_colored_conductors = settings.value(
|
||||
prefix % "drawcoloredconductors",
|
||||
true ).toBool();
|
||||
dxf_blocks = settings.value(prefix % "dxfblocks",
|
||||
false).toBool();
|
||||
|
||||
exported_area = QET::diagramAreaFromString(
|
||||
settings.value(
|
||||
|
||||
@@ -50,6 +50,7 @@ class ExportProperties {
|
||||
bool draw_terminal_names; ///< Whether to render terminal names/labels
|
||||
bool draw_bg_transparent; ///< Whether to use transparency for SVG-Export
|
||||
bool draw_colored_conductors; ///< Whether to render conductors colors
|
||||
bool dxf_blocks; ///< DXF: each symbol as a block, placed with an INSERT
|
||||
QET::DiagramArea exported_area; ///< Area of diagrams to be rendered
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -66,6 +66,7 @@ ExportProperties ExportPropertiesWidget::exportProperties() const
|
||||
export_properties.draw_terminal_names = draw_terminal_names -> isChecked();
|
||||
export_properties.draw_bg_transparent = draw_bg_transparent -> isChecked();
|
||||
export_properties.draw_colored_conductors = draw_colored_conductors -> isChecked();
|
||||
export_properties.dxf_blocks = dxf_blocks -> isChecked();
|
||||
export_properties.exported_area = export_border -> isChecked() ? QET::BorderArea : QET::ElementsArea;
|
||||
|
||||
return(export_properties);
|
||||
@@ -89,6 +90,7 @@ void ExportPropertiesWidget::setExportProperties(const ExportProperties &export_
|
||||
draw_terminal_names -> setChecked(export_properties.draw_terminal_names);
|
||||
draw_bg_transparent -> setChecked(export_properties.draw_bg_transparent);
|
||||
draw_colored_conductors -> setChecked(export_properties.draw_colored_conductors);
|
||||
dxf_blocks -> setChecked(export_properties.dxf_blocks);
|
||||
|
||||
if (export_properties.exported_area == QET::BorderArea) {
|
||||
export_border -> setChecked(true);
|
||||
@@ -219,6 +221,11 @@ void ExportPropertiesWidget::build()
|
||||
// use transparent background for SVG-Export
|
||||
draw_bg_transparent = new QCheckBox(tr("SVG: fond transparent"), groupbox_options);
|
||||
optionshlayout -> addWidget(draw_bg_transparent, 4, 0);
|
||||
|
||||
// each symbol as a DXF block (issue #1339)
|
||||
dxf_blocks = new QCheckBox(tr("DXF : symboles en blocs"), groupbox_options);
|
||||
dxf_blocks -> setToolTip(tr("Chaque symbole devient un bloc DXF, sélectionnable d'un clic dans un logiciel de CAO"));
|
||||
optionshlayout -> addWidget(dxf_blocks, 4, 1);
|
||||
|
||||
vboxLayout -> addWidget(groupbox_options);
|
||||
|
||||
@@ -234,6 +241,7 @@ void ExportPropertiesWidget::build()
|
||||
setTabOrder(draw_titleblock, draw_terminals);
|
||||
setTabOrder(draw_terminals, draw_colored_conductors);
|
||||
setTabOrder(draw_colored_conductors, draw_bg_transparent);
|
||||
setTabOrder(draw_bg_transparent, dxf_blocks);
|
||||
|
||||
// connexion du bouton permettant le choix du repertoire
|
||||
connect(button_browse, &QPushButton::released, this, &ExportPropertiesWidget::slot_chooseADirectory);
|
||||
@@ -249,6 +257,7 @@ void ExportPropertiesWidget::build()
|
||||
connect(draw_terminal_names, &QCheckBox::stateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
connect(draw_bg_transparent, &QCheckBox::stateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
connect(draw_colored_conductors, &QCheckBox::stateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
connect(dxf_blocks, &QCheckBox::stateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
#else
|
||||
connect(draw_grid, &QCheckBox::checkStateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
connect(draw_border, &QCheckBox::checkStateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
@@ -257,5 +266,6 @@ void ExportPropertiesWidget::build()
|
||||
connect(draw_terminal_names, &QCheckBox::checkStateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
connect(draw_bg_transparent, &QCheckBox::checkStateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
connect(draw_colored_conductors, &QCheckBox::checkStateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
connect(dxf_blocks, &QCheckBox::checkStateChanged, this, &ExportPropertiesWidget::optionChanged);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ class ExportPropertiesWidget : public QWidget {
|
||||
QCheckBox *draw_terminal_names;
|
||||
QCheckBox *draw_bg_transparent;
|
||||
QCheckBox *draw_colored_conductors;
|
||||
QCheckBox *dxf_blocks;
|
||||
QRadioButton *export_border;
|
||||
QRadioButton *export_elements;
|
||||
QButtonGroup *exported_content_choices;
|
||||
|
||||
@@ -473,6 +473,17 @@ target_link_libraries(tst_dxfcurves PRIVATE Qt::Test)
|
||||
target_compile_definitions(tst_dxfcurves PRIVATE
|
||||
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
|
||||
|
||||
# --export-dxf --dxf-blocks: a symbol placed twice is one BLOCK and two
|
||||
# INSERTs (issue #1339).
|
||||
add_executable(
|
||||
tst_dxfblocks
|
||||
tst_dxfblocks.cpp)
|
||||
add_test(NAME tst_dxfblocks COMMAND tst_dxfblocks)
|
||||
add_dependencies(tst_dxfblocks qelectrotech)
|
||||
target_link_libraries(tst_dxfblocks PRIVATE Qt::Test)
|
||||
target_compile_definitions(tst_dxfblocks PRIVATE
|
||||
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
|
||||
|
||||
# --export-pdf puts an A3 folio on an A3 page whichever way it is turned:
|
||||
# QPageSize matches standard sheets upright only, so a wide folio is matched
|
||||
# upright and turned. fixtures/pdf_page_a3.qet has one folio each way.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<project title="DXF symbol blocks" uuid="{7d2b8e3f-0c65-4e30-9079-3f0d0f0a7b10}" version="0.200.1">
|
||||
<properties>
|
||||
<property name="saveddate" show="1">10/2/26</property>
|
||||
<property name="saveddate-eu" show="1">02-10-2026</property>
|
||||
<property name="saveddate-us" show="1">2026-10-02</property>
|
||||
<property name="savedfilename" show="1">dxf_blocks</property>
|
||||
<property name="savedtime" show="1">18:39</property>
|
||||
</properties>
|
||||
<usage enabled="true" time_spent="0"/>
|
||||
<newdiagrams>
|
||||
<border cols="17" colsize="60" displaycols="true" displayrows="true" rows="8" rowsize="80"/>
|
||||
<inset author="" auto_page_num="" date="null" displayAt="bottom" filename="" folio="" indexrev="" locmach="" plant="" title="" version=""/>
|
||||
<conductors bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="0" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
|
||||
<report label="%f-%l%c"/>
|
||||
<xrefs>
|
||||
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="coil" xrefpos="AlignBottom"/>
|
||||
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="commutator" xrefpos="AlignBottom"/>
|
||||
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="plc" xrefpos="AlignBottom"/>
|
||||
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="protection" xrefpos="AlignBottom"/>
|
||||
</xrefs>
|
||||
<conductors_autonums auto_break_conductors="false" current_autonum="" freeze_new_conductors="false"/>
|
||||
<folio_autonums/>
|
||||
<element_autonums current_autonum="" freeze_new_elements="false"/>
|
||||
<guides/>
|
||||
</newdiagrams>
|
||||
<diagram author="" auto_page_num="" cols="17" colsize="60" date="null" displayAt="bottom" displaycols="true" displayrows="true" filename="" folio="" freezeNewConductor="false" freezeNewElement="false" height="660" indexrev="" locmach="" order="1" plant="" rows="8" rowsize="80" title="" uuid="{7d2b8e3f-0c65-4e30-9079-3f0d0f0a7a01}" version="0.200.1-dev">
|
||||
<defaultconductor bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="0" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
|
||||
<elements>
|
||||
<element freezeLabel="false" is_movable="1" orientation="0" prefix="" type="embed://import/curves.elmt" uuid="{7d2b8e3f-0c65-4e30-9079-3f0d0f0a7a02}" x="300" y="300" z="10">
|
||||
<terminals/>
|
||||
<inputs/>
|
||||
<dynamic_texts/>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
<element freezeLabel="false" is_movable="1" orientation="1" prefix="" type="embed://import/curves.elmt" uuid="{7d2b8e3f-0c65-4e30-9079-3f0d0f0a7a03}" x="500" y="300" z="10">
|
||||
<terminals/>
|
||||
<inputs/>
|
||||
<dynamic_texts/>
|
||||
<texts_groups/>
|
||||
</element>
|
||||
</elements>
|
||||
</diagram>
|
||||
<collection>
|
||||
<category name="import">
|
||||
<names>
|
||||
<name lang="en">Imported elements</name>
|
||||
</names>
|
||||
<element name="curves.elmt">
|
||||
<definition height="80" hotspot_x="10" hotspot_y="10" link_type="simple" type="element" version="0.100.0" width="120">
|
||||
<uuid uuid="{7d2b8e3f-0c65-4e30-9079-3f0d0f0a7a05}"/>
|
||||
<names>
|
||||
<name lang="en">Circle and arc</name>
|
||||
</names>
|
||||
<description>
|
||||
<ellipse antialias="true" style="line-style:normal;line-weight:normal;filling:none;color:black" x="0" y="0" width="20" height="20"/>
|
||||
<arc antialias="true" style="line-style:normal;line-weight:normal;filling:none;color:black" x="40" y="0" width="20" height="20" start="30" angle="120"/>
|
||||
</description>
|
||||
</definition>
|
||||
</element>
|
||||
</category>
|
||||
</collection>
|
||||
</project>
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <QtTest>
|
||||
#include <QProcess>
|
||||
#include <QTemporaryDir>
|
||||
|
||||
/**
|
||||
--export-dxf --dxf-blocks (issue #1339): a symbol placed twice is one
|
||||
BLOCK and two INSERTs, the second turned a quarter; without the switch
|
||||
there is neither.
|
||||
*/
|
||||
class tst_dxfblocks : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/// The group code / value pairs of the exported folio
|
||||
static QList<QPair<QString, QString>> exportPairs(const QStringList &extra)
|
||||
{
|
||||
const QString project = QFINDTESTDATA("fixtures/dxf_blocks.qet");
|
||||
QTemporaryDir dir;
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen"));
|
||||
QProcess proc;
|
||||
proc.setProcessEnvironment(env);
|
||||
proc.start(QStringLiteral(QET_TEST_BINARY_PATH),
|
||||
QStringList{QStringLiteral("--export-dxf"), project, dir.path()} + extra);
|
||||
if (!proc.waitForFinished(60000) || proc.exitCode() != 0)
|
||||
return {};
|
||||
QFile file(dir.filePath(QStringLiteral("01_diagram.dxf")));
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return {};
|
||||
const QStringList values = QString::fromUtf8(file.readAll()).split(QLatin1Char('\n'));
|
||||
QList<QPair<QString, QString>> pairs;
|
||||
for (int i = 0 ; i + 1 < values.size() ; i += 2)
|
||||
pairs << qMakePair(values.at(i).trimmed(), values.at(i + 1).trimmed());
|
||||
return pairs;
|
||||
}
|
||||
|
||||
/// The values of code @a code in each entity of type @a type
|
||||
static QStringList values(const QList<QPair<QString, QString>> &pairs,
|
||||
const QString &type, const QString &code)
|
||||
{
|
||||
QStringList found;
|
||||
for (int i = 0 ; i < pairs.size() ; ++i) {
|
||||
if (pairs.at(i).first != QLatin1String("0") || pairs.at(i).second != type)
|
||||
continue;
|
||||
for (int j = i + 1 ; j < pairs.size() && pairs.at(j).first != QLatin1String("0") ; ++j)
|
||||
if (pairs.at(j).first == code)
|
||||
found << pairs.at(j).second;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void blocks()
|
||||
{
|
||||
const auto pairs = exportPairs({QStringLiteral("--dxf-blocks")});
|
||||
QVERIFY2(!pairs.isEmpty(), "--export-dxf --dxf-blocks failed");
|
||||
|
||||
QCOMPARE(values(pairs, QStringLiteral("BLOCK"), QStringLiteral("2")),
|
||||
QStringList{QStringLiteral("QET_CURVES")});
|
||||
QCOMPARE(values(pairs, QStringLiteral("INSERT"), QStringLiteral("2")),
|
||||
(QStringList{QStringLiteral("QET_CURVES"), QStringLiteral("QET_CURVES")}));
|
||||
QCOMPARE(values(pairs, QStringLiteral("INSERT"), QStringLiteral("50")),
|
||||
(QStringList{QStringLiteral("0"), QStringLiteral("270")}));
|
||||
//The circle is drawn once, inside the block
|
||||
QCOMPARE(values(pairs, QStringLiteral("CIRCLE"), QStringLiteral("8")).size(), 1);
|
||||
}
|
||||
|
||||
void flatWithoutSwitch()
|
||||
{
|
||||
const auto pairs = exportPairs({});
|
||||
QVERIFY2(!pairs.isEmpty(), "--export-dxf failed");
|
||||
QVERIFY(values(pairs, QStringLiteral("BLOCK"), QStringLiteral("2")).isEmpty());
|
||||
QVERIFY(values(pairs, QStringLiteral("INSERT"), QStringLiteral("2")).isEmpty());
|
||||
QCOMPARE(values(pairs, QStringLiteral("CIRCLE"), QStringLiteral("8")).size(), 2);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_dxfblocks)
|
||||
#include "tst_dxfblocks.moc"
|
||||
Reference in New Issue
Block a user