From 83f72c95c6d2740397a6ffa16565de82d803e956 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Wed, 7 Oct 2026 08:13:52 +1300 Subject: [PATCH] Fix DXF export of circles, arcs and the title block at the right (#1339) Circles and arcs: drawArcEllipse() split each curve into quarters and fitted a circular ARC through a point half way between the curve and its chord, so every circle came out as a flattened diamond. A circle or an arc of one is now one exact CIRCLE or ARC. R10 has no ELLIPSE entity, so a true ellipse is a polyline through the curve, one point every 5 degrees. The export also used a different scale on each axis, which made round things oval; it now uses one, the largest that fits the sheet. Title block at the right: the DXF laid the horizontal template out in the narrow vertical strip, squashing it into the top corner. It is now laid out horizontally and turned a quarter, as draw() turns the painter. Co-Authored-By: Claude Opus 5.5 --- sources/bordertitleblock.cpp | 21 ++- sources/createdxf.cpp | 210 ++++++++++--------------- sources/createdxf.h | 14 ++ sources/dxfexport.cpp | 9 +- sources/titleblocktemplate.cpp | 45 ++++-- sources/titleblocktemplate.h | 6 +- sources/titleblocktemplaterenderer.cpp | 7 +- sources/titleblocktemplaterenderer.h | 4 +- tests/qttest/CMakeLists.txt | 11 ++ tests/qttest/fixtures/dxf_curves.qet | 56 +++++++ tests/qttest/tst_dxfcurves.cpp | 95 +++++++++++ 11 files changed, 325 insertions(+), 153 deletions(-) create mode 100644 tests/qttest/fixtures/dxf_curves.qet create mode 100644 tests/qttest/tst_dxfcurves.cpp diff --git a/sources/bordertitleblock.cpp b/sources/bordertitleblock.cpp index f63877eb4..6ab3e0171 100644 --- a/sources/bordertitleblock.cpp +++ b/sources/bordertitleblock.cpp @@ -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 diff --git a/sources/createdxf.cpp b/sources/createdxf.cpp index 5135274ee..bf24c1add 100644 --- a/sources/createdxf.cpp +++ b/sources/createdxf.cpp @@ -22,6 +22,9 @@ #include #include "dxfexport.h" +#include +#include + 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 > 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 newPart(start,span); - arc_parts_vector.push_back(newPart); - start = i; - } - } - if (start != i) { - span = i - start; - QPair 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 newPart(start,span); - arc_parts_vector.push_back(newPart); - start = i; - } - } - if (start != i) { - span = i - start; - QPair 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 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 } diff --git a/sources/createdxf.h b/sources/createdxf.h index 5fb042e82..5e4a18d23 100644 --- a/sources/createdxf.h +++ b/sources/createdxf.h @@ -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, diff --git a/sources/dxfexport.cpp b/sources/dxfexport.cpp index 6db86c5b4..3e587660c 100644 --- a/sources/dxfexport.cpp +++ b/sources/dxfexport.cpp @@ -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()); diff --git a/sources/titleblocktemplate.cpp b/sources/titleblocktemplate.cpp index 69214702e..f3b488592 100644 --- a/sources/titleblocktemplate.cpp +++ b/sources/titleblocktemplate.cpp @@ -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 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); } diff --git a/sources/titleblocktemplate.h b/sources/titleblocktemplate.h index 8bc1821d6..55f918352 100644 --- a/sources/titleblocktemplate.h +++ b/sources/titleblocktemplate.h @@ -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: diff --git a/sources/titleblocktemplaterenderer.cpp b/sources/titleblocktemplaterenderer.cpp index d41508829..93233db3f 100644 --- a/sources/titleblocktemplaterenderer.cpp +++ b/sources/titleblocktemplaterenderer.cpp @@ -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); } diff --git a/sources/titleblocktemplaterenderer.h b/sources/titleblocktemplaterenderer.h index b332d4cf4..4602bc640 100644 --- a/sources/titleblocktemplaterenderer.h +++ b/sources/titleblocktemplaterenderer.h @@ -18,6 +18,7 @@ #ifndef TITLEBLOCK_TEMPLATE_RENDERER_H #define TITLEBLOCK_TEMPLATE_RENDERER_H #include +#include #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; diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt index b03046a5a..dd8244a93 100644 --- a/tests/qttest/CMakeLists.txt +++ b/tests/qttest/CMakeLists.txt @@ -462,6 +462,17 @@ target_link_libraries(tst_dxfwrappedtext PRIVATE Qt::Test) target_compile_definitions(tst_dxfwrappedtext PRIVATE "QET_TEST_BINARY_PATH=\"$\"") +# --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=\"$\"") + # --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. diff --git a/tests/qttest/fixtures/dxf_curves.qet b/tests/qttest/fixtures/dxf_curves.qet new file mode 100644 index 000000000..d6033b5d6 --- /dev/null +++ b/tests/qttest/fixtures/dxf_curves.qet @@ -0,0 +1,56 @@ + + + 10/2/26 + 02-10-2026 + 2026-10-02 + dxf_curves + 18:39 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Imported elements + + + + + + Circle and arc + + + + + + + + + + diff --git a/tests/qttest/tst_dxfcurves.cpp b/tests/qttest/tst_dxfcurves.cpp new file mode 100644 index 000000000..c5f558077 --- /dev/null +++ b/tests/qttest/tst_dxfcurves.cpp @@ -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 . +*/ +#include +#include +#include + +/** + --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> entities(const QStringList &values, + const QString &type, + const QString &layer) + { + QList> 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 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"