2017-07-16 20:10:48 +02:00
|
|
|
/************************************************************************
|
2015-09-07 21:47:02 +02:00
|
|
|
**
|
|
|
|
** @file vdxfengine.cpp
|
|
|
|
** @author Valentina Zhuravska <zhuravska19(at)gmail.com>
|
|
|
|
** @date 12 8, 2015
|
|
|
|
**
|
|
|
|
** @brief
|
|
|
|
** @copyright
|
2017-10-05 11:20:01 +02:00
|
|
|
** This source code is part of the Valentina project, a pattern making
|
2015-09-07 21:47:02 +02:00
|
|
|
** program, whose allow create and modeling patterns of clothing.
|
|
|
|
** Copyright (C) 2013-2015 Valentina project
|
2020-01-31 07:00:05 +01:00
|
|
|
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
|
2015-09-07 21:47:02 +02:00
|
|
|
**
|
|
|
|
** Valentina 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 3 of the License, or
|
|
|
|
** (at your option) any later version.
|
|
|
|
**
|
|
|
|
** Valentina 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 Valentina. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
**
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
#include "vdxfengine.h"
|
2016-08-08 13:44:49 +02:00
|
|
|
|
|
|
|
#include <QByteArray>
|
|
|
|
#include <QColor>
|
2015-09-07 21:47:02 +02:00
|
|
|
#include <QDateTime>
|
2016-08-08 13:44:49 +02:00
|
|
|
#include <QFlag>
|
|
|
|
#include <QFlags>
|
|
|
|
#include <QFont>
|
|
|
|
#include <QLineF>
|
|
|
|
#include <QList>
|
|
|
|
#include <QMessageLogger>
|
|
|
|
#include <QPaintEngineState>
|
|
|
|
#include <QPainterPath>
|
|
|
|
#include <QPen>
|
|
|
|
#include <QPolygonF>
|
2018-07-16 19:00:42 +02:00
|
|
|
#include <QTextCodec>
|
2016-08-08 13:44:49 +02:00
|
|
|
#include <QTextItem>
|
|
|
|
#include <Qt>
|
|
|
|
#include <QtDebug>
|
|
|
|
|
|
|
|
#include "../vmisc/def.h"
|
2022-08-22 10:34:02 +02:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
|
2016-08-08 13:44:49 +02:00
|
|
|
#include "../vmisc/diagnostic.h"
|
2022-08-22 10:34:02 +02:00
|
|
|
#endif // QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
|
2016-08-16 18:57:32 +02:00
|
|
|
#include "../vmisc/vmath.h"
|
2017-06-21 11:34:20 +02:00
|
|
|
#include "dxiface.h"
|
2017-07-16 20:10:48 +02:00
|
|
|
#include "../vlayout/vlayoutpiece.h"
|
2019-07-22 16:06:30 +02:00
|
|
|
#include "../vgeometry/vgeometrydef.h"
|
2017-07-16 20:10:48 +02:00
|
|
|
|
|
|
|
static const qreal AAMATextHeight = 2.5;
|
2016-08-08 13:44:49 +02:00
|
|
|
|
2020-03-15 12:35:31 +01:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
QVector<QPointF> PieceOutline(const VLayoutPiece &detail)
|
|
|
|
{
|
|
|
|
QVector<QPointF> outline;
|
|
|
|
if (detail.IsSeamAllowance() && not detail.IsSeamAllowanceBuiltIn())
|
|
|
|
{
|
|
|
|
outline = detail.GetMappedSeamAllowancePoints();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outline = detail.GetMappedContourPoints();
|
|
|
|
}
|
|
|
|
return outline;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-07 21:47:02 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
static inline QPaintEngine::PaintEngineFeatures svgEngineFeatures()
|
|
|
|
{
|
2016-08-06 20:42:40 +02:00
|
|
|
QT_WARNING_PUSH
|
|
|
|
QT_WARNING_DISABLE_CLANG("-Wsign-conversion")
|
|
|
|
QT_WARNING_DISABLE_INTEL(68)
|
2015-09-07 21:47:02 +02:00
|
|
|
|
|
|
|
return QPaintEngine::PaintEngineFeatures(
|
|
|
|
QPaintEngine::AllFeatures
|
|
|
|
& ~QPaintEngine::PatternBrush
|
|
|
|
& ~QPaintEngine::PerspectiveTransform
|
|
|
|
& ~QPaintEngine::ConicalGradientFill
|
|
|
|
& ~QPaintEngine::PorterDuff);
|
|
|
|
|
2016-08-06 20:42:40 +02:00
|
|
|
QT_WARNING_POP
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
VDxfEngine::VDxfEngine()
|
|
|
|
:QPaintEngine(svgEngineFeatures()),
|
2015-10-02 07:37:31 +02:00
|
|
|
size(),
|
|
|
|
resolution(static_cast<int>(PrintDPI)),
|
|
|
|
fileName(),
|
2017-06-21 11:34:20 +02:00
|
|
|
m_version(DRW::AC1014),
|
2017-06-26 16:28:41 +02:00
|
|
|
m_binary(false),
|
2015-10-02 07:37:31 +02:00
|
|
|
matrix(),
|
2017-06-21 11:34:20 +02:00
|
|
|
input(),
|
2015-10-02 07:37:31 +02:00
|
|
|
varMeasurement(VarMeasurement::Metric),
|
2017-08-10 15:50:10 +02:00
|
|
|
varInsunits(VarInsunits::Millimeters),
|
2017-06-29 17:56:52 +02:00
|
|
|
textBuffer(new DRW_Text())
|
2015-09-07 21:47:02 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-06-29 17:56:52 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
VDxfEngine::~VDxfEngine()
|
|
|
|
{
|
|
|
|
delete textBuffer;
|
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2015-09-07 21:47:02 +02:00
|
|
|
bool VDxfEngine::begin(QPaintDevice *pdev)
|
|
|
|
{
|
|
|
|
Q_UNUSED(pdev)
|
2017-07-16 20:10:48 +02:00
|
|
|
|
|
|
|
if (isActive())
|
|
|
|
{
|
|
|
|
qWarning("VDxfEngine::begin(), the engine was alredy activated");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-07 21:47:02 +02:00
|
|
|
if (size.isValid() == false)
|
|
|
|
{
|
|
|
|
qWarning()<<"VDxfEngine::begin(), size is not valid";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-07-16 19:00:42 +02:00
|
|
|
input = QSharedPointer<dx_iface>(new dx_iface(getFileNameForLocale(), m_version, varMeasurement,
|
|
|
|
varInsunits));
|
2017-07-16 20:10:48 +02:00
|
|
|
input->AddQtLTypes();
|
2017-07-17 16:19:49 +02:00
|
|
|
input->AddDefLayers();
|
2015-09-07 21:47:02 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2015-09-07 21:47:02 +02:00
|
|
|
bool VDxfEngine::end()
|
|
|
|
{
|
2021-04-28 19:06:24 +02:00
|
|
|
return input->fileExport(m_binary);
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
// cppcheck-suppress unusedFunction
|
2015-09-07 21:47:02 +02:00
|
|
|
void VDxfEngine::updateState(const QPaintEngineState &state)
|
|
|
|
{
|
|
|
|
QPaintEngine::DirtyFlags flags = state.state();
|
|
|
|
|
|
|
|
// always stream full gstate, which is not required, but...
|
|
|
|
flags |= QPaintEngine::AllDirty;
|
|
|
|
|
|
|
|
|
|
|
|
if (flags & QPaintEngine::DirtyTransform)
|
|
|
|
{
|
2020-07-07 09:51:00 +02:00
|
|
|
matrix = state.transform(); // Save new matrix for moving paths
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2015-09-07 21:47:02 +02:00
|
|
|
void VDxfEngine::drawPath(const QPainterPath &path)
|
|
|
|
{
|
2016-02-09 16:19:07 +01:00
|
|
|
const QList<QPolygonF> subpaths = path.toSubpathPolygons(matrix);
|
2015-09-07 21:47:02 +02:00
|
|
|
|
2022-01-29 13:57:21 +01:00
|
|
|
for (const auto& polygon : subpaths)
|
2015-09-07 21:47:02 +02:00
|
|
|
{
|
2016-02-10 18:32:26 +01:00
|
|
|
if (polygon.isEmpty())
|
2016-02-09 16:19:07 +01:00
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
continue;
|
2016-02-09 16:19:07 +01:00
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
if (m_version > DRW::AC1009)
|
|
|
|
{ // Use lwpolyline
|
2022-01-29 13:57:21 +01:00
|
|
|
auto *poly = new DRW_LWPolyline();
|
2018-04-12 12:13:19 +02:00
|
|
|
poly->layer = '0';
|
2017-06-21 11:34:20 +02:00
|
|
|
poly->color = getPenColor();
|
|
|
|
poly->lWeight = DRW_LW_Conv::widthByLayer;
|
|
|
|
poly->lineType = getPenStyle();
|
2017-06-26 12:00:59 +02:00
|
|
|
|
2022-01-29 13:57:21 +01:00
|
|
|
if (polygon.size() > 1 && ConstFirst<QPointF>(polygon) == ConstLast<QPointF>(polygon))
|
2017-06-23 21:11:25 +02:00
|
|
|
{
|
2017-06-26 12:00:59 +02:00
|
|
|
poly->flags |= 0x1; // closed
|
2017-06-23 21:11:25 +02:00
|
|
|
}
|
2017-06-21 11:34:20 +02:00
|
|
|
|
2017-06-26 12:00:59 +02:00
|
|
|
poly->flags |= 0x80; // plinegen
|
|
|
|
|
2018-04-03 13:36:38 +02:00
|
|
|
for (auto p : polygon)
|
2017-06-21 11:34:20 +02:00
|
|
|
{
|
2018-04-03 13:36:38 +02:00
|
|
|
poly->addVertex(DRW_Vertex2D(FromPixel(p.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - p.y(), varInsunits), 0));
|
2017-06-21 11:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
input->AddEntity(poly);
|
2016-02-09 16:19:07 +01:00
|
|
|
}
|
2017-06-21 11:34:20 +02:00
|
|
|
else
|
|
|
|
{ // Use polyline
|
2022-01-29 13:57:21 +01:00
|
|
|
auto *poly = new DRW_Polyline();
|
2018-04-12 12:13:19 +02:00
|
|
|
poly->layer = '0';
|
2017-06-21 11:34:20 +02:00
|
|
|
poly->color = getPenColor();
|
|
|
|
poly->lWeight = DRW_LW_Conv::widthByLayer;
|
|
|
|
poly->lineType = getPenStyle();
|
2022-01-29 13:57:21 +01:00
|
|
|
if (polygon.size() > 1 && ConstFirst<QPointF>(polygon) == ConstLast<QPointF>(polygon))
|
2017-06-23 21:11:25 +02:00
|
|
|
{
|
2017-06-26 12:00:59 +02:00
|
|
|
poly->flags |= 0x1; // closed
|
2017-06-23 21:11:25 +02:00
|
|
|
}
|
2017-06-21 11:34:20 +02:00
|
|
|
|
2017-06-26 12:00:59 +02:00
|
|
|
poly->flags |= 0x80; // plinegen
|
|
|
|
|
2018-04-03 13:36:38 +02:00
|
|
|
for (auto p : polygon)
|
2017-06-21 11:34:20 +02:00
|
|
|
{
|
2018-04-03 13:36:38 +02:00
|
|
|
poly->addVertex(DRW_Vertex(FromPixel(p.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - p.y(), varInsunits), 0, 0));
|
2017-06-21 11:34:20 +02:00
|
|
|
}
|
2016-02-10 18:32:26 +01:00
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
input->AddEntity(poly);
|
|
|
|
}
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::drawLines(const QLineF * lines, int lineCount)
|
|
|
|
{
|
2016-02-10 18:32:26 +01:00
|
|
|
for (int i = 0; i < lineCount; ++i)
|
2015-09-07 21:47:02 +02:00
|
|
|
{
|
2016-03-27 18:00:08 +02:00
|
|
|
const QPointF p1 = matrix.map(lines[i].p1());
|
|
|
|
const QPointF p2 = matrix.map(lines[i].p2());
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
DRW_Line *line = new DRW_Line();
|
|
|
|
line->basePoint = DRW_Coord(FromPixel(p1.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - p1.y(), varInsunits), 0);
|
|
|
|
line->secPoint = DRW_Coord(FromPixel(p2.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - p2.y(), varInsunits), 0);
|
2018-04-12 12:13:19 +02:00
|
|
|
line->layer = '0';
|
2017-06-21 11:34:20 +02:00
|
|
|
line->color = getPenColor();
|
|
|
|
line->lWeight = DRW_LW_Conv::widthByLayer;
|
|
|
|
line->lineType = getPenStyle();
|
|
|
|
|
|
|
|
input->AddEntity(line);
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::drawLines(const QLine * lines, int lineCount)
|
|
|
|
{
|
|
|
|
QPaintEngine::drawLines(lines, lineCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
|
|
|
|
{
|
|
|
|
Q_UNUSED(mode)
|
|
|
|
|
2016-02-10 18:32:26 +01:00
|
|
|
if (pointCount <= 0)
|
2015-09-07 21:47:02 +02:00
|
|
|
{
|
2016-02-10 18:32:26 +01:00
|
|
|
return;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
2016-02-10 18:32:26 +01:00
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
if (m_version > DRW::AC1009)
|
|
|
|
{ // Use lwpolyline
|
|
|
|
DRW_LWPolyline *poly = new DRW_LWPolyline();
|
2018-04-12 12:13:19 +02:00
|
|
|
poly->layer = '0';
|
2017-06-21 11:34:20 +02:00
|
|
|
poly->color = getPenColor();
|
|
|
|
poly->lWeight = DRW_LW_Conv::widthByLayer;
|
|
|
|
poly->lineType = getPenStyle();
|
2016-02-10 18:32:26 +01:00
|
|
|
|
2017-06-26 12:00:59 +02:00
|
|
|
if (pointCount > 1 && points[0] == points[pointCount])
|
|
|
|
{
|
|
|
|
poly->flags |= 0x1; // closed
|
|
|
|
}
|
|
|
|
|
|
|
|
poly->flags |= 0x80; // plinegen
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
for (int i = 0; i < pointCount; ++i)
|
|
|
|
{
|
|
|
|
const QPointF p = matrix.map(points[i]);
|
|
|
|
poly->addVertex(DRW_Vertex2D(FromPixel(p.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - p.y(), varInsunits), 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
input->AddEntity(poly);
|
2016-02-10 18:32:26 +01:00
|
|
|
}
|
2017-06-21 11:34:20 +02:00
|
|
|
else
|
|
|
|
{ // Use polyline
|
|
|
|
DRW_Polyline *poly = new DRW_Polyline();
|
2018-04-12 12:13:19 +02:00
|
|
|
poly->layer = '0';
|
2017-06-21 11:34:20 +02:00
|
|
|
poly->color = getPenColor();
|
|
|
|
poly->lWeight = DRW_LW_Conv::widthByLayer;
|
|
|
|
poly->lineType = getPenStyle();
|
|
|
|
|
2017-06-26 12:00:59 +02:00
|
|
|
if (pointCount > 1 && points[0] == points[pointCount])
|
|
|
|
{
|
|
|
|
poly->flags |= 0x1; // closed
|
|
|
|
}
|
|
|
|
|
|
|
|
poly->flags |= 0x80; // plinegen
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
for (int i = 0; i < pointCount; ++i)
|
|
|
|
{
|
|
|
|
const QPointF p = matrix.map(points[i]);
|
|
|
|
poly->addVertex(DRW_Vertex(FromPixel(p.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - p.y(), varInsunits), 0, 0));
|
|
|
|
}
|
2016-02-10 18:32:26 +01:00
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
input->AddEntity(poly);
|
|
|
|
}
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::drawPolygon(const QPoint *points, int pointCount, QPaintEngine::PolygonDrawMode mode)
|
|
|
|
{
|
|
|
|
QPaintEngine::drawPolygon(points, pointCount, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::drawEllipse(const QRectF & rect)
|
|
|
|
{
|
2016-03-27 18:00:08 +02:00
|
|
|
const QRectF newRect = matrix.mapRect(rect);
|
|
|
|
const double rotationAngle = atan(matrix.m12()/matrix.m11());
|
2015-09-07 21:47:02 +02:00
|
|
|
|
|
|
|
double majorX, majorY; // distanse between center and endpoint of the major axis
|
|
|
|
double ratio; // ratio of minor axis to major axis
|
|
|
|
if(rect.width()<= rect.height())
|
|
|
|
{
|
|
|
|
majorX = (rect.top() - rect.center().y())*sin(rotationAngle)*matrix.m11()/cos(rotationAngle);
|
|
|
|
// major axis * sin(rotation angle) * x-scale-factor
|
|
|
|
majorY = (rect.top() - rect.center().y())*matrix.m22();
|
|
|
|
// major axis * cos(rotation angle) * y-scale-factor, where y-scale-factor = matrix.m22()/cos(rotationAngle)
|
|
|
|
ratio = rect.width()/rect.height();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
majorX = (rect.right() - rect.center().x())*matrix.m11();
|
|
|
|
// major axis * cos(rotation angle) * x-scale-factor, where y-scale-factor = matrix.m22()/cos(rotationAngle)
|
|
|
|
majorY = (rect.right() - rect.center().x())*sin(rotationAngle)*matrix.m22()/cos(rotationAngle);
|
|
|
|
// major axis * sin(rotation angle) * y-scale-factor
|
|
|
|
ratio = rect.height()/rect.width();
|
|
|
|
}
|
2016-03-27 18:00:08 +02:00
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
DRW_Ellipse *ellipse = new DRW_Ellipse();
|
|
|
|
ellipse->basePoint = DRW_Coord(FromPixel(newRect.center().x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - newRect.center().y(), varInsunits), 0);
|
|
|
|
ellipse->secPoint = DRW_Coord(FromPixel(majorX, varInsunits), FromPixel(majorY, varInsunits), 0);
|
|
|
|
ellipse->ratio = ratio;
|
|
|
|
ellipse->staparam = 0;
|
|
|
|
ellipse->endparam = 2*M_PI;
|
|
|
|
|
2018-04-12 12:13:19 +02:00
|
|
|
ellipse->layer = '0';
|
2017-06-21 11:34:20 +02:00
|
|
|
ellipse->color = getPenColor();
|
|
|
|
ellipse->lWeight = DRW_LW_Conv::widthByLayer;
|
|
|
|
ellipse->lineType = getPenStyle();
|
|
|
|
|
|
|
|
input->AddEntity(ellipse);
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::drawEllipse(const QRect & rect)
|
|
|
|
{
|
|
|
|
QPaintEngine::drawEllipse(rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::drawTextItem(const QPointF & p, const QTextItem & textItem)
|
|
|
|
{
|
2017-06-29 17:56:52 +02:00
|
|
|
if (textBuffer->text.size() == 0)
|
|
|
|
{
|
|
|
|
const QPointF startPoint = matrix.map(p);
|
|
|
|
const double rotationAngle = qRadiansToDegrees(qAtan2(matrix.m12(), matrix.m11()));
|
2015-09-07 21:47:02 +02:00
|
|
|
|
2017-06-29 17:56:52 +02:00
|
|
|
const QFont f = textItem.font();
|
|
|
|
const UTF8STRING fontStyle = input->AddFont(f);
|
2017-06-21 11:34:20 +02:00
|
|
|
|
2017-06-29 17:56:52 +02:00
|
|
|
textBuffer->basePoint = DRW_Coord(FromPixel(startPoint.x(), varInsunits),
|
2017-06-21 11:34:20 +02:00
|
|
|
FromPixel(getSize().height() - startPoint.y(), varInsunits), 0);
|
2017-06-29 17:56:52 +02:00
|
|
|
textBuffer->secPoint = DRW_Coord(FromPixel(startPoint.x(), varInsunits),
|
2017-06-21 11:34:20 +02:00
|
|
|
FromPixel(getSize().height() - startPoint.y(), varInsunits), 0);
|
2017-06-29 17:56:52 +02:00
|
|
|
textBuffer->height = FromPixel(QFontMetrics(f).height(), varInsunits);
|
2017-06-21 11:34:20 +02:00
|
|
|
|
2017-06-29 17:56:52 +02:00
|
|
|
textBuffer->style = fontStyle;
|
|
|
|
textBuffer->angle = -rotationAngle;
|
2017-06-21 11:34:20 +02:00
|
|
|
|
2018-04-12 12:13:19 +02:00
|
|
|
textBuffer->layer = '0';
|
2017-06-29 17:56:52 +02:00
|
|
|
textBuffer->color = getPenColor();
|
|
|
|
textBuffer->lWeight = DRW_LW_Conv::widthByLayer;
|
|
|
|
textBuffer->lineType = getPenStyle();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Because QPaintEngine::drawTextItem doesn't pass whole string per time we mark end of each string by adding
|
|
|
|
* special placholder. */
|
|
|
|
QString t = textItem.text();
|
|
|
|
const bool foundEndOfString = t.contains(endStringPlaceholder);
|
|
|
|
|
|
|
|
if (foundEndOfString)
|
|
|
|
{
|
2018-03-14 15:01:24 +01:00
|
|
|
t.replace(endStringPlaceholder, QString());
|
2017-06-21 11:34:20 +02:00
|
|
|
}
|
|
|
|
|
2017-06-29 17:56:52 +02:00
|
|
|
textBuffer->text += t.toStdString();
|
2017-06-21 11:34:20 +02:00
|
|
|
|
2017-06-29 17:56:52 +02:00
|
|
|
if (foundEndOfString)
|
|
|
|
{
|
|
|
|
input->AddEntity(textBuffer);
|
|
|
|
textBuffer = new DRW_Text();
|
2017-06-21 11:34:20 +02:00
|
|
|
}
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
|
2017-06-29 17:56:52 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2015-09-07 21:47:02 +02:00
|
|
|
QPaintEngine::Type VDxfEngine::type() const
|
|
|
|
{
|
|
|
|
return QPaintEngine::User;
|
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
// cppcheck-suppress unusedFunction
|
2015-09-07 21:47:02 +02:00
|
|
|
void VDxfEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
|
|
|
|
{
|
|
|
|
Q_UNUSED(r)
|
|
|
|
Q_UNUSED(pm)
|
|
|
|
Q_UNUSED(sr)
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
QSize VDxfEngine::getSize() const
|
|
|
|
{
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::setSize(const QSize &value)
|
|
|
|
{
|
2015-10-28 15:22:36 +01:00
|
|
|
Q_ASSERT(not isActive());
|
2015-09-07 21:47:02 +02:00
|
|
|
size = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2016-03-27 18:00:08 +02:00
|
|
|
double VDxfEngine::getResolution() const
|
2015-09-07 21:47:02 +02:00
|
|
|
{
|
|
|
|
return resolution;
|
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2016-03-27 18:00:08 +02:00
|
|
|
void VDxfEngine::setResolution(double value)
|
2015-09-07 21:47:02 +02:00
|
|
|
{
|
2015-10-28 15:22:36 +01:00
|
|
|
Q_ASSERT(not isActive());
|
2015-09-07 21:47:02 +02:00
|
|
|
resolution = value;
|
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2015-09-07 21:47:02 +02:00
|
|
|
QString VDxfEngine::getFileName() const
|
|
|
|
{
|
|
|
|
return fileName;
|
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2015-09-07 21:47:02 +02:00
|
|
|
void VDxfEngine::setFileName(const QString &value)
|
|
|
|
{
|
2015-10-28 15:22:36 +01:00
|
|
|
Q_ASSERT(not isActive());
|
2015-09-07 21:47:02 +02:00
|
|
|
fileName = value;
|
|
|
|
}
|
|
|
|
|
2017-06-21 11:34:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
DRW::Version VDxfEngine::GetVersion() const
|
|
|
|
{
|
|
|
|
return m_version;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::SetVersion(DRW::Version version)
|
|
|
|
{
|
|
|
|
Q_ASSERT(not isActive());
|
|
|
|
m_version = version;
|
|
|
|
}
|
|
|
|
|
2017-06-26 16:28:41 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::SetBinaryFormat(bool binary)
|
|
|
|
{
|
|
|
|
m_binary = binary;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
bool VDxfEngine::IsBinaryFormat() const
|
|
|
|
{
|
|
|
|
return m_binary;
|
|
|
|
}
|
|
|
|
|
2015-09-07 21:47:02 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
std::string VDxfEngine::getPenStyle()
|
|
|
|
{
|
|
|
|
switch (state->pen().style())
|
|
|
|
{
|
|
|
|
case Qt::DashLine:
|
2017-06-26 12:00:59 +02:00
|
|
|
return "DASHED";
|
2015-09-07 21:47:02 +02:00
|
|
|
case Qt::DotLine:
|
|
|
|
return "DOT";
|
|
|
|
case Qt::DashDotLine:
|
2017-06-23 21:11:25 +02:00
|
|
|
return "DASHDOT2";
|
2015-09-07 21:47:02 +02:00
|
|
|
case Qt::DashDotDotLine:
|
2017-06-23 21:11:25 +02:00
|
|
|
return "DIVIDE2";
|
2016-12-21 20:35:07 +01:00
|
|
|
case Qt::SolidLine:
|
2015-09-07 21:47:02 +02:00
|
|
|
default:
|
|
|
|
return "BYLAYER";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
int VDxfEngine::getPenColor()
|
|
|
|
{
|
|
|
|
QColor color = state->pen().color();
|
|
|
|
|
|
|
|
if(color == Qt::black)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::black;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::white)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::white;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::darkGray)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::gray;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::gray)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::l_gray;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::darkMagenta)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::magenta;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::magenta)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::l_magenta;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::cyan)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::l_cyan;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::darkCyan)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::cyan;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::blue)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::l_blue;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::darkBlue)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::blue;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::darkGreen)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::green;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::green)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::l_green;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::darkRed)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::red;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::red)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::l_red;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else if(color == Qt::yellow)
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::yellow;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-21 11:34:20 +02:00
|
|
|
return DRW::ColorByLayer;
|
2015-09-07 21:47:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::setMeasurement(const VarMeasurement &var)
|
|
|
|
{
|
2015-10-28 15:22:36 +01:00
|
|
|
Q_ASSERT(not isActive());
|
2015-09-07 21:47:02 +02:00
|
|
|
varMeasurement = var;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::setInsunits(const VarInsunits &var)
|
|
|
|
{
|
2015-10-28 15:22:36 +01:00
|
|
|
Q_ASSERT(not isActive());
|
2015-09-07 21:47:02 +02:00
|
|
|
varInsunits = var;
|
|
|
|
}
|
2016-03-27 18:00:08 +02:00
|
|
|
|
2020-03-21 17:15:29 +01:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
qreal VDxfEngine::GetXScale() const
|
|
|
|
{
|
|
|
|
return m_xscale;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::SetXScale(const qreal &xscale)
|
|
|
|
{
|
|
|
|
m_xscale = xscale;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
qreal VDxfEngine::GetYScale() const
|
|
|
|
{
|
|
|
|
return m_yscale;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::SetYScale(const qreal &yscale)
|
|
|
|
{
|
|
|
|
m_yscale = yscale;
|
|
|
|
}
|
|
|
|
|
2021-04-28 19:06:24 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
QString VDxfEngine::ErrorString() const
|
|
|
|
{
|
|
|
|
return QString::fromStdString(input->ErrorString());
|
|
|
|
}
|
|
|
|
|
2016-03-27 18:00:08 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2016-08-06 20:42:40 +02:00
|
|
|
QT_WARNING_PUSH
|
|
|
|
QT_WARNING_DISABLE_GCC("-Wswitch-default")
|
2016-03-27 18:00:08 +02:00
|
|
|
|
|
|
|
double VDxfEngine::FromPixel(double pix, const VarInsunits &unit) const
|
|
|
|
{
|
|
|
|
switch (unit)
|
|
|
|
{
|
|
|
|
case VarInsunits::Millimeters:
|
|
|
|
return pix / resolution * 25.4;
|
|
|
|
case VarInsunits::Centimeters:
|
|
|
|
return pix / resolution * 25.4 / 10.0;
|
|
|
|
case VarInsunits::Inches:
|
|
|
|
return pix / resolution;
|
|
|
|
}
|
2017-07-16 20:10:48 +02:00
|
|
|
return pix;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
double VDxfEngine::ToPixel(double val, const VarInsunits &unit) const
|
|
|
|
{
|
|
|
|
switch (unit)
|
|
|
|
{
|
|
|
|
case VarInsunits::Millimeters:
|
|
|
|
return (val / 25.4) * resolution;
|
|
|
|
case VarInsunits::Centimeters:
|
|
|
|
return ((val * 10.0) / 25.4) * resolution;
|
|
|
|
case VarInsunits::Inches:
|
|
|
|
return val * resolution;
|
|
|
|
}
|
|
|
|
return val;
|
2016-03-27 18:00:08 +02:00
|
|
|
}
|
|
|
|
|
2016-08-06 20:42:40 +02:00
|
|
|
QT_WARNING_POP
|
2017-07-16 20:10:48 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
bool VDxfEngine::ExportToAAMA(const QVector<VLayoutPiece> &details)
|
|
|
|
{
|
|
|
|
if (size.isValid() == false)
|
|
|
|
{
|
|
|
|
qWarning()<<"VDxfEngine::begin(), size is not valid";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-07-16 19:00:42 +02:00
|
|
|
input = QSharedPointer<dx_iface>(new dx_iface(getFileNameForLocale(), m_version, varMeasurement,
|
|
|
|
varInsunits));
|
2017-07-19 09:34:24 +02:00
|
|
|
input->AddAAMAHeaderData();
|
2017-07-17 16:19:49 +02:00
|
|
|
if (m_version > DRW::AC1009)
|
|
|
|
{
|
|
|
|
input->AddDefLayers();
|
|
|
|
}
|
2017-07-16 20:10:48 +02:00
|
|
|
input->AddAAMALayers();
|
|
|
|
|
2020-03-15 12:35:31 +01:00
|
|
|
ExportStyleSystemText(input, details);
|
2017-07-16 20:10:48 +02:00
|
|
|
|
2020-03-21 17:15:29 +01:00
|
|
|
for(auto detail : details)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2021-04-28 19:06:24 +02:00
|
|
|
auto *detailBlock = new dx_ifaceBlock();
|
2017-07-17 16:43:10 +02:00
|
|
|
|
|
|
|
QString blockName = detail.GetName();
|
|
|
|
if (m_version <= DRW::AC1009)
|
|
|
|
{
|
|
|
|
blockName.replace(' ', '_');
|
|
|
|
}
|
|
|
|
|
|
|
|
detailBlock->name = blockName.toStdString();
|
2018-04-12 12:13:19 +02:00
|
|
|
detailBlock->layer = '1';
|
2017-07-16 20:10:48 +02:00
|
|
|
|
2020-03-21 17:15:29 +01:00
|
|
|
detail.Scale(m_xscale, m_yscale);
|
|
|
|
|
2017-07-16 20:10:48 +02:00
|
|
|
ExportAAMAOutline(detailBlock, detail);
|
|
|
|
ExportAAMADraw(detailBlock, detail);
|
|
|
|
ExportAAMAIntcut(detailBlock, detail);
|
|
|
|
ExportAAMANotch(detailBlock, detail);
|
|
|
|
ExportAAMAGrainline(detailBlock, detail);
|
2020-03-15 12:35:31 +01:00
|
|
|
ExportPieceText(detailBlock, detail);
|
2017-10-15 11:25:20 +02:00
|
|
|
ExportAAMADrill(detailBlock, detail);
|
2017-07-16 20:10:48 +02:00
|
|
|
|
|
|
|
input->AddBlock(detailBlock);
|
|
|
|
|
2021-04-28 19:06:24 +02:00
|
|
|
auto *insert = new DRW_Insert();
|
2017-07-17 16:43:10 +02:00
|
|
|
insert->name = blockName.toStdString();
|
2018-04-12 12:13:19 +02:00
|
|
|
insert->layer = '1';
|
2017-07-16 20:10:48 +02:00
|
|
|
|
|
|
|
input->AddEntity(insert);
|
|
|
|
}
|
|
|
|
|
|
|
|
return input->fileExport(m_binary);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportAAMAOutline(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2020-03-15 12:35:31 +01:00
|
|
|
DRW_Entity *e = AAMAPolygon(PieceOutline(detail), QChar('1'), true);
|
2017-07-16 20:10:48 +02:00
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportAAMADraw(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2021-04-19 16:28:25 +02:00
|
|
|
if (detail.IsSeamAllowance() && not detail.IsHideMainPath() && not detail.IsSeamAllowanceBuiltIn())
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2020-01-11 10:48:02 +01:00
|
|
|
if (DRW_Entity *e = AAMAPolygon(detail.GetMappedContourPoints(), QChar('8'), true))
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-14 14:18:15 +02:00
|
|
|
const QVector<QVector<QPointF>> drawIntCut = detail.MappedInternalPathsForCut(false);
|
2018-04-03 10:15:58 +02:00
|
|
|
for(auto &intCut : drawIntCut)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2018-04-12 12:13:19 +02:00
|
|
|
if (DRW_Entity *e = AAMAPolygon(intCut, QChar('8'), false))
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-14 14:18:15 +02:00
|
|
|
const QVector<VLayoutPlaceLabel> labels = detail.GetMappedPlaceLabels();
|
2018-04-03 10:15:58 +02:00
|
|
|
for(auto &label : labels)
|
2017-10-15 11:25:20 +02:00
|
|
|
{
|
2019-04-23 16:42:09 +02:00
|
|
|
if (label.type != PlaceLabelType::Doubletree && label.type != PlaceLabelType::Button
|
|
|
|
&& label.type != PlaceLabelType::Circle)
|
2017-10-15 11:25:20 +02:00
|
|
|
{
|
2018-04-03 10:15:58 +02:00
|
|
|
for(auto &p : qAsConst(label.shape))
|
2017-10-15 11:25:20 +02:00
|
|
|
{
|
2018-04-12 12:13:19 +02:00
|
|
|
if (DRW_Entity *e = AAMAPolygon(p, QChar('8'), false))
|
2017-10-15 11:25:20 +02:00
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportAAMAIntcut(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2021-08-14 14:18:15 +02:00
|
|
|
QVector<QVector<QPointF>> drawIntCut = detail.MappedInternalPathsForCut(true);
|
2018-04-03 10:15:58 +02:00
|
|
|
for(auto &intCut : drawIntCut)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2018-04-03 10:15:58 +02:00
|
|
|
if (DRW_Entity *e = AAMAPolygon(intCut, "11", false))
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportAAMANotch(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
|
|
|
if (detail.IsSeamAllowance())
|
|
|
|
{
|
2021-05-27 18:52:37 +02:00
|
|
|
const QVector<VLayoutPassmark> passmarks = detail.GetMappedPassmarks();
|
2019-05-27 13:57:36 +02:00
|
|
|
for(auto &passmark : passmarks)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2019-05-27 13:57:36 +02:00
|
|
|
for (auto &line : passmark.lines)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2019-05-27 13:57:36 +02:00
|
|
|
if (DRW_Entity *e = AAMALine(line, QChar('4')))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
2017-07-16 20:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportAAMAGrainline(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2021-05-27 18:52:37 +02:00
|
|
|
const QVector<QPointF> grainline = detail.GetMappedGrainline();
|
2017-07-16 20:10:48 +02:00
|
|
|
if (grainline.count() > 1)
|
|
|
|
{
|
2022-01-29 09:59:02 +01:00
|
|
|
if (DRW_Entity *e = AAMALine(QLineF(ConstFirst(grainline), ConstLast(grainline)), QChar('7')))
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2020-03-15 12:35:31 +01:00
|
|
|
void VDxfEngine::ExportPieceText(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
|
|
|
const QStringList list = detail.GetPieceText();
|
|
|
|
const QPointF startPos = detail.GetPieceTextPosition();
|
|
|
|
|
|
|
|
for (int i = 0; i < list.size(); ++i)
|
|
|
|
{
|
2020-03-21 17:15:29 +01:00
|
|
|
QPointF pos(startPos.x(), startPos.y() - ToPixel(AAMATextHeight * m_yscale, varInsunits)*(list.size() - i-1));
|
2018-04-12 12:13:19 +02:00
|
|
|
detailBlock->ent.push_back(AAMAText(pos, list.at(i), QChar('1')));
|
2017-07-16 20:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
2020-03-15 12:35:31 +01:00
|
|
|
void VDxfEngine::ExportStyleSystemText(const QSharedPointer<dx_iface> &input, const QVector<VLayoutPiece> &details)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2018-04-03 13:36:38 +02:00
|
|
|
for(auto &detail : details)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2018-04-03 13:36:38 +02:00
|
|
|
const QStringList strings = detail.GetPatternText();
|
2017-07-16 20:10:48 +02:00
|
|
|
if (not strings.isEmpty())
|
|
|
|
{
|
|
|
|
for (int j = 0; j < strings.size(); ++j)
|
|
|
|
{
|
2020-03-21 17:15:29 +01:00
|
|
|
QPointF pos(0, getSize().height() -
|
|
|
|
ToPixel(AAMATextHeight * m_yscale, varInsunits)*(strings.size() - j-1));
|
2018-04-12 12:13:19 +02:00
|
|
|
input->AddEntity(AAMAText(pos, strings.at(j), QChar('1')));
|
2017-07-16 20:10:48 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-15 11:25:20 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportAAMADrill(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2021-08-14 14:18:15 +02:00
|
|
|
const QVector<VLayoutPlaceLabel> labels = detail.GetMappedPlaceLabels();
|
2017-10-15 11:25:20 +02:00
|
|
|
|
2018-04-03 10:15:58 +02:00
|
|
|
for(auto &label : labels)
|
2017-10-15 11:25:20 +02:00
|
|
|
{
|
2019-04-23 16:42:09 +02:00
|
|
|
if (label.type == PlaceLabelType::Doubletree || label.type == PlaceLabelType::Button
|
|
|
|
|| label.type == PlaceLabelType::Circle)
|
2017-10-15 11:25:20 +02:00
|
|
|
{
|
2019-08-07 09:15:53 +02:00
|
|
|
const QPointF center = detail.GetMatrix().map(label.center);
|
2017-10-15 11:25:20 +02:00
|
|
|
DRW_Point *point = new DRW_Point();
|
2019-08-07 09:15:53 +02:00
|
|
|
point->basePoint = DRW_Coord(FromPixel(center.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - center.y(), varInsunits), 0);
|
2017-10-15 11:25:20 +02:00
|
|
|
point->layer = "13";
|
|
|
|
|
|
|
|
detailBlock->ent.push_back(point);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-15 12:35:31 +01:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
bool VDxfEngine::ExportToASTM(const QVector<VLayoutPiece> &details)
|
|
|
|
{
|
|
|
|
if (size.isValid() == false)
|
|
|
|
{
|
|
|
|
qWarning()<<"VDxfEngine::begin(), size is not valid";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
input = QSharedPointer<dx_iface>(new dx_iface(getFileNameForLocale(), m_version, varMeasurement,
|
|
|
|
varInsunits));
|
|
|
|
|
|
|
|
input->AddAAMAHeaderData();
|
|
|
|
if (m_version > DRW::AC1009)
|
|
|
|
{
|
|
|
|
input->AddDefLayers();
|
|
|
|
}
|
|
|
|
input->AddASTMLayers();
|
|
|
|
|
|
|
|
ExportStyleSystemText(input, details);
|
|
|
|
|
2020-03-21 17:15:29 +01:00
|
|
|
for(auto detail : details)
|
2020-03-15 12:35:31 +01:00
|
|
|
{
|
2021-04-28 19:06:24 +02:00
|
|
|
auto *detailBlock = new dx_ifaceBlock();
|
2020-03-15 12:35:31 +01:00
|
|
|
|
|
|
|
QString blockName = detail.GetName();
|
|
|
|
if (m_version <= DRW::AC1009)
|
|
|
|
{
|
|
|
|
blockName.replace(' ', '_');
|
|
|
|
}
|
|
|
|
|
|
|
|
detailBlock->name = blockName.toStdString();
|
|
|
|
detailBlock->layer = '1';
|
|
|
|
|
2020-03-21 17:15:29 +01:00
|
|
|
detail.Scale(m_xscale, m_yscale);
|
|
|
|
|
2020-03-15 12:35:31 +01:00
|
|
|
ExportASTMPieceBoundary(detailBlock, detail);
|
|
|
|
ExportASTMSewLine(detailBlock, detail);
|
|
|
|
ExportASTMInternalLine(detailBlock, detail);
|
|
|
|
ExportASTMInternalCutout(detailBlock, detail);
|
|
|
|
ExportASTMNotch(detailBlock, detail);
|
|
|
|
ExportAAMAGrainline(detailBlock, detail);
|
|
|
|
ExportPieceText(detailBlock, detail);
|
|
|
|
ExportASTMDrill(detailBlock, detail);
|
|
|
|
ExportASTMAnnotationText(detailBlock, detail);
|
|
|
|
|
|
|
|
input->AddBlock(detailBlock);
|
|
|
|
|
2021-04-28 19:06:24 +02:00
|
|
|
auto *insert = new DRW_Insert();
|
2020-03-15 12:35:31 +01:00
|
|
|
insert->name = blockName.toStdString();
|
|
|
|
insert->layer = '1';
|
|
|
|
|
|
|
|
input->AddEntity(insert);
|
|
|
|
}
|
|
|
|
|
|
|
|
return input->fileExport(m_binary);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportASTMPieceBoundary(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
|
|
|
QVector<QPointF> pieceBoundary = PieceOutline(detail);
|
|
|
|
|
|
|
|
// Piece boundary
|
|
|
|
DRW_Entity *e = AAMAPolygon(PieceOutline(detail), QChar('1'), true);
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Piece boundary quality validation curves
|
|
|
|
DRW_Entity *q = AAMAPolygon(PieceOutline(detail), "84", true);
|
|
|
|
if (q)
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(q);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportASTMSewLine(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2021-04-19 16:28:25 +02:00
|
|
|
if (detail.IsSeamAllowance() && not detail.IsHideMainPath() && not detail.IsSeamAllowanceBuiltIn())
|
2020-03-15 12:35:31 +01:00
|
|
|
{
|
|
|
|
QVector<QPointF> sewLine = detail.GetMappedContourPoints();
|
|
|
|
|
|
|
|
// Sew lines
|
|
|
|
if (DRW_Entity *e = AAMAPolygon(sewLine, "14", true))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sew lines quality validation curves
|
|
|
|
if (DRW_Entity *e = AAMAPolygon(sewLine, "87", true))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportASTMInternalLine(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2021-08-14 14:18:15 +02:00
|
|
|
const QVector<QVector<QPointF>> drawIntCut = detail.MappedInternalPathsForCut(false);
|
2020-03-15 12:35:31 +01:00
|
|
|
for(auto &intCut : drawIntCut)
|
|
|
|
{
|
|
|
|
// Internal line
|
|
|
|
if (DRW_Entity *e = AAMAPolygon(intCut, QChar('8'), false))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Internal lines quality validation curves
|
|
|
|
if (DRW_Entity *e = AAMAPolygon(intCut, "85", false))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-14 14:18:15 +02:00
|
|
|
const QVector<VLayoutPlaceLabel> labels = detail.GetMappedPlaceLabels();
|
2020-03-15 12:35:31 +01:00
|
|
|
for(auto &label : labels)
|
|
|
|
{
|
|
|
|
if (label.type != PlaceLabelType::Doubletree && label.type != PlaceLabelType::Button
|
|
|
|
&& label.type != PlaceLabelType::Circle)
|
|
|
|
{
|
|
|
|
for(auto &p : qAsConst(label.shape))
|
|
|
|
{
|
|
|
|
// Internal line (placelabel)
|
|
|
|
if (DRW_Entity *e = AAMAPolygon(p, QChar('8'), false))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Internal lines quality validation curves
|
|
|
|
if (DRW_Entity *e = AAMAPolygon(p, "85", false))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportASTMInternalCutout(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2021-08-14 14:18:15 +02:00
|
|
|
QVector<QVector<QPointF>> drawIntCut = detail.MappedInternalPathsForCut(true);
|
2020-03-15 12:35:31 +01:00
|
|
|
for(auto &intCut : drawIntCut)
|
|
|
|
{
|
|
|
|
// Internal cutout
|
|
|
|
if (DRW_Entity *e = AAMAPolygon(intCut, "11", false))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Internal cutouts quality validation curves
|
|
|
|
if (DRW_Entity *e = AAMAPolygon(intCut, "86", false))
|
|
|
|
{
|
|
|
|
detailBlock->ent.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportASTMAnnotationText(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
|
|
|
QString name = detail.GetName();
|
|
|
|
QPointF textPos = detail.VLayoutPiece::DetailBoundingRect().center();
|
|
|
|
|
|
|
|
QPointF pos(textPos.x(), textPos.y() - ToPixel(AAMATextHeight, varInsunits));
|
|
|
|
detailBlock->ent.push_back(AAMAText(pos, name, "15"));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportASTMDrill(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
2021-08-14 14:18:15 +02:00
|
|
|
const QVector<VLayoutPlaceLabel> labels = detail.GetMappedPlaceLabels();
|
2020-03-15 12:35:31 +01:00
|
|
|
|
|
|
|
for(auto &label : labels)
|
|
|
|
{
|
|
|
|
if (label.type == PlaceLabelType::Doubletree || label.type == PlaceLabelType::Button
|
|
|
|
|| label.type == PlaceLabelType::Circle)
|
|
|
|
{
|
|
|
|
const QPointF center = detail.GetMatrix().map(label.center);
|
|
|
|
DRW_Point *point = new DRW_Point();
|
|
|
|
point->basePoint = DRW_Coord(FromPixel(center.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - center.y(), varInsunits), 0);
|
|
|
|
point->layer = "13";
|
|
|
|
|
|
|
|
detailBlock->ent.push_back(point);
|
|
|
|
|
|
|
|
// TODO. Investigate drill category
|
|
|
|
// QPointF pos(center.x(), center.y() - ToPixel(AAMATextHeight, varInsunits));
|
|
|
|
// detailBlock->ent.push_back(AAMAText(pos, category, "13"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void VDxfEngine::ExportASTMNotch(dx_ifaceBlock *detailBlock, const VLayoutPiece &detail)
|
|
|
|
{
|
|
|
|
if (detail.IsSeamAllowance())
|
|
|
|
{
|
2021-05-27 18:52:37 +02:00
|
|
|
const QVector<VLayoutPassmark> passmarks = detail.GetMappedPassmarks();
|
2020-03-15 12:35:31 +01:00
|
|
|
for(auto &passmark : passmarks)
|
|
|
|
{
|
|
|
|
DRW_ASTMNotch *notch = new DRW_ASTMNotch();
|
|
|
|
const QPointF center = passmark.baseLine.p1();
|
|
|
|
|
|
|
|
notch->basePoint = DRW_Coord(FromPixel(center.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - center.y(), varInsunits),
|
|
|
|
FromPixel(passmark.baseLine.length(), varInsunits));
|
|
|
|
|
|
|
|
notch->angle = passmark.baseLine.angle();
|
|
|
|
|
|
|
|
if (passmark.type == PassmarkLineType::OneLine || passmark.type == PassmarkLineType::TwoLines
|
|
|
|
|| passmark.type == PassmarkLineType::ThreeLines)
|
|
|
|
{ // Slit notch
|
|
|
|
notch->layer = "4";
|
|
|
|
}
|
|
|
|
else if (passmark.type == PassmarkLineType::VMark || passmark.type == PassmarkLineType::VMark2)
|
|
|
|
{
|
2022-01-29 09:59:02 +01:00
|
|
|
QLineF boundaryLine(ConstFirst(passmark.lines).p2(), ConstLast(passmark.lines).p2());
|
2020-03-15 12:35:31 +01:00
|
|
|
notch->thickness = FromPixel(boundaryLine.length(), varInsunits); // width
|
|
|
|
|
|
|
|
notch->layer = "4";
|
|
|
|
}
|
|
|
|
else if (passmark.type == PassmarkLineType::TMark)
|
|
|
|
{
|
2022-01-29 09:59:02 +01:00
|
|
|
qreal width = FromPixel(ConstLast(passmark.lines).length(), varInsunits);
|
2020-03-15 12:35:31 +01:00
|
|
|
notch->thickness = FromPixel(width, varInsunits);
|
|
|
|
|
|
|
|
notch->layer = "80";
|
|
|
|
}
|
|
|
|
else if (passmark.type == PassmarkLineType::BoxMark)
|
|
|
|
{
|
2022-01-29 09:59:02 +01:00
|
|
|
QPointF start = ConstFirst(passmark.lines).p1();
|
|
|
|
QPointF end = ConstLast(passmark.lines).p2();
|
2020-03-15 12:35:31 +01:00
|
|
|
|
|
|
|
notch->layer = "81";
|
|
|
|
|
|
|
|
notch->thickness = FromPixel(QLineF(start, end).length(), varInsunits);
|
|
|
|
}
|
|
|
|
else if (passmark.type == PassmarkLineType::UMark)
|
|
|
|
{
|
2022-01-29 09:59:02 +01:00
|
|
|
QPointF start = ConstFirst(passmark.lines).p1();
|
|
|
|
QPointF end = ConstLast(passmark.lines).p2();
|
2020-03-15 12:35:31 +01:00
|
|
|
|
|
|
|
notch->thickness = FromPixel(QLineF(start, end).length(), varInsunits);
|
|
|
|
|
|
|
|
notch->layer = "83";
|
|
|
|
}
|
|
|
|
|
|
|
|
detailBlock->ent.push_back(notch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-16 20:10:48 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
DRW_Entity *VDxfEngine::AAMAPolygon(const QVector<QPointF> &polygon, const QString &layer, bool forceClosed)
|
|
|
|
{
|
|
|
|
if (polygon.isEmpty())
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_version > DRW::AC1009)
|
|
|
|
{ // Use lwpolyline
|
|
|
|
return CreateAAMAPolygon<DRW_LWPolyline, DRW_Vertex2D>(polygon, layer, forceClosed);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Use polyline
|
|
|
|
return CreateAAMAPolygon<DRW_Polyline, DRW_Vertex>(polygon, layer, forceClosed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
DRW_Entity *VDxfEngine::AAMALine(const QLineF &line, const QString &layer)
|
|
|
|
{
|
|
|
|
DRW_Line *lineEnt = new DRW_Line();
|
|
|
|
lineEnt->basePoint = DRW_Coord(FromPixel(line.p1().x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - line.p1().y(), varInsunits), 0);
|
|
|
|
lineEnt->secPoint = DRW_Coord(FromPixel(line.p2().x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - line.p2().y(), varInsunits), 0);
|
|
|
|
lineEnt->layer = layer.toStdString();
|
|
|
|
|
|
|
|
return lineEnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
DRW_Entity *VDxfEngine::AAMAText(const QPointF &pos, const QString &text, const QString &layer)
|
|
|
|
{
|
|
|
|
DRW_Text *textLine = new DRW_Text();
|
|
|
|
|
|
|
|
textLine->basePoint = DRW_Coord(FromPixel(pos.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - pos.y(), varInsunits), 0);
|
|
|
|
textLine->secPoint = DRW_Coord(FromPixel(pos.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - pos.y(), varInsunits), 0);
|
|
|
|
textLine->height = AAMATextHeight;
|
|
|
|
textLine->layer = layer.toStdString();
|
|
|
|
textLine->text = text.toStdString();
|
|
|
|
|
|
|
|
return textLine;
|
|
|
|
}
|
|
|
|
|
2018-07-16 19:00:42 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
std::string VDxfEngine::FromUnicodeToCodec(const QString &str, QTextCodec *codec)
|
|
|
|
{
|
2019-04-05 14:42:22 +02:00
|
|
|
return codec->fromUnicode(str).toStdString();
|
2018-07-16 19:00:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
std::string VDxfEngine::getFileNameForLocale() const
|
|
|
|
{
|
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
return VDxfEngine::FromUnicodeToCodec(fileName, QTextCodec::codecForLocale());
|
|
|
|
#else
|
|
|
|
return fileName.toStdString();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-07-16 20:10:48 +02:00
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
template<class P, class V>
|
|
|
|
P *VDxfEngine::CreateAAMAPolygon(const QVector<QPointF> &polygon, const QString &layer, bool forceClosed)
|
|
|
|
{
|
|
|
|
P *poly = new P();
|
|
|
|
poly->layer = layer.toStdString();
|
|
|
|
|
|
|
|
if (forceClosed)
|
|
|
|
{
|
|
|
|
poly->flags |= 0x1; // closed
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-29 13:57:21 +01:00
|
|
|
if (polygon.size() > 1 && ConstFirst<QPointF>(polygon) == ConstLast<QPointF>(polygon))
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
|
|
|
poly->flags |= 0x1; // closed
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-03 13:36:38 +02:00
|
|
|
for (auto p : polygon)
|
2017-07-16 20:10:48 +02:00
|
|
|
{
|
2018-04-03 13:36:38 +02:00
|
|
|
poly->addVertex(V(FromPixel(p.x(), varInsunits),
|
|
|
|
FromPixel(getSize().height() - p.y(), varInsunits)));
|
2017-07-16 20:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return poly;
|
|
|
|
}
|