/************************************************************************ ** ** @file vdxfengine.cpp ** @author Valentina Zhuravska ** @date 12 8, 2015 ** ** @brief ** @copyright ** This source code is part of the Valentina project, a pattern making ** program, whose allow create and modeling patterns of clothing. ** Copyright (C) 2013-2015 Valentina project ** All Rights Reserved. ** ** 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 . ** *************************************************************************/ #include "vdxfengine.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include "../vmisc/vtextcodec.h" #else #include #endif #include "../vgeometry/vgeometrydef.h" #include "../vgeometry/vlayoutplacelabel.h" #include "../vlayout/vboundary.h" #include "../vlayout/vfoldline.h" #include "../vlayout/vlayoutpiece.h" #include "../vlayout/vlayoutpiecepath.h" #include "../vlayout/vlayoutpoint.h" #include "../vlayout/vtextmanager.h" #include "../vmisc/def.h" #include "dxiface.h" #include "libdxfrw/drw_entities.h" #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) #include "../vmisc/compatibility.h" #endif using namespace Qt::Literals::StringLiterals; namespace { const qreal AAMATextHeight = 2.5; QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wunused-member-function") Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer0, (UTF8STRING("0"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer1, (UTF8STRING("1"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer2, (UTF8STRING("2"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer3, (UTF8STRING("3"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer4, (UTF8STRING("4"))) // NOLINT // Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer5, (UTF8STRING("5"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer6, (UTF8STRING("6"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer7, (UTF8STRING("7"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer8, (UTF8STRING("8"))) // NOLINT // Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer9, (UTF8STRING("9"))) // NOLINT // Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer10, (UTF8STRING("10"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer11, (UTF8STRING("11"))) // NOLINT // Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer12, (UTF8STRING("12"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer13, (UTF8STRING("13"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer14, (UTF8STRING("14"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer15, (UTF8STRING("15"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer19, (UTF8STRING("19"))) // NOLINT // Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer26, (UTF8STRING("26"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer80, (UTF8STRING("80"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer81, (UTF8STRING("81"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer82, (UTF8STRING("82"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer83, (UTF8STRING("83"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer84, (UTF8STRING("84"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer85, (UTF8STRING("85"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer86, (UTF8STRING("86"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const UTF8STRING, layer87, (UTF8STRING("87"))) // NOLINT QT_WARNING_POP //--------------------------------------------------------------------------------------------------------------------- auto PieceOutline(const VLayoutPiece &detail) -> QVector { if (detail.IsSeamAllowance() && not detail.IsSeamAllowanceBuiltIn()) { return detail.GetMappedFullSeamAllowancePoints(); } return detail.GetMappedFullContourPoints(); } //--------------------------------------------------------------------------------------------------------------------- inline auto LineFont(const TextLine &tl, const QFont &base) -> QFont { QFont fnt = base; fnt.setPointSize(qMax(base.pointSize() + tl.m_iFontSize, 1)); fnt.setBold(tl.m_bold); fnt.setItalic(tl.m_italic); return fnt; } //--------------------------------------------------------------------------------------------------------------------- inline auto LineAlign(const TextLine &tl, const QString &text, const QFontMetrics &fm, qreal width) -> qreal { const int lineWidth = TextWidth(fm, text); qreal dX = 0; if ((tl.m_eAlign & Qt::AlignHCenter) > 0) { dX = (width - lineWidth) / 2; } else if ((tl.m_eAlign & Qt::AlignRight) > 0) { dX = width - lineWidth; } return dX; } //--------------------------------------------------------------------------------------------------------------------- inline auto LineMatrix(const VLayoutPiece &piece, const QPointF &topLeft, qreal angle, const QPointF &linePos, int maxLineWidth) -> QTransform { QTransform labelMatrix; labelMatrix.translate(topLeft.x(), topLeft.y()); if ((piece.IsVerticallyFlipped() && piece.IsHorizontallyFlipped()) || (!piece.IsVerticallyFlipped() && !piece.IsHorizontallyFlipped())) { labelMatrix.rotate(-angle); } else if (piece.IsVerticallyFlipped() || piece.IsHorizontallyFlipped()) { if (piece.IsVerticallyFlipped()) { labelMatrix.scale(-1, 1); labelMatrix.rotate(angle); labelMatrix.translate(-maxLineWidth, 0); } if (piece.IsHorizontallyFlipped()) { labelMatrix.scale(-1, 1); labelMatrix.rotate(angle); labelMatrix.translate(-maxLineWidth, 0); } } labelMatrix.translate(linePos.x(), linePos.y()); // Each string has own position labelMatrix *= piece.GetMatrix(); return labelMatrix; } } // namespace //--------------------------------------------------------------------------------------------------------------------- static inline auto svgEngineFeatures() -> QPaintEngine::PaintEngineFeatures { QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wsign-conversion") QT_WARNING_DISABLE_INTEL(68) return {QPaintEngine::AllFeatures & ~QPaintEngine::PatternBrush & ~QPaintEngine::PerspectiveTransform & ~QPaintEngine::ConicalGradientFill & ~QPaintEngine::PorterDuff}; QT_WARNING_POP } //--------------------------------------------------------------------------------------------------------------------- VDxfEngine::VDxfEngine() : QPaintEngine(svgEngineFeatures()), m_textBuffer(new DRW_Text()) { } //--------------------------------------------------------------------------------------------------------------------- VDxfEngine::~VDxfEngine() { delete m_textBuffer; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::begin(QPaintDevice *pdev) -> bool { Q_UNUSED(pdev) if (isActive()) { qWarning("VDxfEngine::begin(), the engine was alredy activated"); return false; } if (not m_size.isValid()) { qWarning() << "VDxfEngine::begin(), size is not valid"; return false; } m_input = QSharedPointer(new dx_iface(GetFileNameForLocale(), m_version, m_varMeasurement, m_varInsunits)); m_input->AddDefHeaderData(); m_input->AddQtLTypes(); m_input->AddDefLayers(); return true; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::end() -> bool { return m_input->fileExport(m_binary); } //--------------------------------------------------------------------------------------------------------------------- // cppcheck-suppress unusedFunction 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) { m_matrix = state.transform(); // Save new matrix for moving paths } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::drawPath(const QPainterPath &path) { const QList subpaths = path.toSubpathPolygons(m_matrix); for (const auto &polygon : subpaths) { if (polygon.isEmpty()) { continue; } if (m_version > DRW::AC1009) { // Use lwpolyline auto *poly = new DRW_LWPolyline(); poly->layer = *layer0; poly->color = GetPenColor(); poly->lWeight = DRW_LW_Conv::widthByLayer; poly->lineType = GetPenStyle(); if (polygon.size() > 1 && polygon.constFirst() == polygon.constLast()) { poly->flags |= 0x1; // closed NOLINT(hicpp-signed-bitwise) } poly->flags |= 0x80; // plinegen NOLINT(hicpp-signed-bitwise) for (auto p : polygon) { poly->addVertex(DRW_Vertex2D(FromPixel(p.x(), m_varInsunits), FromPixel(GetSize().height() - p.y(), m_varInsunits), 0)); } m_input->AddEntity(poly); } else { // Use polyline auto *poly = new DRW_Polyline(); poly->layer = *layer0; poly->color = GetPenColor(); poly->lWeight = DRW_LW_Conv::widthByLayer; poly->lineType = GetPenStyle(); if (polygon.size() > 1 && polygon.constFirst() == polygon.constLast()) { poly->flags |= 0x1; // closed NOLINT(hicpp-signed-bitwise) } poly->flags |= 0x80; // plinegen NOLINT(hicpp-signed-bitwise) for (auto p : polygon) { poly->addVertex(DRW_Vertex(FromPixel(p.x(), m_varInsunits), FromPixel(GetSize().height() - p.y(), m_varInsunits), 0, 0)); } m_input->AddEntity(poly); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::drawLines(const QLineF *lines, int lineCount) { for (int i = 0; i < lineCount; ++i) { const QPointF p1 = m_matrix.map(lines[i].p1()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const QPointF p2 = m_matrix.map(lines[i].p2()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) auto *line = new DRW_Line(); line->basePoint = DRW_Coord(FromPixel(p1.x(), m_varInsunits), FromPixel(GetSize().height() - p1.y(), m_varInsunits), 0); line->secPoint = DRW_Coord(FromPixel(p2.x(), m_varInsunits), FromPixel(GetSize().height() - p2.y(), m_varInsunits), 0); line->layer = *layer0; line->color = GetPenColor(); line->lWeight = DRW_LW_Conv::widthByLayer; line->lineType = GetPenStyle(); m_input->AddEntity(line); } } //--------------------------------------------------------------------------------------------------------------------- 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) if (pointCount <= 0) { return; } if (m_version > DRW::AC1009) { // Use lwpolyline auto *poly = new DRW_LWPolyline(); poly->layer = *layer0; poly->color = GetPenColor(); poly->lWeight = DRW_LW_Conv::widthByLayer; poly->lineType = GetPenStyle(); if (pointCount > 1 && points[0] == points[pointCount]) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { poly->flags |= 0x1; // closed NOLINT(hicpp-signed-bitwise) } poly->flags |= 0x80; // plinegen NOLINT(hicpp-signed-bitwise) for (int i = 0; i < pointCount; ++i) { const QPointF p = m_matrix.map(points[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) poly->addVertex( DRW_Vertex2D(FromPixel(p.x(), m_varInsunits), FromPixel(GetSize().height() - p.y(), m_varInsunits), 0)); } m_input->AddEntity(poly); } else { // Use polyline auto *poly = new DRW_Polyline(); poly->layer = *layer0; poly->color = GetPenColor(); poly->lWeight = DRW_LW_Conv::widthByLayer; poly->lineType = GetPenStyle(); if (pointCount > 1 && points[0] == points[pointCount]) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { poly->flags |= 0x1; // closed NOLINT(hicpp-signed-bitwise) } poly->flags |= 0x80; // plinegen NOLINT(hicpp-signed-bitwise) for (int i = 0; i < pointCount; ++i) { const QPointF p = m_matrix.map(points[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) poly->addVertex(DRW_Vertex(FromPixel(p.x(), m_varInsunits), FromPixel(GetSize().height() - p.y(), m_varInsunits), 0, 0)); } m_input->AddEntity(poly); } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::drawPolygon(const QPoint *points, int pointCount, QPaintEngine::PolygonDrawMode mode) { QPaintEngine::drawPolygon(points, pointCount, mode); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::drawEllipse(const QRectF &rect) { const QRectF newRect = m_matrix.mapRect(rect); const double rotationAngle = atan(m_matrix.m12() / m_matrix.m11()); 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) * m_matrix.m11() / cos(rotationAngle); // major axis * sin(rotation angle) * x-scale-factor majorY = (rect.top() - rect.center().y()) * m_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()) * m_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) * m_matrix.m22() / cos(rotationAngle); // major axis * sin(rotation angle) * y-scale-factor ratio = rect.height() / rect.width(); } auto *ellipse = new DRW_Ellipse(); ellipse->basePoint = DRW_Coord(FromPixel(newRect.center().x(), m_varInsunits), FromPixel(GetSize().height() - newRect.center().y(), m_varInsunits), 0); ellipse->secPoint = DRW_Coord(FromPixel(majorX, m_varInsunits), FromPixel(majorY, m_varInsunits), 0); ellipse->ratio = ratio; ellipse->staparam = 0; ellipse->endparam = 2 * M_PI; ellipse->layer = *layer0; ellipse->color = GetPenColor(); ellipse->lWeight = DRW_LW_Conv::widthByLayer; ellipse->lineType = GetPenStyle(); m_input->AddEntity(ellipse); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::drawEllipse(const QRect &rect) { QPaintEngine::drawEllipse(rect); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) { if (m_textBuffer->text.empty()) { const QPointF startPoint = m_matrix.map(p); const double rotationAngle = qRadiansToDegrees(qAtan2(m_matrix.m12(), m_matrix.m11())); const QFont f = textItem.font(); const UTF8STRING fontStyle = m_input->AddFont(f); m_textBuffer->basePoint = DRW_Coord(FromPixel(startPoint.x(), m_varInsunits), FromPixel(GetSize().height() - startPoint.y(), m_varInsunits), 0); m_textBuffer->secPoint = DRW_Coord(FromPixel(startPoint.x(), m_varInsunits), FromPixel(GetSize().height() - startPoint.y(), m_varInsunits), 0); m_textBuffer->height = FromPixel(QFontMetrics(f).height(), m_varInsunits); m_textBuffer->style = fontStyle; m_textBuffer->angle = -rotationAngle; m_textBuffer->layer = *layer0; m_textBuffer->color = GetPenColor(); m_textBuffer->lWeight = DRW_LW_Conv::widthByLayer; m_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) { t.replace(endStringPlaceholder, QString()); } m_textBuffer->text += t.toStdString(); if (foundEndOfString) { m_input->AddEntity(m_textBuffer); m_textBuffer = new DRW_Text(); } } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::type() const -> QPaintEngine::Type { return QPaintEngine::User; } //--------------------------------------------------------------------------------------------------------------------- // cppcheck-suppress unusedFunction void VDxfEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) { Q_UNUSED(r) Q_UNUSED(pm) Q_UNUSED(sr) } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetSize() const -> QSize { return m_size; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetSize(const QSize &value) { Q_ASSERT(not isActive()); m_size = value; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetResolution() const -> double { return m_resolution; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetResolution(double value) { Q_ASSERT(not isActive()); m_resolution = value; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetFileName() const -> QString { return m_fileName; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetFileName(const QString &value) { Q_ASSERT(not isActive()); m_fileName = value; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetVersion() const -> DRW::Version { return m_version; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetVersion(DRW::Version version) { Q_ASSERT(not isActive()); m_version = version; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetBinaryFormat(bool binary) { m_binary = binary; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::IsBinaryFormat() const -> bool { return m_binary; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetPenStyle() -> std::string { switch (state->pen().style()) { case Qt::DashLine: return "DASHED"; case Qt::DotLine: return "DOT"; case Qt::DashDotLine: return "DASHDOT2"; case Qt::DashDotDotLine: return "DIVIDE2"; case Qt::SolidLine: default: return "BYLAYER"; } } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetPenColor() -> int { QColor color = state->pen().color(); if (color == Qt::black) { return DRW::black; } if (color == Qt::white) { return DRW::white; } if (color == Qt::darkGray) { return DRW::gray; } if (color == Qt::gray) { return DRW::l_gray; } if (color == Qt::darkMagenta) { return DRW::magenta; } if (color == Qt::magenta) { return DRW::l_magenta; } if (color == Qt::cyan) { return DRW::l_cyan; } if (color == Qt::darkCyan) { return DRW::cyan; } if (color == Qt::blue) { return DRW::l_blue; } if (color == Qt::darkBlue) { return DRW::blue; } if (color == Qt::darkGreen) { return DRW::green; } if (color == Qt::green) { return DRW::l_green; } if (color == Qt::darkRed) { return DRW::red; } if (color == Qt::red) { return DRW::l_red; } if (color == Qt::yellow) { return DRW::yellow; } return DRW::ColorByLayer; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetMeasurement(const VarMeasurement &var) { Q_ASSERT(not isActive()); m_varMeasurement = var; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetInsunits(const VarInsunits &var) { Q_ASSERT(not isActive()); m_varInsunits = var; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetXScale() const -> qreal { return m_xscale; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetXScale(const qreal &xscale) { Q_ASSERT(not isActive()); m_xscale = xscale; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetYScale() const -> qreal { return m_yscale; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetYScale(const qreal &yscale) { Q_ASSERT(not isActive()); m_yscale = yscale; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::SetBoundaryTogetherWithNotches(bool value) { Q_ASSERT(not isActive()); m_togetherWithNotches = value; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::IsBoundaryTogetherWithNotches() const -> bool { return m_togetherWithNotches; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::ErrorString() const -> QString { return QString::fromStdString(m_input->ErrorString()); } //--------------------------------------------------------------------------------------------------------------------- QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wswitch-default") auto VDxfEngine::FromPixel(double pix, const VarInsunits &unit) const -> double { switch (unit) { case VarInsunits::Millimeters: return pix / m_resolution * 25.4; case VarInsunits::Centimeters: return pix / m_resolution * 25.4 / 10.0; case VarInsunits::Inches: return pix / m_resolution; } return pix; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::ToPixel(double val, const VarInsunits &unit) const -> double { switch (unit) { case VarInsunits::Millimeters: return (val / 25.4) * m_resolution; case VarInsunits::Centimeters: return ((val * 10.0) / 25.4) * m_resolution; case VarInsunits::Inches: return val * m_resolution; } return val; } QT_WARNING_POP //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::ExportToAAMA(const QVector &details) -> bool { if (not m_size.isValid()) { qWarning() << "VDxfEngine::begin(), size is not valid"; return false; } m_input = QSharedPointer::create(GetFileNameForLocale(), m_version, m_varMeasurement, m_varInsunits); m_input->AddXSpaceBlock(false); m_input->AddAAMAHeaderData(); if (m_version > DRW::AC1009) { m_input->AddDefLayers(); } m_input->AddAAMALayers(); ExportStyleSystemText(m_input, details); for (auto detail : details) { // Use custom deleter function to lose ownership after adding the block bool deleteBlock = true; auto NoOpDeleter = [&deleteBlock](dx_ifaceBlock *block) { if (deleteBlock) { delete block; } }; auto detailBlock = QSharedPointer(new dx_ifaceBlock, NoOpDeleter); QString blockName = detail.GetName(); if (m_version <= DRW::AC1009) { blockName.replace(' '_L1, '_'_L1); } detailBlock->name = blockName.toStdString(); detailBlock->flags = 64; detailBlock->layer = *layer1; detail.Scale(m_xscale, m_yscale); ExportAAMAOutline(detailBlock, detail); ExportAAMADraw(detailBlock, detail); ExportAAMAIntcut(detailBlock, detail); ExportAAMANotch(detailBlock, detail); ExportAAMAGrainline(detailBlock, detail); ExportPieceText(detailBlock, detail); ExportAAMADrill(detailBlock, detail); ExportAnnotationText(detailBlock, detail, *layer19); m_input->AddBlock(detailBlock.data()); std::unique_ptr insert(new DRW_Insert()); insert->name = blockName.toStdString(); insert->layer = *layer1; m_input->AddEntity(insert.release()); deleteBlock = false; // lose ownership } return m_input->fileExport(m_binary); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMAOutline(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { QVector points = PieceOutline(detail); if (m_togetherWithNotches) { const QVector passmarks = detail.GetMappedPassmarks(); bool seamAllowance = detail.IsSeamAllowance() && !detail.IsSeamAllowanceBuiltIn(); bool builtInSeamAllowance = detail.IsSeamAllowance() && detail.IsSeamAllowanceBuiltIn(); VBoundary boundary(points, seamAllowance, builtInSeamAllowance); boundary.SetPieceName(detail.GetName()); if (detail.IsShowFullPiece() && !detail.GetMappedSeamAllowanceMirrorLine().isNull()) { boundary.SetMirrorLine(detail.GetMappedSeamAllowanceMirrorLine()); } const QList sequence = boundary.Combine(passmarks, false, false); points.clear(); for (const auto &item : sequence) { const auto path = item.item.value().Points(); points += path; } points = VAbstractPiece::RemoveDublicates(points, false); } if (DRW_Entity *e = AAMAPolygon(points, *layer1, true)) { detailBlock->ent.push_back(e); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMADraw(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { ExportAAMADrawSewLine(detailBlock, detail); ExportAAMADrawInternalPaths(detailBlock, detail); ExportAAMADrawPlaceLabels(detailBlock, detail); ExportAAMADrawFoldLine(detailBlock, detail); if (detail.IsShowFullPiece()) { const QLineF mirrorLine = detail.GetMappedSeamAllowanceMirrorLine(); if (not mirrorLine.isNull()) { if (DRW_Entity *e = AAMALine(mirrorLine, *layer8)) { e->lineType = dx_iface::QtPenStyleToString(Qt::DashDotLine); detailBlock->ent.push_back(e); } } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMADrawSewLine(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { if (detail.IsSeamAllowance() && not detail.IsHideMainPath() && not detail.IsSeamAllowanceBuiltIn()) { const UTF8STRING &layer = not detail.IsSewLineOnDrawing() ? *layer14 : *layer8; QVector points = detail.GetMappedFullContourPoints(); auto DrawPolygon = [this, detailBlock, layer](const QVector &points, bool forceClosed) { if (DRW_Entity *e = AAMAPolygon(points, layer, forceClosed)) { detailBlock->ent.push_back(e); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); }; if (m_togetherWithNotches) { const QVector passmarks = detail.GetMappedPassmarks(); bool seamAllowance = detail.IsSeamAllowance() && detail.IsSeamAllowanceBuiltIn(); bool builtInSeamAllowance = detail.IsSeamAllowance() && detail.IsSeamAllowanceBuiltIn(); VBoundary boundary(points, seamAllowance, builtInSeamAllowance); boundary.SetPieceName(detail.GetName()); if (detail.IsShowFullPiece() && !detail.GetMappedSeamAllowanceMirrorLine().isNull()) { boundary.SetMirrorLine(detail.GetMappedSeamAllowanceMirrorLine()); } const QList sequence = boundary.Combine(passmarks, true, false); for (const auto &item : sequence) { const auto path = item.item.value().Points(); DrawPolygon(path, false); } } else { DrawPolygon(points, true); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMADrawInternalPaths(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { auto DrawPolygon = [this, detailBlock](const QVector &points, Qt::PenStyle style, bool forceClosed) { if (DRW_Entity *e = AAMAPolygon(points, *layer8, forceClosed)) { e->lineType = dx_iface::QtPenStyleToString(style); detailBlock->ent.push_back(e); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); }; const QVector drawIPaths = detail.MappedInternalPathsForCut(false); for (const auto &iPath : drawIPaths) { QVector points = iPath.Points(); DrawPolygon(points, iPath.PenStyle(), false); if (!iPath.IsNotMirrored() && detail.IsShowFullPiece() && !detail.GetMappedSeamMirrorLine().isNull()) { const QTransform matrix = VGObject::FlippingMatrix(detail.GetMappedSeamMirrorLine()); std::transform(points.begin(), points.end(), points.begin(), [matrix](const VLayoutPoint &point) { return VAbstractPiece::MapPoint(point, matrix); }); DrawPolygon(points, iPath.PenStyle(), false); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMADrawPlaceLabels(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { auto DrawShape = [this, detailBlock](const PlaceLabelImg &shape, bool forceClosed) { for (const auto &points : shape) { if (DRW_Entity *e = AAMAPolygon(points, *layer8, forceClosed)) { detailBlock->ent.push_back(e); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); } }; const QVector labels = detail.GetPlaceLabels(); for (const auto &label : labels) { if (label.Type() != PlaceLabelType::Doubletree && label.Type() != PlaceLabelType::Button && label.Type() != PlaceLabelType::Circle) { DrawShape(detail.MapPlaceLabelShape(VAbstractPiece::PlaceLabelShape(label)), false); if (!label.IsNotMirrored() && detail.IsShowFullPiece() && !detail.GetMappedSeamMirrorLine().isNull()) { PlaceLabelImg shape = detail.MapPlaceLabelShape(VAbstractPiece::PlaceLabelShape(label)); const QTransform matrix = VGObject::FlippingMatrix(detail.GetMappedSeamMirrorLine()); for (auto &points : shape) { std::transform(points.begin(), points.end(), points.begin(), [matrix](const VLayoutPoint &point) { return VAbstractPiece::MapPoint(point, matrix); }); } DrawShape(shape, false); } } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMAIntcut(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { auto DrawPolygon = [this, detailBlock](const QVector &points, bool forceClosed) { if (DRW_Entity *e = AAMAPolygon(points, *layer11, forceClosed)) { detailBlock->ent.push_back(e); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); }; QVector drawIntCut = detail.MappedInternalPathsForCut(true); for (auto &intCut : drawIntCut) { QVector points = intCut.Points(); DrawPolygon(points, false); if (!intCut.IsNotMirrored() && detail.IsShowFullPiece() && !detail.GetMappedSeamMirrorLine().isNull()) { const QTransform matrix = VGObject::FlippingMatrix(detail.GetMappedSeamMirrorLine()); std::transform(points.begin(), points.end(), points.begin(), [matrix](const VLayoutPoint &point) { return VAbstractPiece::MapPoint(point, matrix); }); DrawPolygon(points, false); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMANotch(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { auto ExportNotch = [this, detailBlock](QPointF center, qreal length, qreal angle) { std::unique_ptr notch(new DRW_ASTMNotch()); notch->basePoint = DRW_Coord(FromPixel(center.x(), m_varInsunits), FromPixel(GetSize().height() - center.y(), m_varInsunits), FromPixel(length, m_varInsunits)); notch->angle = angle; notch->layer = *layer4; detailBlock->ent.push_back(notch.release()); }; if (detail.IsSeamAllowance() && !m_togetherWithNotches) { const QLineF mirrorLine = detail.GetMappedSeamMirrorLine(); const QVector passmarks = detail.GetMappedPassmarks(); for (const auto &passmark : passmarks) { ExportNotch(passmark.baseLine.p1(), passmark.baseLine.length(), passmark.baseLine.angle()); if (!mirrorLine.isNull() && detail.IsShowFullPiece()) { if (!VGObject::IsPointOnLineviaPDP(passmark.baseLine.p1(), mirrorLine.p1(), mirrorLine.p2())) { const QTransform matrix = VGObject::FlippingMatrix(mirrorLine); QLineF baseLine = matrix.map(passmark.baseLine); ExportNotch(baseLine.p1(), baseLine.length(), baseLine.angle()); } } } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMAGrainline(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { const QLineF grainlineMainLine = detail.GetMappedGrainlineMainLine(); if (not grainlineMainLine.isNull()) { if (DRW_Entity *e = AAMALine(grainlineMainLine, *layer7)) { detailBlock->ent.push_back(e); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportPieceText(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { QVector const labelShape = detail.GetPieceLabelRect(); if (labelShape.count() != 4) { return; } const qreal scale = qMin(detail.GetXScale(), detail.GetYScale()); const qreal dW = QLineF(labelShape.at(0), labelShape.at(1)).length(); const qreal dH = QLineF(labelShape.at(1), labelShape.at(2)).length(); const qreal angle = QLineF(labelShape.at(0), labelShape.at(1)).angle(); qreal dY = 0; VTextManager const tm = detail.GetPieceLabelData(); const QVector labelLines = tm.GetLabelSourceLines(qFloor(dW), tm.GetFont()); const int maxLineWidth = tm.MaxLineWidthOutlineFont(static_cast(dW)); for (const auto &tl : labelLines) { const QFont fnt = LineFont(tl, tm.GetFont()); QFontMetrics const fm(fnt); if (dY + fm.height() > dH) { break; } dY += fm.height(); const qreal dX = LineAlign(tl, tl.m_qsText, fm, dW); QTransform const lineMatrix = LineMatrix(detail, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth); QPointF const pos = lineMatrix.map(QPointF()); auto *textLine = new DRW_Text(); textLine->basePoint = DRW_Coord(FromPixel(pos.x(), m_varInsunits), FromPixel(GetSize().height() - pos.y(), m_varInsunits), 0); textLine->secPoint = DRW_Coord(FromPixel(pos.x(), m_varInsunits), FromPixel(GetSize().height() - pos.y(), m_varInsunits), 0); textLine->height = FromPixel(fm.ascent() * scale, m_varInsunits); textLine->layer = *layer1; textLine->text = tl.m_qsText.toStdString(); textLine->style = m_input->AddFont(fnt); if (detail.IsVerticallyFlipped() && detail.IsHorizontallyFlipped()) { textLine->angle = angle + 180; } else if (detail.IsVerticallyFlipped()) { textLine->angle = -angle; } else if (detail.IsHorizontallyFlipped()) { textLine->angle = -angle - 180; } else { textLine->angle = angle; } detailBlock->ent.push_back(textLine); dY += MmToPixel(1.5); } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAnnotationText(const QSharedPointer &detailBlock, const VLayoutPiece &detail, const UTF8STRING &layer) { VFoldLine const fLine = detail.FoldLine(); bool ok = false; FoldLabelPosData const labelData = fLine.LabelPosition(ok); if (not ok) { return; } QFontMetrics const fm(labelData.font); QPointF pos = labelData.pos; qreal const height = fm.height() * qMin(detail.GetXScale(), detail.GetYScale()); qreal const width = TextWidth(fm, labelData.label); QLineF base(pos, QPointF(pos.x() + 100, pos.y())); base.setAngle(base.angle() - 90); base.setLength(height); pos = base.p2(); QTransform matrix; if ((detail.IsVerticallyFlipped() && !detail.IsHorizontallyFlipped()) || (!detail.IsVerticallyFlipped() && detail.IsHorizontallyFlipped())) { matrix.translate(pos.x(), pos.y()); matrix.rotate(180); matrix.translate(-pos.x(), -pos.y()); matrix.translate(-width, fm.height()); } matrix *= detail.GetMatrix(); QLineF angleLine(QPointF(), QPointF(1000, 0)); angleLine.setAngle(labelData.angle); angleLine = matrix.map(angleLine); pos = matrix.map(pos); auto *text = new DRW_Text(); text->basePoint = DRW_Coord(FromPixel(pos.x(), m_varInsunits), FromPixel(GetSize().height() - pos.y(), m_varInsunits), 0); text->secPoint = DRW_Coord(FromPixel(pos.x(), m_varInsunits), FromPixel(GetSize().height() - pos.y(), m_varInsunits), 0); text->height = FromPixel(height, m_varInsunits); text->layer = layer; text->text = labelData.label.toStdString(); text->style = m_input->AddFont(labelData.font); text->angle = angleLine.angle(); detailBlock->ent.push_back(text); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportStyleSystemText(const QSharedPointer &input, const QVector &details) { for (const auto &detail : details) { const QStringList strings = detail.GetPatternText(); if (not strings.isEmpty()) { for (int j = 0; j < strings.size(); ++j) { const qreal height = ToPixel(AAMATextHeight * m_yscale, m_varInsunits); QPointF pos(0, GetSize().height() - height * (static_cast(strings.size()) - j - 1)); input->AddEntity(AAMAText(pos, strings.at(j), *layer1)); } return; } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMADrill(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { const QVector labels = detail.GetPlaceLabels(); for (const auto &label : labels) { if (label.Type() == PlaceLabelType::Doubletree || label.Type() == PlaceLabelType::Button || label.Type() == PlaceLabelType::Circle) { QPointF center = detail.GetMatrix().map(label.Center()); detailBlock->ent.push_back(AAMAPoint(center, *layer13)); if (!label.IsNotMirrored() && detail.IsShowFullPiece() && !detail.GetMappedSeamMirrorLine().isNull()) { const QTransform matrix = VGObject::FlippingMatrix(detail.GetMappedSeamMirrorLine()); center = VAbstractPiece::MapPoint(center, matrix); detailBlock->ent.push_back(AAMAPoint(center, *layer13)); } } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMADrawFoldLine(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { VFoldLine const fLine = detail.FoldLine(); QVector> points = fLine.FoldLineMarkPoints(); switch (detail.GetFoldLineType()) { case FoldLineType::TwoArrows: case FoldLineType::TwoArrowsTextAbove: case FoldLineType::TwoArrowsTextUnder: points.removeAt(1); AAMADrawFoldLineTwoArrows(points, detailBlock); break; case FoldLineType::ThreeDots: AAMADrawFoldLineThreeDots(points, detailBlock, fLine.ThreeDotsRadius()); break; case FoldLineType::ThreeX: AAMADrawFoldLineThreeX(points, detailBlock); break; case FoldLineType::LAST_ONE_DO_NOT_USE: Q_UNREACHABLE(); break; case FoldLineType::Text: case FoldLineType::None: default: break; }; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::ExportToASTM(const QVector &details) -> bool { if (not m_size.isValid()) { qWarning() << "VDxfEngine::begin(), size is not valid"; return false; } m_input = QSharedPointer(new dx_iface(GetFileNameForLocale(), m_version, m_varMeasurement, m_varInsunits)); m_input->AddXSpaceBlock(false); m_input->AddAAMAHeaderData(); if (m_version > DRW::AC1009) { m_input->AddDefLayers(); } m_input->AddASTMLayers(); ExportStyleSystemText(m_input, details); for (auto detail : details) { // Use custom deleter function to lose ownership after adding the block bool deleteBlock = true; auto NoOpDeleter = [&deleteBlock](dx_ifaceBlock *block) { if (deleteBlock) { delete block; } }; auto detailBlock = QSharedPointer(new dx_ifaceBlock, NoOpDeleter); QString blockName = detail.GetName(); if (m_version <= DRW::AC1009) { blockName.replace(' '_L1, '_'_L1); } detailBlock->name = blockName.toStdString(); detailBlock->layer = *layer1; detail.Scale(m_xscale, m_yscale); ExportASTMPieceBoundary(detailBlock, detail); ExportASTMSewLine(detailBlock, detail); ExportASTMDrawInternalPaths(detailBlock, detail); ExportASTMDrawPlaceLabels(detailBlock, detail); ExportASTMInternalCutout(detailBlock, detail); ExportASTMNotches(detailBlock, detail); ExportAAMAGrainline(detailBlock, detail); ExportPieceText(detailBlock, detail); ExportASTMDrill(detailBlock, detail); ExportASTMAnnotationText(detailBlock, detail); ExportASTMMirrorLine(detailBlock, detail); ExportASTMDrawFoldLine(detailBlock, detail); ExportAnnotationText(detailBlock, detail, *layer15); m_input->AddBlock(detailBlock.data()); std::unique_ptr insert(new DRW_Insert()); insert->name = blockName.toStdString(); insert->layer = *layer1; m_input->AddEntity(insert.release()); deleteBlock = false; // lose ownership } return m_input->fileExport(m_binary); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMPieceBoundary(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { QVector pieceBoundary = PieceOutline(detail); if (m_togetherWithNotches) { const QVector passmarks = detail.GetMappedPassmarks(); bool seamAllowance = detail.IsSeamAllowance() && !detail.IsSeamAllowanceBuiltIn(); bool builtInSeamAllowance = detail.IsSeamAllowance() && detail.IsSeamAllowanceBuiltIn(); VBoundary boundary(pieceBoundary, seamAllowance, builtInSeamAllowance); boundary.SetPieceName(detail.GetName()); if (detail.IsShowFullPiece() && !detail.GetMappedSeamAllowanceMirrorLine().isNull()) { boundary.SetMirrorLine(detail.GetMappedSeamAllowanceMirrorLine()); } const QList sequence = boundary.Combine(passmarks, false, false); pieceBoundary.clear(); for (const auto &item : sequence) { const auto path = item.item.value().Points(); pieceBoundary += path; } pieceBoundary = VAbstractPiece::RemoveDublicates(pieceBoundary, false); } // Piece boundary if (DRW_Entity *e = AAMAPolygon(pieceBoundary, *layer1, true)) { detailBlock->ent.push_back(e); } ExportTurnPoints(detailBlock, pieceBoundary); ExportCurvePoints(detailBlock, pieceBoundary); // Piece boundary quality validation curves if (DRW_Entity *q = AAMAPolygon(pieceBoundary, *layer84, true)) { detailBlock->ent.push_back(q); } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMSewLine(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { if (detail.IsSeamAllowance() && not detail.IsHideMainPath() && not detail.IsSeamAllowanceBuiltIn()) { QVector sewLine = detail.GetMappedFullContourPoints(); auto DrawPolygon = [this, detailBlock](const QVector &points, bool forceClosed) { // Sew lines if (DRW_Entity *e = AAMAPolygon(points, *layer14, forceClosed)) { detailBlock->ent.push_back(e); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); // Sew lines quality validation curves if (DRW_Entity *e = AAMAPolygon(points, *layer87, forceClosed)) { detailBlock->ent.push_back(e); } }; if (m_togetherWithNotches) { const QVector passmarks = detail.GetMappedPassmarks(); bool seamAllowance = detail.IsSeamAllowance() && detail.IsSeamAllowanceBuiltIn(); bool builtInSeamAllowance = detail.IsSeamAllowance() && detail.IsSeamAllowanceBuiltIn(); VBoundary boundary(sewLine, seamAllowance, builtInSeamAllowance); boundary.SetPieceName(detail.GetName()); if (detail.IsShowFullPiece() && !detail.GetMappedSeamAllowanceMirrorLine().isNull()) { boundary.SetMirrorLine(detail.GetMappedSeamAllowanceMirrorLine()); } const QList sequence = boundary.Combine(passmarks, true, false); for (const auto &item : sequence) { const auto path = item.item.value().Points(); DrawPolygon(path, false); } } else { DrawPolygon(sewLine, true); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMDrawInternalPaths(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { auto DrawPolygon = [this, detailBlock](const QVector &points, Qt::PenStyle style, bool notMirrored, bool forceClosed) { // Internal line if (DRW_Entity *e = AAMAPolygon(points, *layer8, forceClosed)) { e->lineType = dx_iface::QtPenStyleToString(style); detailBlock->ent.push_back(e); } if (notMirrored && !points.isEmpty()) { QPointF pos(points.constFirst().x(), points.constFirst().y() - ToPixel(AAMATextHeight, m_varInsunits)); detailBlock->ent.push_back(AAMAText(pos, QStringLiteral("NM"), *layer8)); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); // Internal lines quality validation curves if (DRW_Entity *e = AAMAPolygon(points, *layer85, forceClosed)) { detailBlock->ent.push_back(e); } }; const QVector drawIPaths = detail.MappedInternalPathsForCut(false); for (const auto &iPath : drawIPaths) { QVector points = iPath.Points(); DrawPolygon(points, iPath.PenStyle(), iPath.IsNotMirrored(), false); if (!iPath.IsNotMirrored() && detail.IsShowFullPiece() && !detail.GetMappedSeamMirrorLine().isNull()) { const QTransform matrix = VGObject::FlippingMatrix(detail.GetMappedSeamMirrorLine()); std::transform(points.begin(), points.end(), points.begin(), [matrix](const VLayoutPoint &point) { return VAbstractPiece::MapPoint(point, matrix); }); DrawPolygon(points, iPath.PenStyle(), iPath.IsNotMirrored(), false); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMDrawPlaceLabels(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { auto DrawShape = [this, detailBlock](const PlaceLabelImg &shape, bool notMirrored, bool forceClosed) { for (const auto &points : shape) { // Internal line (placelabel) if (DRW_Entity *e = AAMAPolygon(points, *layer8, forceClosed)) { detailBlock->ent.push_back(e); } if (notMirrored && !points.isEmpty()) { QPointF pos(points.constFirst().x(), points.constFirst().y() - ToPixel(AAMATextHeight, m_varInsunits)); detailBlock->ent.push_back(AAMAText(pos, QStringLiteral("NM"), *layer8)); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); // Internal lines quality validation curves if (DRW_Entity *e = AAMAPolygon(points, *layer85, false)) { detailBlock->ent.push_back(e); } } }; const QVector labels = detail.GetPlaceLabels(); for (const auto &label : labels) { if (label.Type() != PlaceLabelType::Doubletree && label.Type() != PlaceLabelType::Button && label.Type() != PlaceLabelType::Circle) { PlaceLabelImg shape = detail.MapPlaceLabelShape(VAbstractPiece::PlaceLabelShape(label)); DrawShape(shape, label.IsNotMirrored(), false); if (!label.IsNotMirrored() && detail.IsShowFullPiece() && !detail.GetMappedSeamMirrorLine().isNull()) { const QTransform matrix = VGObject::FlippingMatrix(detail.GetMappedSeamMirrorLine()); for (auto &points : shape) { std::transform(points.begin(), points.end(), points.begin(), [matrix](const VLayoutPoint &point) { return VAbstractPiece::MapPoint(point, matrix); }); } DrawShape(shape, label.IsNotMirrored(), false); } } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMInternalCutout(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { auto DrawPolygon = [this, detailBlock](const QVector &points, bool notMirrored, bool forceClosed) { // Internal cutout if (DRW_Entity *e = AAMAPolygon(points, *layer11, forceClosed)) { detailBlock->ent.push_back(e); } if (notMirrored && !points.isEmpty()) { QPointF pos(points.constFirst().x(), points.constFirst().y() - ToPixel(AAMATextHeight, m_varInsunits)); detailBlock->ent.push_back(AAMAText(pos, QStringLiteral("NM"), *layer11)); } ExportTurnPoints(detailBlock, points); ExportCurvePoints(detailBlock, points); // Internal cutouts quality validation curves if (DRW_Entity *e = AAMAPolygon(points, *layer86, forceClosed)) { detailBlock->ent.push_back(e); } }; QVector drawIntCut = detail.MappedInternalPathsForCut(true); for (auto &intCut : drawIntCut) { QVector points = intCut.Points(); DrawPolygon(points, intCut.IsNotMirrored(), false); if (!intCut.IsNotMirrored() && detail.IsShowFullPiece() && !detail.GetMappedSeamMirrorLine().isNull()) { const QTransform matrix = VGObject::FlippingMatrix(detail.GetMappedSeamMirrorLine()); std::transform(points.begin(), points.end(), points.begin(), [matrix](const VLayoutPoint &point) { return VAbstractPiece::MapPoint(point, matrix); }); DrawPolygon(points, intCut.IsNotMirrored(), false); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMAnnotationText(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { QString const name = detail.GetName(); QPointF const textPos = detail.VLayoutPiece::MappedDetailBoundingRect().center(); QPointF const pos(textPos.x(), textPos.y() - ToPixel(AAMATextHeight, m_varInsunits)); detailBlock->ent.push_back(AAMAText(pos, name, *layer15)); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMDrill(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { const QVector labels = detail.GetPlaceLabels(); auto ExportPoint = [this, detailBlock](QPointF center, qreal diameter) { std::unique_ptr point(new DRW_Point()); point->basePoint = DRW_Coord(FromPixel(center.x(), m_varInsunits), FromPixel(GetSize().height() - center.y(), m_varInsunits), FromPixel(diameter, m_varInsunits)); point->layer = *layer13; detailBlock->ent.push_back(point.release()); // TODO. Investigate drill category // QPointF pos(center.x(), center.y() - ToPixel(AAMATextHeight, m_varInsunits)); // detailBlock->ent.push_back(AAMAText(pos, category, *layer13)); }; for (const auto &label : labels) { if (label.Type() == PlaceLabelType::Doubletree || label.Type() == PlaceLabelType::Button || label.Type() == PlaceLabelType::Circle) { QPointF center = detail.GetMatrix().map(label.Center()); const QLineF diameter(label.Box().bottomLeft(), label.Box().topRight()); ExportPoint(center, diameter.length()); if (!label.IsNotMirrored() && detail.IsShowFullPiece() && !detail.GetMappedSeamMirrorLine().isNull()) { const QTransform matrix = VGObject::FlippingMatrix(detail.GetMappedSeamMirrorLine()); center = VAbstractPiece::MapPoint(center, matrix); ExportPoint(center, diameter.length()); } } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMNotches(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { if (!detail.IsSeamAllowance() || m_togetherWithNotches) { return; } auto ExportPassmark = [this, detailBlock, detail](const VLayoutPassmark &passmark) { DRW_ASTMNotch *notch = ExportASTMNotch(passmark); DRW_ATTDEF *attdef = ExportASTMNotchDataDependecy(passmark, notch->layer, detail); detailBlock->ent.push_back(notch); if (attdef != nullptr) { detailBlock->ent.push_back(attdef); } }; const QVector passmarks = detail.GetMappedPassmarks(); for (const auto &passmark : passmarks) { ExportPassmark(passmark); const QLineF mirrorLine = detail.GetMappedSeamMirrorLine(); if (!mirrorLine.isNull() && detail.IsShowFullPiece()) { if (!VGObject::IsPointOnLineviaPDP(passmark.baseLine.p1(), mirrorLine.p1(), mirrorLine.p2())) { const QTransform matrix = VGObject::FlippingMatrix(mirrorLine); const VLayoutPassmark mirroredPassmark = VLayoutPiece::MapPassmark(passmark, matrix, false); ExportPassmark(mirroredPassmark); } } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMMirrorLine(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { if (detail.IsShowFullPiece()) { const QLineF mirrorLine = detail.GetMappedSeamAllowanceMirrorLine(); if (not mirrorLine.isNull()) { if (DRW_Entity *e = AAMALine(mirrorLine, *layer6)) { e->lineType = dx_iface::QtPenStyleToString(Qt::DashDotLine); detailBlock->ent.push_back(e); } } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportASTMDrawFoldLine(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { VFoldLine const fLine = detail.FoldLine(); QVector> points = fLine.FoldLineMarkPoints(); switch (detail.GetFoldLineType()) { case FoldLineType::TwoArrows: case FoldLineType::TwoArrowsTextAbove: case FoldLineType::TwoArrowsTextUnder: points.removeAt(1); ASTMDrawFoldLineTwoArrows(points, detailBlock); break; case FoldLineType::ThreeDots: AAMADrawFoldLineThreeDots(points, detailBlock, fLine.ThreeDotsRadius()); break; case FoldLineType::ThreeX: AAMADrawFoldLineThreeX(points, detailBlock); break; case FoldLineType::LAST_ONE_DO_NOT_USE: Q_UNREACHABLE(); break; case FoldLineType::Text: case FoldLineType::None: default: break; }; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::ExportASTMNotch(const VLayoutPassmark &passmark) -> DRW_ASTMNotch * { auto *notch = new DRW_ASTMNotch(); const QPointF center = passmark.baseLine.p1(); notch->basePoint = DRW_Coord(FromPixel(center.x(), m_varInsunits), FromPixel(GetSize().height() - center.y(), m_varInsunits), FromPixel(passmark.baseLine.length(), m_varInsunits)); notch->angle = passmark.baseLine.angle(); switch (passmark.type) { case PassmarkLineType::OneLine: case PassmarkLineType::TwoLines: case PassmarkLineType::ThreeLines: // Slit notch notch->layer = *layer4; break; case PassmarkLineType::ExternalVMark: case PassmarkLineType::InternalVMark: { // V-Notch const QLineF boundaryLine(passmark.lines.constFirst().p1(), passmark.lines.constLast().p2()); notch->thickness = FromPixel(boundaryLine.length(), m_varInsunits); // width notch->layer = *layer4; break; } case PassmarkLineType::TMark: // T-Notch notch->thickness = FromPixel(passmark.lines.constLast().length(), m_varInsunits); // width notch->layer = *layer80; break; case PassmarkLineType::BoxMark: { // Castle Notch QPointF start = passmark.lines.constFirst().p1(); QPointF end = passmark.lines.constLast().p2(); notch->layer = *layer81; notch->thickness = FromPixel(QLineF(start, end).length(), m_varInsunits); // width break; } case PassmarkLineType::UMark: { // U-Notch QPointF start = passmark.lines.constFirst().p1(); QPointF end = passmark.lines.constLast().p2(); notch->thickness = FromPixel(QLineF(start, end).length(), m_varInsunits); // width notch->layer = *layer83; break; } case PassmarkLineType::CheckMark: { // Check Notch const QLineF &line1 = passmark.lines.constFirst(); const QLineF &line2 = passmark.lines.constLast(); qreal width = QLineF(line1.p1(), line2.p2()).length(); if (not passmark.isClockwiseOpening) { // a counter clockwise opening width *= -1; } notch->thickness = FromPixel(width, m_varInsunits); // width notch->layer = *layer82; break; } case PassmarkLineType::LAST_ONE_DO_NOT_USE: Q_UNREACHABLE(); break; default: break; }; return notch; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::ExportASTMNotchDataDependecy(const VLayoutPassmark &passmark, const UTF8STRING ¬chLayer, const VLayoutPiece &detail) -> DRW_ATTDEF * { QVector boundary = not detail.IsSeamAllowanceBuiltIn() && !passmark.isBuiltIn ? detail.GetMappedSeamAllowancePoints() : detail.GetMappedContourPoints(); const QPointF center = passmark.baseLine.p1(); QPointF referencePoint; if (not NotchPrecedingPoint(boundary, center, referencePoint)) { return nullptr; } auto *attdef = new DRW_ATTDEF(); attdef->layer = not detail.IsSeamAllowanceBuiltIn() && !passmark.isBuiltIn ? *layer1 : *layer14; attdef->basePoint = DRW_Coord(FromPixel(referencePoint.x(), m_varInsunits), FromPixel(GetSize().height() - referencePoint.y(), m_varInsunits), 0); attdef->adjustmentPoint = DRW_Coord(FromPixel(center.x(), m_varInsunits), FromPixel(GetSize().height() - center.y(), m_varInsunits), 0); attdef->height = 3.0; attdef->text = "Link:" + notchLayer; attdef->name = "Dependency"; attdef->flags = 2; // this is a constant attribute attdef->horizontalAdjustment = 3; // aligned (if vertical alignment = 0) return attdef; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportTurnPoints(const QSharedPointer &detailBlock, const QVector &points) const { for (const auto &p : qAsConst(points)) { if (p.TurnPoint()) { detailBlock->ent.push_back(AAMAPoint(p, *layer2)); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportCurvePoints(const QSharedPointer &detailBlock, const QVector &points) const { for (const auto &p : qAsConst(points)) { if (p.CurvePoint() && not p.TurnPoint()) { detailBlock->ent.push_back(AAMAPoint(p, *layer3)); } } } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::AAMAPolygon(const QVector &polygon, const UTF8STRING &layer, bool forceClosed) -> DRW_Entity * { if (polygon.isEmpty()) { return nullptr; } if (m_version > DRW::AC1009) { // Use lwpolyline return CreateAAMAPolygon(polygon, layer, forceClosed); } // Use polyline return CreateAAMAPolygon(polygon, layer, forceClosed); } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::AAMALine(const QLineF &line, const UTF8STRING &layer) -> DRW_Entity * { auto *lineEnt = new DRW_Line(); lineEnt->basePoint = DRW_Coord(FromPixel(line.p1().x(), m_varInsunits), FromPixel(GetSize().height() - line.p1().y(), m_varInsunits), 0); lineEnt->secPoint = DRW_Coord(FromPixel(line.p2().x(), m_varInsunits), FromPixel(GetSize().height() - line.p2().y(), m_varInsunits), 0); lineEnt->layer = layer; return lineEnt; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::AAMAText(const QPointF &pos, const QString &text, const UTF8STRING &layer) -> DRW_Entity * { auto *textLine = new DRW_Text(); textLine->basePoint = DRW_Coord(FromPixel(pos.x(), m_varInsunits), FromPixel(GetSize().height() - pos.y(), m_varInsunits), 0); textLine->secPoint = DRW_Coord(FromPixel(pos.x(), m_varInsunits), FromPixel(GetSize().height() - pos.y(), m_varInsunits), 0); textLine->height = AAMATextHeight; textLine->layer = layer; textLine->text = text.toStdString(); return textLine; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::AAMAPoint(const QPointF &pos, const UTF8STRING &layer) const -> DRW_Point * { auto *point = new DRW_Point(); point->basePoint = DRW_Coord(FromPixel(pos.x(), m_varInsunits), FromPixel(GetSize().height() - pos.y(), m_varInsunits), 0); point->layer = layer; return point; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::AAMACircle(const QPointF &pos, const std::string &layer, qreal radius) const -> DRW_Circle * { auto *circle = new DRW_Circle(); circle->basePoint = DRW_Coord(FromPixel(pos.x(), m_varInsunits), FromPixel(GetSize().height() - pos.y(), m_varInsunits), 0); circle->layer = layer; circle->radious = FromPixel(radius, m_varInsunits); return circle; } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::FromUnicodeToCodec(const QString &str, VTextCodec *codec) -> std::string { return codec->fromUnicode(str).toStdString(); } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::GetFileNameForLocale() const -> std::string { #if defined(Q_OS_WIN) return VDxfEngine::FromUnicodeToCodec(m_fileName, VTextCodec::codecForName("System")); #else return m_fileName.toStdString(); #endif } //--------------------------------------------------------------------------------------------------------------------- auto VDxfEngine::NotchPrecedingPoint(const QVector &boundary, QPointF notchBase, QPointF &point) -> bool { if (boundary.count() < 2) { return false; } if (VFuzzyComparePoints(boundary.constFirst(), notchBase)) { point = boundary.constFirst(); return true; } if (VFuzzyComparePoints(boundary.constLast(), notchBase)) { point = boundary.constLast(); return true; } QPointF candidatePoint; qreal bestDistance = INT_MAX; bool found = false; for (qint32 i = 0; i < boundary.count() - 1; ++i) { const QPointF cPoint = VGObject::ClosestPoint(QLineF(boundary.at(i), boundary.at(i + 1)), notchBase); if (VGObject::IsPointOnLineSegment(cPoint, boundary.at(i), boundary.at(i + 1))) { const qreal length = QLineF(notchBase, cPoint).length(); if (length < bestDistance) { candidatePoint = boundary.at(i); bestDistance = length; found = true; } } } if (found) { point = candidatePoint; return true; } return found; } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::AAMADrawFoldLineTwoArrows(const QVector> &points, const QSharedPointer &detailBlock) { QVector shape; for (const auto &subShape : points) { for (const auto &point : subShape) { VLayoutPoint p(point); p.SetTurnPoint(true); shape.append(p); } } if (DRW_Entity *e = AAMAPolygon(shape, *layer8, false)) { detailBlock->ent.push_back(e); } ExportTurnPoints(detailBlock, shape); } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::AAMADrawFoldLineThreeDots(const QVector> &points, const QSharedPointer &detailBlock, qreal radius) { if (points.isEmpty() || points.constFirst().size() != 3) { return; } QVector const &shape = points.constFirst(); for (const auto ¢er : shape) { if (DRW_Entity *e = AAMACircle(center, *layer8, radius)) { detailBlock->ent.push_back(e); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::AAMADrawFoldLineThreeX(const QVector> &points, const QSharedPointer &detailBlock) { if (points.isEmpty()) { return; } QVector const &shape = points.constFirst(); for (int i = 0; i < shape.size() - 1; i += 2) { if (DRW_Entity *e = AAMALine(QLineF(shape.at(i), shape.at(i + 1)), *layer8)) { detailBlock->ent.push_back(e); } } } //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ASTMDrawFoldLineTwoArrows(const QVector> &points, const QSharedPointer &detailBlock) { QVector shape; for (const auto &subShape : points) { for (const auto &point : subShape) { VLayoutPoint p(point); p.SetTurnPoint(true); shape.append(p); } } if (DRW_Entity *e = AAMAPolygon(shape, *layer8, false)) { detailBlock->ent.push_back(e); } if (!shape.isEmpty()) { QPointF const pos(shape.constFirst().x(), shape.constFirst().y() - ToPixel(AAMATextHeight, m_varInsunits)); detailBlock->ent.push_back(AAMAText(pos, QStringLiteral("NM"), *layer8)); } ExportTurnPoints(detailBlock, shape); if (DRW_Entity *e = AAMAPolygon(shape, *layer85, false)) { detailBlock->ent.push_back(e); } } //--------------------------------------------------------------------------------------------------------------------- template auto VDxfEngine::CreateAAMAPolygon(const QVector &polygon, const UTF8STRING &layer, bool forceClosed) -> P * { auto *poly = new P(); poly->layer = layer; if (forceClosed) { poly->flags |= 0x1; // closed NOLINT(hicpp-signed-bitwise) } else { if (polygon.size() > 1 && polygon.constFirst() == polygon.constLast()) { poly->flags |= 0x1; // closed NOLINT(hicpp-signed-bitwise) } } for (const auto &p : polygon) { poly->addVertex(V(FromPixel(p.x(), m_varInsunits), FromPixel(GetSize().height() - p.y(), m_varInsunits))); } return poly; }