Merge pull request #1350 from ispyisail/fix/1339-dxf

Fix DXF export of circles, arcs and right-side title blocks (#1339)
This commit is contained in:
Laurent Trinques
2026-10-07 06:31:57 +02:00
committed by GitHub
11 changed files with 325 additions and 153 deletions
+17 -4
View File
@@ -708,13 +708,26 @@ void BorderTitleBlock::drawDxf(
// render the titleblock, using the TitleBlockTemplate object
if (display_titleblock_) {
Createdxf::layer = DxfExport::Layer::TitleBlock;
//qp -> translate(titleblock_rect_.topLeft());
QRectF rect = titleBlockRect();
//Laid out horizontally, then turned like the QPainter in
//draw(): a quarter turn counter-clockwise around its top
//left, which for a title block at the right is the bottom
//right of the diagram (issue #1339).
QRectF rect = titleBlockRectForQPainter();
QTransform dxf_transform;
if (m_edge != Qt::BottomEdge)
{
const QPointF pivot(rect.left() * Createdxf::xScale,
Createdxf::sheetHeight
- rect.top() * Createdxf::yScale);
dxf_transform.translate(pivot.x(), pivot.y());
dxf_transform.rotate(90);
dxf_transform.translate(-pivot.x(), -pivot.y());
}
m_titleblock_template_renderer -> renderDxf(rect,
rect.width(),
file_path,
color);
//qp -> translate(-titleblock_rect_.topLeft());
color,
dxf_transform);
}
// Transform back to QET scale
+82 -128
View File
@@ -22,6 +22,9 @@
#include <QString>
#include "dxfexport.h"
#include <QtMath>
#include <cmath>
const double Createdxf::sheetWidth = 4000;
const double Createdxf::sheetHeight = 2700;
@@ -504,6 +507,24 @@ int Createdxf::dxfColor(QPen pen) {
return Createdxf::dxfColor(pen.color());
}
/**
@brief Createdxf::drawArcEllipse
Draw an arc of an ellipse, or a whole ellipse, in DXF units.
@param x, y : top left of the ellipse's bounding rect (y is the top, the
DXF Y axis going up)
@param w, h : width and height of that rect
@param startAngle, spanAngle : in degrees, as QPainter::drawArc() takes
them: counter-clockwise from 3 o'clock
@param hotspot_x, hotspot_y, rotation_angle : the whole shape is turned
clockwise by rotation_angle degrees around the hotspot, as a rotated
symbol is
A circle, or an arc of one, is written as one exact CIRCLE or ARC. R10,
the version this file declares, has no ELLIPSE entity, so a true
ellipse is written as a polyline through points of the curve, one every
5 degrees. It used to be four ARCs fitted through a point between the
curve and its chord, which drew every circle as a flattened diamond
(issue #1339).
*/
void Createdxf::drawArcEllipse(
const QString &file_path,
qreal x,
@@ -517,138 +538,46 @@ void Createdxf::drawArcEllipse(
qreal rotation_angle,
const int &colorcode)
{
// vector of parts of arc (stored as a pair of startAngle and spanAngle) for each quadrant.
QVector< QPair<qreal,qreal> > arc_parts_vector;
if (qFuzzyIsNull(spanAngle) || w <= 0 || h <= 0)
return;
if (spanAngle > 0) {
qreal start = startAngle;
qreal span;
int i;
for ( i = startAngle; i < startAngle+spanAngle; i++ ) {
int absolute_theta = (i > 0) ? i : -i;
if (absolute_theta == 0 || absolute_theta == 90 ||
absolute_theta == 180 || absolute_theta == 270 ||
absolute_theta == 360) {
span = i - start;
QPair<qreal, qreal> newPart(start,span);
arc_parts_vector.push_back(newPart);
start = i;
}
}
if (start != i) {
span = i - start;
QPair<qreal, qreal> newPart(start,span);
arc_parts_vector.push_back(newPart);
}
} else {
qreal start = startAngle;
qreal span;
int i;
for ( i = startAngle; i > startAngle+spanAngle; i-- ) {
int absolute_theta = (i > 0) ? i : -i;
if (absolute_theta == 0 || absolute_theta == 90 ||
absolute_theta == 180 || absolute_theta == 270 ||
absolute_theta == 360) {
span = i - start;
QPair<qreal, qreal> newPart(start,span);
arc_parts_vector.push_back(newPart);
start = i;
}
}
if (start != i) {
span = i - start;
QPair<qreal, qreal> newPart(start,span);
arc_parts_vector.push_back(newPart);
const qreal a = w/2;
const qreal b = h/2;
const QPointF center = DxfExport::rotation_transformed(
x + a, y - b, hotspot_x, hotspot_y, rotation_angle);
const bool full_turn = qAbs(spanAngle) >= 360;
if (qAbs(a - b) <= 1e-6 * qMax(a, b))
{
if (full_turn) {
drawCircle(file_path, a, center.x(), center.y(), colorcode);
return;
}
//A DXF ARC always runs counter-clockwise from 50 to 51.
qreal start = startAngle - rotation_angle;
if (spanAngle < 0)
start += spanAngle;
start = std::fmod(start, 360.0);
if (start < 0)
start += 360;
drawArc(file_path, center.x(), center.y(), a,
start, start + qAbs(spanAngle), colorcode);
return;
}
for (int i = 0; i < arc_parts_vector.size(); i++) {
QPair<qreal,qreal> arc = arc_parts_vector[i];
if (arc.second == 0)
continue;
qreal arc_startAngle = arc.first * 3.142/180;
qreal arc_spanAngle = arc.second * 3.142/180;
qreal a = w/2;
qreal b = h/2;
qreal x1 = x + w/2 + a*cos(arc_startAngle);
qreal y1 = y - h/2 + b*sin(arc_startAngle);
qreal x2 = x + w/2 + a*cos(arc_startAngle + arc_spanAngle);
qreal y2 = y - h/2 + b*sin(arc_startAngle + arc_spanAngle);
qreal mid_ellipse_x = x + w/2 + a*cos(arc_startAngle + arc_spanAngle/2);
qreal mid_ellipse_y = y - h/2 + b*sin(arc_startAngle + arc_spanAngle/2);
qreal mid_line_x = (x1+x2)/2;
qreal mid_line_y = (y1+y2)/2;
qreal x3 = (mid_ellipse_x + mid_line_x)/2;
qreal y3 = (mid_ellipse_y + mid_line_y)/2;
// find circumcenter of points (x1,y1), (x3,y3) and (x2,y2)
qreal a1 = 2*x2 - 2*x1;
qreal b1 = 2*y2 - 2*y1;
qreal c1 = x1*x1 + y1*y1 - x2*x2 - y2*y2;
qreal a2 = 2*x3 - 2*x1;
qreal b2 = 2*y3 - 2*y1;
qreal c2 = x1*x1 + y1*y1 - x3*x3 - y3*y3;
qreal center_x = (b1*c2 - b2*c1) / (a1*b2 - a2*b1);
qreal center_y = (a1*c2 - a2*c1) / (b1*a2 - b2*a1);
qreal radius = sqrt( (x1-center_x)*(x1-center_x) + (y1-center_y)*(y1-center_y) );
if ( x1 > center_x && y1 > center_y )
arc_startAngle = asin( (y1 - center_y) / radius );
else if ( x1 > center_x && y1 < center_y )
arc_startAngle = 3.142*2 - asin( (center_y - y1) / radius );
else if ( x1 < center_x && y1 < center_y )
arc_startAngle = 3.142 + asin( (center_y - y1) / radius );
else
arc_startAngle = 3.142 - asin( (y1 - center_y) / radius );
qreal arc_endAngle;
if ( x2 > center_x && y2 > center_y )
arc_endAngle = asin( (y2 - center_y) / radius );
else if ( x2 > center_x && y2 < center_y )
arc_endAngle = 3.142*2 - asin( (center_y - y2) / radius );
else if ( x2 < center_x && y2 < center_y )
arc_endAngle = 3.142 + asin( (center_y - y2) / radius );
else
arc_endAngle = 3.142 - asin( (y2 - center_y) / radius );
if (arc_endAngle < arc_startAngle) {
qreal temp = arc_startAngle;
arc_startAngle = arc_endAngle;
arc_endAngle = temp;
}
QPointF transformed_point = DxfExport::rotation_transformed(
center_x,
center_y,
hotspot_x,
hotspot_y,
rotation_angle);
center_x = transformed_point.x();
center_y = transformed_point.y();
arc_endAngle *= 180/3.142;
arc_startAngle *= 180/3.142;
arc_endAngle -= rotation_angle;
arc_startAngle -= rotation_angle;
drawArc(
file_path,
center_x,
center_y,
radius,
arc_startAngle,
arc_endAngle,
colorcode);
const qreal span = full_turn ? 360 : spanAngle;
const int steps = qMax(2, qCeil(qAbs(span) / 5));
QPolygonF poly;
poly.reserve(steps + 1);
for (int i = 0 ; i <= steps ; ++i)
{
const qreal theta = qDegreesToRadians(startAngle + span * i / steps);
poly << DxfExport::rotation_transformed(
x + a + a*std::cos(theta),
y - b + b*std::sin(theta),
hotspot_x, hotspot_y, rotation_angle);
}
drawPolyline(file_path, poly, colorcode, true);
}
@@ -809,6 +738,31 @@ void Createdxf::drawTextAligned(
double xAlign,
double xScaleW,
int colour)
{
drawTextAligned(fileName, text, x, y, height, rotation, oblique,
hAlign, vAlign, xAlign, y, xScaleW, colour);
}
/**
@brief Createdxf::drawTextAligned
As above, with the second alignment point given in full (@a xAlign,
@a yAlign) instead of on the same horizontal line as the insertion
point, which is what a rotated aligned text needs.
*/
void Createdxf::drawTextAligned(
const QString& fileName,
const QString& text,
double x,
double y,
double height,
double rotation,
double oblique,
int hAlign,
int vAlign,
double xAlign,
double yAlign,
double xScaleW,
int colour)
{
if (!fileName.isEmpty()) {
QFile file(fileName);
@@ -869,7 +823,7 @@ void Createdxf::drawTextAligned(
To_Dxf << 11 << "\r\n"; // XYZ
To_Dxf << xAlign << "\r\n"; // X in UCS (User Coordinate System)coordinates
To_Dxf << 21 << "\r\n";
To_Dxf << y << "\r\n"; // Y in UCS (User Coordinate System)coordinates
To_Dxf << yAlign << "\r\n"; // Y in UCS (User Coordinate System)coordinates
To_Dxf << 31 << "\r\n";
To_Dxf << 0.0 << "\r\n"; // Z in UCS (User Coordinate System)coordinates
}
+14
View File
@@ -141,6 +141,20 @@ class Createdxf
double xAlign,
double xScale,
int colour);
static void drawTextAligned(
const QString& fileName,
const QString& text,
double x,
double y,
double height,
double rotation,
double oblique,
int hAlign,
int vAlign,
double xAlign,
double yAlign,
double xScale,
int colour);
static void drawPolyline(
const QString &filepath,
+7 -2
View File
@@ -80,8 +80,13 @@ void DxfExport::write(Diagram *diagram, int width, int height,
width -= 2*Diagram::margin;
height -= 2*Diagram::margin;
Createdxf::xScale = Createdxf::sheetWidth / double(width);
Createdxf::yScale = Createdxf::sheetHeight / double(height);
//One scale for both axes, the largest that fits the sheet: two
//scales stretched the drawing and turned every circle into an oval
//(issue #1339).
const double scale = qMin(Createdxf::sheetWidth / double(width),
Createdxf::sheetHeight / double(height));
Createdxf::xScale = scale;
Createdxf::yScale = scale;
Createdxf::dxfBegin(file_path, Layer::all());
+31 -14
View File
@@ -1646,12 +1646,16 @@ void TitleBlockTemplate::render(QPainter &painter,
Width of the titleblock to render
@param file_path :
@param color :
@param dxf_transform :
Applied to every DXF point after the title block is laid out, as the
QPainter is rotated for a title block at the right of the folio
*/
void TitleBlockTemplate::renderDxf(QRectF &title_block_rect,
const DiagramContext &diagram_context,
int titleblock_width,
QString &file_path,
int color) const
int color,
const QTransform &dxf_transform) const
{
QList<int> widths = columnsWidth(titleblock_width);
@@ -1663,12 +1667,13 @@ void TitleBlockTemplate::renderDxf(QRectF &title_block_rect,
*Createdxf::yScale;
double recWidth = title_block_rect.width() * Createdxf::xScale;
double recHeight = title_block_rect.height() * Createdxf::yScale;
Createdxf::drawRectangle(file_path,
xCoord,
yCoord,
recWidth,
recHeight,
color);
Createdxf::drawPolyline(file_path,
dxf_transform.map(QPolygonF(QRectF(xCoord,
yCoord,
recWidth,
recHeight))),
color,
true);
// run through each individual cell
for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
@@ -1702,7 +1707,10 @@ void TitleBlockTemplate::renderDxf(QRectF &title_block_rect,
y = yCoord + recHeight - h - y*Createdxf::yScale;
w *= Createdxf::xScale;
Createdxf::drawRectangle(file_path, x, y, w, h, color);
Createdxf::drawPolyline(file_path,
dxf_transform.map(QPolygonF(QRectF(x, y, w, h))),
color,
true);
if (cells_[i][j] -> type() == TitleBlockCell::TextCell)
{
QString final_text =
@@ -1715,7 +1723,8 @@ void TitleBlockTemplate::renderDxf(QRectF &title_block_rect,
y,
w,
h,
color);
color,
dxf_transform);
}
}
}
@@ -1967,6 +1976,7 @@ void TitleBlockTemplate::renderTextCell(QPainter &painter,
@param w
@param h
@param color
@param dxf_transform : see renderDxf()
*/
void TitleBlockTemplate::renderTextCellDxf(
QString &file_path,
@@ -1976,7 +1986,8 @@ void TitleBlockTemplate::renderTextCellDxf(
qreal y,
qreal w,
qreal h,
int color) const
int color,
const QTransform &dxf_transform) const
{
if (text.isEmpty()) return;
QFont text_font = TitleBlockTemplate::fontForCell(cell);
@@ -2038,6 +2049,8 @@ void TitleBlockTemplate::renderTextCellDxf(
const QStringList lines = text.split(QRegularExpression(QStringLiteral("\r\n|\r|\n")));
const qreal line_spacing = textHeight * Createdxf::yScale * 1.6;
const int last = lines.size() - 1;
const qreal rotation = qRadiansToDegrees(
qAtan2(dxf_transform.m12(), dxf_transform.m11()));
for (int i = 0 ; i < lines.size() ; ++i)
{
const QString &line = lines.at(i);
@@ -2064,17 +2077,21 @@ void TitleBlockTemplate::renderTextCellDxf(
}
// x offset value below currently set heuristically based on appearance...
const QPointF insert = dxf_transform.map(
QPointF(x - 2*Createdxf::xScale, y1 + offset));
const QPointF align = dxf_transform.map(QPointF(x2, y1 + offset));
Createdxf::drawTextAligned(
file_path,
line,
x - 2*Createdxf::xScale,
y1 + offset,
insert.x(),
insert.y(),
textHeight*Createdxf::yScale,
0,
rotation,
0,
hAlign,
vAlign,
x2,
align.x(),
align.y(),
ratio,
color);
}
+4 -2
View File
@@ -176,7 +176,8 @@ class TitleBlockTemplate : public QObject {
const DiagramContext &,
int,
QString &,
int) const;
int,
const QTransform & = QTransform()) const;
void renderCell(QPainter &,
const TitleBlockCell &,
const DiagramContext &,
@@ -245,7 +246,8 @@ class TitleBlockTemplate : public QObject {
qreal,
qreal,
qreal,
int) const;
int,
const QTransform &) const;
// attributes
private:
+5 -2
View File
@@ -91,15 +91,18 @@ void TitleBlockTemplateRenderer::render(QPainter *provided_painter,
@param titleblock_width
@param file_path
@param color
@param dxf_transform : see TitleBlockTemplate::renderDxf()
*/
void TitleBlockTemplateRenderer::renderDxf(QRectF &title_block_rect,
int titleblock_width,
QString &file_path,
int color) {
int color,
const QTransform &dxf_transform) {
if (!m_titleblock_template) return;
m_titleblock_template -> renderDxf(title_block_rect,
m_context,
titleblock_width,
file_path, color);
file_path, color,
dxf_transform);
}
+3 -1
View File
@@ -18,6 +18,7 @@
#ifndef TITLEBLOCK_TEMPLATE_RENDERER_H
#define TITLEBLOCK_TEMPLATE_RENDERER_H
#include <QPicture>
#include <QTransform>
#include "diagramcontext.h"
class TitleBlockTemplate;
@@ -40,7 +41,8 @@ class TitleBlockTemplateRenderer : public QObject
int height() const;
void render(QPainter *, int);
void renderDxf(QRectF &, int, QString &, int);
void renderDxf(QRectF &, int, QString &, int,
const QTransform & = QTransform());
private:
const TitleBlockTemplate *m_titleblock_template;
+11
View File
@@ -478,6 +478,17 @@ target_link_libraries(tst_dxfwrappedtext PRIVATE Qt::Test)
target_compile_definitions(tst_dxfwrappedtext PRIVATE
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
# --export-dxf on a folio with its title block at the right (issue #1339):
# a circle and an arc stay one CIRCLE and one ARC, the title block is turned.
add_executable(
tst_dxfcurves
tst_dxfcurves.cpp)
add_test(NAME tst_dxfcurves COMMAND tst_dxfcurves)
add_dependencies(tst_dxfcurves qelectrotech)
target_link_libraries(tst_dxfcurves PRIVATE Qt::Test)
target_compile_definitions(tst_dxfcurves 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.
+56
View File
@@ -0,0 +1,56 @@
<project title="DXF curves and title block" uuid="{6c1a7d2e-9b54-4d2f-8f68-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_curves</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="right" displaycols="true" displayrows="true" filename="" folio="" freezeNewConductor="false" freezeNewElement="false" height="660" indexrev="" locmach="" order="1" plant="" rows="8" rowsize="80" title="" uuid="{6c1a7d2e-9b54-4d2f-8f68-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="{6c1a7d2e-9b54-4d2f-8f68-3f0d0f0a7a02}" x="300" 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="{6c1a7d2e-9b54-4d2f-8f68-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>
+95
View File
@@ -0,0 +1,95 @@
/*
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 on a folio whose title block is at the right (issue #1339):
a symbol's circle is one CIRCLE and its arc one ARC with the symbol's own
angles, which needs the same scale on both axes; the title block is
turned a quarter, as it is on screen.
*/
class tst_dxfcurves : public QObject
{
Q_OBJECT
/// The entities on @a layer, each as its group codes and values.
static QList<QMultiHash<int, QString>> entities(const QStringList &values,
const QString &type,
const QString &layer)
{
QList<QMultiHash<int, QString>> found;
for (int i = 0 ; i + 1 < values.size() ; i += 2)
{
if (values.at(i).trimmed() != QLatin1String("0")
|| values.at(i + 1).trimmed() != type)
continue;
QMultiHash<int, QString> entity;
for (int j = i + 2 ; j + 1 < values.size()
&& values.at(j).trimmed() != QLatin1String("0") ; j += 2)
entity.insert(values.at(j).trimmed().toInt(), values.at(j + 1).trimmed());
if (entity.value(8) == layer)
found << entity;
}
return found;
}
private slots:
void curvesAndTitleBlock()
{
const QString project = QFINDTESTDATA("fixtures/dxf_curves.qet");
QVERIFY2(!project.isEmpty(), "fixture project not found");
QTemporaryDir dir;
QVERIFY(dir.isValid());
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen"));
QProcess proc;
proc.setProcessEnvironment(env);
proc.start(QStringLiteral(QET_TEST_BINARY_PATH), {QStringLiteral("--export-dxf"), project, dir.path()});
QVERIFY2(proc.waitForFinished(60000), "--export-dxf timed out");
QCOMPARE(proc.exitCode(), 0);
QFile file(dir.filePath(QStringLiteral("01_diagram.dxf")));
QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
const QStringList values = QString::fromUtf8(file.readAll()).split(QLatin1Char('\n'));
const QString symbols = QStringLiteral("QET_SYMBOLS");
//The 20 px circle: one CIRCLE, nothing approximated
const auto circles = entities(values, QStringLiteral("CIRCLE"), symbols);
QCOMPARE(circles.size(), 1);
QVERIFY(entities(values, QStringLiteral("POLYLINE"), symbols).isEmpty());
//The arc from 30 to 150 degrees, same radius as the circle
const auto arcs = entities(values, QStringLiteral("ARC"), symbols);
QCOMPARE(arcs.size(), 1);
QCOMPARE(arcs.first().value(50).toDouble(), 30.0);
QCOMPARE(arcs.first().value(51).toDouble(), 150.0);
QCOMPARE(arcs.first().value(40).toDouble(), circles.first().value(40).toDouble());
//Every title block text turned a quarter, as drawn on screen
const auto texts = entities(values, QStringLiteral("TEXT"), QStringLiteral("QET_TITLEBLOCK"));
QVERIFY(!texts.isEmpty());
for (const auto &text : texts)
QCOMPARE(text.value(50).toDouble(), 90.0);
}
};
QTEST_APPLESS_MAIN(tst_dxfcurves)
#include "tst_dxfcurves.moc"