From 1311c794c3966065a650aba4003b7703ff0cd301 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Tue, 2 May 2023 17:38:02 +0300 Subject: [PATCH] Improve handling four ways grainlines. --- src/app/puzzle/layout/vppiece.cpp | 145 ++--- src/app/puzzle/layout/vppiece.h | 6 +- src/app/puzzle/scene/vpgraphicspiece.cpp | 14 +- src/app/puzzle/xml/vplayoutfilereader.cpp | 79 ++- src/app/puzzle/xml/vplayoutfilewriter.cpp | 39 +- src/app/puzzle/xml/vplayoutfilewriter.h | 1 + src/app/puzzle/xml/vplayoutliterals.cpp | 19 +- src/app/puzzle/xml/vplayoutliterals.h | 17 +- src/app/valentina/mainwindowsnogui.cpp | 21 +- src/libs/ifc/schema.qrc | 1 + src/libs/ifc/schema/layout/v0.1.5.xsd | 579 ++++++++++++++++++ src/libs/ifc/schema/pattern/v0.9.2.xsd | 26 +- src/libs/ifc/xml/vdomdocument.h | 8 + src/libs/ifc/xml/vlayoutconverter.cpp | 133 +++- src/libs/ifc/xml/vlayoutconverter.h | 6 +- src/libs/vdxf/vdxfengine.cpp | 8 +- src/libs/vlayout/vabstractpiece.cpp | 86 +-- src/libs/vlayout/vabstractpiece.h | 4 +- src/libs/vlayout/vgraphicsfillitem.cpp | 7 + src/libs/vlayout/vgraphicsfillitem.h | 2 + src/libs/vlayout/vlayoutpiece.cpp | 165 +++-- src/libs/vlayout/vlayoutpiece.h | 21 +- src/libs/vlayout/vlayoutpiece_p.h | 66 +- src/libs/vlayout/vposition.cpp | 27 +- .../vpatterndb/floatItemData/floatitemdef.h | 19 +- .../tools/piece/dialogseamallowance.cpp | 37 +- src/libs/vtools/tools/vtoolseamallowance.cpp | 53 +- src/libs/vwidgets/vgrainlineitem.cpp | 399 +++++------- src/libs/vwidgets/vgrainlineitem.h | 74 ++- src/libs/vwidgets/vpiecegrainline.cpp | 449 ++++++++++++++ src/libs/vwidgets/vpiecegrainline.h | 98 +++ src/libs/vwidgets/vpiecegrainline_p.h | 125 ++++ src/libs/vwidgets/vwidgets.pri | 7 +- src/libs/vwidgets/vwidgets.qbs | 6 +- 34 files changed, 2040 insertions(+), 707 deletions(-) create mode 100644 src/libs/ifc/schema/layout/v0.1.5.xsd create mode 100644 src/libs/vwidgets/vpiecegrainline.cpp create mode 100644 src/libs/vwidgets/vpiecegrainline.h create mode 100644 src/libs/vwidgets/vpiecegrainline_p.h diff --git a/src/app/puzzle/layout/vppiece.cpp b/src/app/puzzle/layout/vppiece.cpp index 8a1997c43..b35072187 100644 --- a/src/app/puzzle/layout/vppiece.cpp +++ b/src/app/puzzle/layout/vppiece.cpp @@ -29,11 +29,13 @@ #include -#include "vpsheet.h" -#include "vplayout.h" -#include "../vlayout/vtextmanager.h" -#include "../vlayout/vlayoutpiecepath.h" #include "../vgeometry/vlayoutplacelabel.h" +#include "../vlayout/vlayoutpiecepath.h" +#include "../vlayout/vtextmanager.h" +#include "qline.h" +#include "vpiecegrainline.h" +#include "vplayout.h" +#include "vpsheet.h" #include #include @@ -154,12 +156,7 @@ void VPPiece::Update(const VPPiecePtr &piece) SetInternalPaths(piece->GetInternalPaths()); SetPassmarks(piece->GetPassmarks()); SetPlaceLabels(piece->GetPlaceLabels()); - - SetGrainlineEnabled(piece->IsGrainlineEnabled()); - SetGrainlineAngle(piece->GrainlineAngle()); - SetGrainlineArrowType(piece->GrainlineArrowType()); - SetGrainlinePoints(piece->GetGrainline()); - + SetGrainline(piece->GetGrainline()); SetPieceLabelRect(piece->GetPieceLabelRect()); SetPieceLabelData(piece->GetPieceLabelData()); SetPatternLabelRect(piece->GetPatternLabelRect()); @@ -225,112 +222,62 @@ void VPPiece::RotateToGrainline(const VPTransformationOrigon &origin) return; } - const QVector grainlinePoints = GetMappedGrainline(); - if (grainlinePoints.count() < 2) + const QLineF grainline = GetMappedGrainlineMainLine(); + if (grainline.isNull()) { return; } - QLineF grainline(ConstFirst(grainlinePoints), ConstLast(grainlinePoints)); - - QLineF canonical(ConstFirst(grainlinePoints).x(), ConstFirst(grainlinePoints).y(), - ConstFirst(grainlinePoints).x()+100, ConstFirst(grainlinePoints).y()); - - GrainlineType grainlineType = sheet->GrainlineOrientation(); - - auto DegreesAtFront = [grainline, canonical, grainlineType]() + QLineF fabricGrainline(grainline.p1().x(), grainline.p1().y(), grainline.p1().x() + 100, grainline.p1().y()); + if (sheet->GrainlineOrientation() == GrainlineType::Vertical) { - QLineF atFront = canonical; - if (grainlineType == GrainlineType::Vertical) - { - atFront.setAngle(90); - } + fabricGrainline.setAngle(fabricGrainline.angle() - 90); + } - qreal angleTo = grainline.angleTo(atFront); - return angleTo; - }; + QVector angles; + angles.reserve(4); - auto DegreesAtRear = [grainline, canonical, grainlineType]() + const VPieceGrainline pieceGrainline = GetGrainline(); + + if (pieceGrainline.IsArrowUpEnabled()) { - QLineF atRear = canonical; - atRear.setAngle(grainlineType == GrainlineType::Vertical ? 270 : 180); + angles.append(grainline.angleTo(fabricGrainline)); + } - qreal angleTo = grainline.angleTo(atRear); - return angleTo; - }; + if (pieceGrainline.IsArrowDownEnabled()) + { + QLineF arrow = grainline; + arrow.setAngle(arrow.angle() + 180); + angles.append(arrow.angleTo(fabricGrainline)); + } + + if (pieceGrainline.IsArrowLeftEnabled()) + { + QLineF arrow = grainline; + arrow.setAngle(arrow.angle() + 90); + angles.append(arrow.angleTo(fabricGrainline)); + } + + if (pieceGrainline.IsArrowRightEnabled()) + { + QLineF arrow = grainline; + arrow.setAngle(arrow.angle() - 90); + angles.append(arrow.angleTo(fabricGrainline)); + } - GrainlineArrowDirection type = GrainlineArrowType(); qreal degrees = 0; - - if (type == GrainlineArrowDirection::atFront) + if (not angles.isEmpty()) { - degrees = DegreesAtFront(); - } - else if (type == GrainlineArrowDirection::atRear) - { - degrees = DegreesAtRear(); - } - else if (type == GrainlineArrowDirection::atBoth) - { - const qreal atFront = DegreesAtFront(); - if (atFront <= 90 || atFront >= 270) - { - degrees = atFront; - } - else - { - degrees = DegreesAtRear(); - } - } - else - { - const qreal atFront = DegreesAtFront(); - if (atFront <= 45) - { - degrees = atFront; - } - else if (atFront > 45 && atFront < 90) - { - degrees = atFront - 90; - } - else - { - degrees = atFront - 90 * qFloor(atFront / 90); - } + degrees = *std::min_element(angles.constBegin(), angles.constEnd()); } - if (origin.custom) - { - Rotate(MappedDetailBoundingRect().center(), degrees); - } - else - { - Rotate(origin.origin, degrees); - } + Rotate(origin.custom ? MappedDetailBoundingRect().center() : origin.origin, degrees); } //--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetGrainlineEnabled(bool enabled) +void VPPiece::SetGrainline(const VPieceGrainline &grainline) { - VLayoutPiece::SetGrainlineEnabled(enabled); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetGrainlineAngle(qreal angle) -{ - VLayoutPiece::SetGrainlineAngle(angle); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetGrainlineArrowType(GrainlineArrowDirection type) -{ - VLayoutPiece::SetGrainlineArrowType(type); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetGrainlinePoints(const QVector &points) -{ - VLayoutPiece::SetGrainlinePoints(points); + VLayoutPiece::SetGrainline(grainline); } //--------------------------------------------------------------------------------------------------------------------- @@ -528,7 +475,7 @@ auto VPPiece::IsValid(QString &error) const -> bool return false; } - if (IsGrainlineEnabled() && GetGrainline().isEmpty()) + if (IsGrainlineEnabled() && not GetGrainline().IsShapeValid()) { error = tr("Grainline is empty"); return false; diff --git a/src/app/puzzle/layout/vppiece.h b/src/app/puzzle/layout/vppiece.h index 75ef5600a..8d111cc22 100644 --- a/src/app/puzzle/layout/vppiece.h +++ b/src/app/puzzle/layout/vppiece.h @@ -35,6 +35,7 @@ #include "../vlayout/vlayoutpiece.h" #include "../layout/layoutdef.h" +#include "vpiecegrainline.h" #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) #include "../vmisc/defglobal.h" @@ -92,10 +93,7 @@ public: auto Layout() const -> VPLayoutPtr; void SetLayout(const VPLayoutPtr &layout); - void SetGrainlineEnabled(bool enabled); - void SetGrainlineAngle(qreal angle); - void SetGrainlineArrowType(GrainlineArrowDirection type); - void SetGrainlinePoints(const QVector &points); + void SetGrainline(const VPieceGrainline &grainline); auto GetPieceLabelRect() const -> QVector; void SetPieceLabelRect(const QVector &rect); diff --git a/src/app/puzzle/scene/vpgraphicspiece.cpp b/src/app/puzzle/scene/vpgraphicspiece.cpp index 3cc8105a3..e57271997 100644 --- a/src/app/puzzle/scene/vpgraphicspiece.cpp +++ b/src/app/puzzle/scene/vpgraphicspiece.cpp @@ -54,6 +54,7 @@ #include "undocommands/vpundopiecemove.h" #include "undocommands/vpundomovepieceonsheet.h" +#include "vpiecegrainline.h" #include @@ -465,19 +466,8 @@ void VPGraphicsPiece::InitGrainlineItem() if(piece->IsGrainlineEnabled()) { - QPainterPath grainline; - QVector grainLinepoints = piece->GetMappedGrainline(); - if(!grainLinepoints.isEmpty()) - { - grainline.moveTo(ConstFirst(grainLinepoints)); - for (int i = 1; i < grainLinepoints.size(); i++) - { - grainline.lineTo(grainLinepoints.at(i)); - } - } - m_grainlineItem = new VGraphicsFillItem(this); - m_grainlineItem->setPath(grainline); + m_grainlineItem->setPath(VLayoutPiece::GrainlinePath(piece->GetMappedGrainlineShape())); VPSettings *settings = VPApplication::VApp()->PuzzleSettings(); QPen pen(PieceColor(), settings->GetLayoutLineWidth(), Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); diff --git a/src/app/puzzle/xml/vplayoutfilereader.cpp b/src/app/puzzle/xml/vplayoutfilereader.cpp index cae09b089..a0dedd518 100644 --- a/src/app/puzzle/xml/vplayoutfilereader.cpp +++ b/src/app/puzzle/xml/vplayoutfilereader.cpp @@ -30,6 +30,7 @@ #include #include #include +#include "vpiecegrainline.h" #include "vplayoutfilereader.h" #include "vplayoutliterals.h" #include "../layout/vpsheet.h" @@ -109,29 +110,60 @@ auto StringToPath(const QString &path) -> QVector //--------------------------------------------------------------------------------------------------------------------- auto StringToGrainlineArrowDirrection(const QString &dirrection) -> GrainlineArrowDirection { - const QStringList arrows - { - ML::atFrontStr, // 0 - ML::atRearStr, // 1 - ML::atFourWayStr, // 2 - ML::atBothStr // 3 + const QStringList arrows{ + ML::twoWaysUpDownStr, // 0 + ML::oneWayUpStr, // 1 + ML::oneWayDownStr, // 2 + ML::fourWaysStr, // 3 + ML::twoWaysUpLeftStr, // 4 + ML::twoWaysUpRightStr, // 5 + ML::twoWaysDownLeftStr, // 6 + ML::twoWaysDownRightStr, // 7 + ML::threeWaysUpDownLeftStr, // 8 + ML::threeWaysUpDownRightStr, // 9 + ML::threeWaysUpLeftRightStr, // 10 + ML::threeWaysDownLeftRightStr, // 11 }; - GrainlineArrowDirection arrowDirection = GrainlineArrowDirection::atBoth; + GrainlineArrowDirection arrowDirection = GrainlineArrowDirection::twoWaysUpDown; switch (arrows.indexOf(dirrection)) { - case 0:// at front - arrowDirection = GrainlineArrowDirection::atFront; + case 1: // oneWayUp + arrowDirection = GrainlineArrowDirection::oneWayUp; break; - case 1:// at rear - arrowDirection = GrainlineArrowDirection::atRear; + case 2: // oneWayDown + arrowDirection = GrainlineArrowDirection::oneWayDown; break; - case 2:// at four way - arrowDirection = GrainlineArrowDirection::atFourWay; + case 3: // fourWays + arrowDirection = GrainlineArrowDirection::fourWays; break; - case 3:// at both + case 4: // twoWaysUpLeft + arrowDirection = GrainlineArrowDirection::twoWaysUpLeft; + break; + case 5: // twoWaysUpRight + arrowDirection = GrainlineArrowDirection::twoWaysUpRight; + break; + case 6: // twoWaysDownLeft + arrowDirection = GrainlineArrowDirection::twoWaysDownLeft; + break; + case 7: // twoWaysDownRight + arrowDirection = GrainlineArrowDirection::twoWaysDownRight; + break; + case 8: // threeWaysUpDownLeft + arrowDirection = GrainlineArrowDirection::threeWaysUpDownLeft; + break; + case 9: // threeWaysUpDownRight + arrowDirection = GrainlineArrowDirection::threeWaysUpDownRight; + break; + case 10: // threeWaysUpLeftRight + arrowDirection = GrainlineArrowDirection::threeWaysUpLeftRight; + break; + case 11: // threeWaysDownLeftRight + arrowDirection = GrainlineArrowDirection::threeWaysDownLeftRight; + break; + case 0: // twoWaysUpDown default: - arrowDirection = GrainlineArrowDirection::atBoth; + arrowDirection = GrainlineArrowDirection::twoWaysUpDown; break; } return arrowDirection; @@ -600,23 +632,26 @@ void VPLayoutFileReader::ReadGrainline(const VPPiecePtr &piece) { AssertRootTag(ML::TagGrainline); + VPieceGrainline grainline; + QXmlStreamAttributes attribs = attributes(); bool enabled = ReadAttributeBool(attribs, ML::AttrEnabled, falseStr); - piece->SetGrainlineEnabled(enabled); - QVector path = StringToPath(readElementText()); + grainline.SetEnabled(enabled); + QLineF mainLine = StringToLine(readElementText()); if (enabled) { - piece->SetGrainlineAngle(ReadAttributeDouble(attribs, ML::AttrAngle, QChar('0'))); QString arrowDirection = ReadAttributeEmptyString(attribs, ML::AttrArrowDirection); - piece->SetGrainlineArrowType(StringToGrainlineArrowDirrection(arrowDirection)); + grainline.SetArrowType(StringToGrainlineArrowDirrection(arrowDirection)); - if (path.isEmpty()) + if (mainLine.isNull()) { - throw VException(tr("Error in line %1. Grainline is empty.").arg(lineNumber())); + throw VException(tr("Error in line %1. Grainline main line is empty.").arg(lineNumber())); } - piece->SetGrainlinePoints(path); + grainline.SetMainLine(mainLine); } + + piece->SetGrainline(grainline); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/xml/vplayoutfilewriter.cpp b/src/app/puzzle/xml/vplayoutfilewriter.cpp index e73cb913f..0771ff8f2 100644 --- a/src/app/puzzle/xml/vplayoutfilewriter.cpp +++ b/src/app/puzzle/xml/vplayoutfilewriter.cpp @@ -115,17 +115,33 @@ auto LinesToString(const QVector &lines) -> QString //--------------------------------------------------------------------------------------------------------------------- auto GrainlineArrowDirrectionToString(GrainlineArrowDirection type) -> QString { - switch(type) + switch (type) { - case GrainlineArrowDirection::atFront: - return ML::atFrontStr; - case GrainlineArrowDirection::atRear: - return ML::atRearStr; - case GrainlineArrowDirection::atFourWay: - return ML::atFourWayStr; - case GrainlineArrowDirection::atBoth: + case GrainlineArrowDirection::oneWayUp: + return ML::oneWayUpStr; + case GrainlineArrowDirection::oneWayDown: + return ML::oneWayDownStr; + case GrainlineArrowDirection::fourWays: + return ML::fourWaysStr; + case GrainlineArrowDirection::twoWaysUpLeft: + return ML::twoWaysUpLeftStr; + case GrainlineArrowDirection::twoWaysUpRight: + return ML::twoWaysUpRightStr; + case GrainlineArrowDirection::twoWaysDownLeft: + return ML::twoWaysDownLeftStr; + case GrainlineArrowDirection::twoWaysDownRight: + return ML::twoWaysDownRightStr; + case GrainlineArrowDirection::threeWaysUpDownLeft: + return ML::threeWaysUpDownLeftStr; + case GrainlineArrowDirection::threeWaysUpDownRight: + return ML::threeWaysUpDownRightStr; + case GrainlineArrowDirection::threeWaysUpLeftRight: + return ML::threeWaysUpLeftRightStr; + case GrainlineArrowDirection::threeWaysDownLeftRight: + return ML::threeWaysDownLeftRightStr; + case GrainlineArrowDirection::twoWaysUpDown: default: - return ML::atBothStr; + return ML::twoWaysUpDownStr; } } } // namespace @@ -304,9 +320,8 @@ void VPLayoutFileWriter::WritePiece(const VPPiecePtr &piece) [](bool enabled) noexcept {return not enabled;}); if (piece->IsGrainlineEnabled()) { - SetAttribute(ML::AttrAngle, piece->GrainlineAngle()); - SetAttribute(ML::AttrArrowDirection, GrainlineArrowDirrectionToString(piece->GrainlineArrowType())); - writeCharacters(PathToString(piece->GetGrainline())); + SetAttribute(ML::AttrArrowDirection, GrainlineArrowDirrectionToString(piece->GetGrainline().GetArrowType())); + writeCharacters(LineToString(piece->GetGrainlineMainLine())); } writeEndElement(); diff --git a/src/app/puzzle/xml/vplayoutfilewriter.h b/src/app/puzzle/xml/vplayoutfilewriter.h index 66bcb889f..03732c5f9 100644 --- a/src/app/puzzle/xml/vplayoutfilewriter.h +++ b/src/app/puzzle/xml/vplayoutfilewriter.h @@ -51,6 +51,7 @@ class VLayoutPoint; class VPLayoutFileWriter : public QXmlStreamWriter { Q_DECLARE_TR_FUNCTIONS(VPLayoutFileWriter) // NOLINT + public: VPLayoutFileWriter()= default; ~VPLayoutFileWriter()= default; diff --git a/src/app/puzzle/xml/vplayoutliterals.cpp b/src/app/puzzle/xml/vplayoutliterals.cpp index fbd1ea9ff..4748d90fd 100644 --- a/src/app/puzzle/xml/vplayoutliterals.cpp +++ b/src/app/puzzle/xml/vplayoutliterals.cpp @@ -85,7 +85,6 @@ const QString AttrTransform = QStringLiteral("transform"); // NOLINT( const QString AttrShowSeamline = QStringLiteral("showSeamline"); // NOLINT(cert-err58-cpp) const QString AttrEnabled = QStringLiteral("enabled"); // NOLINT(cert-err58-cpp) const QString AttrBuiltIn = QStringLiteral("builtIn"); // NOLINT(cert-err58-cpp) -const QString AttrAngle = QStringLiteral("angle"); // NOLINT(cert-err58-cpp) const QString AttrArrowDirection = QStringLiteral("arrowDirection"); // NOLINT(cert-err58-cpp) const QString AttrType = QStringLiteral("type"); // NOLINT(cert-err58-cpp) const QString AttrBaseLine = QStringLiteral("baseLine"); // NOLINT(cert-err58-cpp) @@ -115,12 +114,20 @@ const QString AttrY = QStringLiteral("y"); // NOLINT(cert-err const QString AttrTurnPoint = QStringLiteral("turnPoint"); // NOLINT(cert-err58-cpp) const QString AttrCurvePoint = QStringLiteral("curvePoint"); // NOLINT(cert-err58-cpp) -const QString atFrontStr = QStringLiteral("atFront"); // NOLINT(cert-err58-cpp) -const QString atRearStr = QStringLiteral("atRear"); // NOLINT(cert-err58-cpp) -const QString atFourWayStr = QStringLiteral("atFourWay"); // NOLINT(cert-err58-cpp) -const QString atBothStr = QStringLiteral("atBoth"); // NOLINT(cert-err58-cpp) +const QString oneWayUpStr = QStringLiteral("oneWayUp"); // NOLINT(cert-err58-cpp) +const QString oneWayDownStr = QStringLiteral("oneWayDown"); // NOLINT(cert-err58-cpp) +const QString fourWaysStr = QStringLiteral("fourWays"); // NOLINT(cert-err58-cpp) +const QString twoWaysUpDownStr = QStringLiteral("twoWaysUpDown"); // NOLINT(cert-err58-cpp) +const QString twoWaysUpLeftStr = QStringLiteral("twoWaysUpLeft"); // NOLINT(cert-err58-cpp) +const QString twoWaysUpRightStr = QStringLiteral("twoWaysUpRight"); // NOLINT(cert-err58-cpp) +const QString twoWaysDownLeftStr = QStringLiteral("twoWaysDownLeft"); // NOLINT(cert-err58-cpp) +const QString twoWaysDownRightStr = QStringLiteral("twoWaysDownRight"); // NOLINT(cert-err58-cpp) +const QString threeWaysUpDownLeftStr = QStringLiteral("threeWaysUpDownLeft"); // NOLINT(cert-err58-cpp) +const QString threeWaysUpDownRightStr = QStringLiteral("threeWaysUpDownRight"); // NOLINT(cert-err58-cpp) +const QString threeWaysUpLeftRightStr = QStringLiteral("threeWaysUpLeftRight"); // NOLINT(cert-err58-cpp) +const QString threeWaysDownLeftRightStr = QStringLiteral("threeWaysDownLeftRight"); // NOLINT(cert-err58-cpp) -const QChar groupSep = QLatin1Char(';'); +const QChar groupSep = QLatin1Char(';'); const QChar coordintatesSep = QLatin1Char(','); const QChar pointsSep = QLatin1Char(' '); const QChar itemsSep = QLatin1Char('*'); diff --git a/src/app/puzzle/xml/vplayoutliterals.h b/src/app/puzzle/xml/vplayoutliterals.h index e9cc450fa..750f81ccd 100644 --- a/src/app/puzzle/xml/vplayoutliterals.h +++ b/src/app/puzzle/xml/vplayoutliterals.h @@ -90,7 +90,6 @@ extern const QString AttrTransform; extern const QString AttrShowSeamline; extern const QString AttrEnabled; extern const QString AttrBuiltIn; -extern const QString AttrAngle; extern const QString AttrArrowDirection; extern const QString AttrType; extern const QString AttrBaseLine; @@ -120,10 +119,18 @@ extern const QString AttrY; extern const QString AttrTurnPoint; extern const QString AttrCurvePoint; -extern const QString atFrontStr; -extern const QString atRearStr; -extern const QString atFourWayStr; -extern const QString atBothStr; +extern const QString oneWayUpStr; +extern const QString oneWayDownStr; +extern const QString fourWaysStr; +extern const QString twoWaysUpDownStr; +extern const QString twoWaysUpLeftStr; +extern const QString twoWaysUpRightStr; +extern const QString twoWaysDownLeftStr; +extern const QString twoWaysDownRightStr; +extern const QString threeWaysUpDownLeftStr; +extern const QString threeWaysUpDownRightStr; +extern const QString threeWaysUpLeftRightStr; +extern const QString threeWaysDownLeftRightStr; extern const QChar groupSep; extern const QChar coordintatesSep; diff --git a/src/app/valentina/mainwindowsnogui.cpp b/src/app/valentina/mainwindowsnogui.cpp index 860d5c9b0..aa8b05e0f 100644 --- a/src/app/valentina/mainwindowsnogui.cpp +++ b/src/app/valentina/mainwindowsnogui.cpp @@ -1138,23 +1138,23 @@ void MainWindowsNoGUI::ExportScene(const QList &scenes, exporter.SetFileName(name); exporter.SetImageRect(paper->rect()); + QPen defaultPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(), Qt::SolidLine, + Qt::RoundCap, Qt::RoundJoin); + switch (m_dialogSaveLayout->Format()) { case LayoutExportFormats::SVG: paper->setVisible(false); - exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(), - Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + exporter.SetPen(defaultPen); exporter.ExportToSVG(scene, details.at(i)); paper->setVisible(true); break; case LayoutExportFormats::PDF: - exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(), - Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + exporter.SetPen(defaultPen); exporter.ExportToPDF(scene, details.at(i)); break; case LayoutExportFormats::PNG: - exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(), - Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + exporter.SetPen(defaultPen); exporter.ExportToPNG(scene, details.at(i)); break; case LayoutExportFormats::OBJ: @@ -1163,13 +1163,11 @@ void MainWindowsNoGUI::ExportScene(const QList &scenes, paper->setVisible(true); break; case LayoutExportFormats::PS: - exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(), - Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + exporter.SetPen(defaultPen); exporter.ExportToPS(scene, details.at(i)); break; case LayoutExportFormats::EPS: - exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(), - Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + exporter.SetPen(defaultPen); exporter.ExportToEPS(scene, details.at(i)); break; case LayoutExportFormats::DXF_AC1006_Flat: @@ -1227,8 +1225,7 @@ void MainWindowsNoGUI::ExportScene(const QList &scenes, paper->setVisible(true); break; case LayoutExportFormats::TIF: - exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(), - Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + exporter.SetPen(defaultPen); exporter.ExportToTIF(scene, details.at(i)); break; default: diff --git a/src/libs/ifc/schema.qrc b/src/libs/ifc/schema.qrc index c4ec8f211..ace77acdc 100644 --- a/src/libs/ifc/schema.qrc +++ b/src/libs/ifc/schema.qrc @@ -96,5 +96,6 @@ schema/layout/v0.1.2.xsd schema/layout/v0.1.3.xsd schema/layout/v0.1.4.xsd + schema/layout/v0.1.5.xsd diff --git a/src/libs/ifc/schema/layout/v0.1.5.xsd b/src/libs/ifc/schema/layout/v0.1.5.xsd new file mode 100644 index 000000000..6c512804b --- /dev/null +++ b/src/libs/ifc/schema/layout/v0.1.5.xsd @@ -0,0 +1,579 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/ifc/schema/pattern/v0.9.2.xsd b/src/libs/ifc/schema/pattern/v0.9.2.xsd index 39e92a10c..b20abf52a 100644 --- a/src/libs/ifc/schema/pattern/v0.9.2.xsd +++ b/src/libs/ifc/schema/pattern/v0.9.2.xsd @@ -946,15 +946,31 @@ - + - + - + - + - + + + + + + + + + + + + + + + + + diff --git a/src/libs/ifc/xml/vdomdocument.h b/src/libs/ifc/xml/vdomdocument.h index 6e5eb3e09..546b3e912 100644 --- a/src/libs/ifc/xml/vdomdocument.h +++ b/src/libs/ifc/xml/vdomdocument.h @@ -196,6 +196,14 @@ inline void VDomDocument::SetAttribute(QDomElement &domElement, const Q domElement.setAttribute(name, value); } +//--------------------------------------------------------------------------------------------------------------------- +template <> +inline void VDomDocument::SetAttribute(QDomElement &domElement, const QString &name, + const QLatin1String &value) const +{ + domElement.setAttribute(name, value); +} + //--------------------------------------------------------------------------------------------------------------------- template <> inline void VDomDocument::SetAttribute(QDomElement &domElement, const QString &name, const QChar &value) const diff --git a/src/libs/ifc/xml/vlayoutconverter.cpp b/src/libs/ifc/xml/vlayoutconverter.cpp index b7dc8d2dd..9ec637a6b 100644 --- a/src/libs/ifc/xml/vlayoutconverter.cpp +++ b/src/libs/ifc/xml/vlayoutconverter.cpp @@ -29,6 +29,8 @@ #include "../exception/vexception.h" #include "../ifcdef.h" #include "../vlayout/vlayoutpoint.h" +#include "compatibility.h" +#include "vpatterndb/floatItemData/floatitemdef.h" /* * Version rules: @@ -39,8 +41,8 @@ */ const QString VLayoutConverter::LayoutMinVerStr = QStringLiteral("0.1.0"); -const QString VLayoutConverter::LayoutMaxVerStr = QStringLiteral("0.1.4"); -const QString VLayoutConverter::CurrentSchema = QStringLiteral("://schema/layout/v0.1.4.xsd"); +const QString VLayoutConverter::LayoutMaxVerStr = QStringLiteral("0.1.5"); +const QString VLayoutConverter::CurrentSchema = QStringLiteral("://schema/layout/v0.1.5.xsd"); //VLayoutConverter::LayoutMinVer; // <== DON'T FORGET TO UPDATE TOO!!!! //VLayoutConverter::LayoutMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!! @@ -55,14 +57,17 @@ Q_GLOBAL_STATIC_WITH_ARGS(const QString, strInternalPathTag, (QLatin1String("int Q_GLOBAL_STATIC_WITH_ARGS(const QString, strMarkerTag, (QLatin1String("marker"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, strPointTag, (QLatin1String("point"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, strPieceTag, (QLatin1String("piece"))) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, strGrainlineTag, (QLatin1String("grainline"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrX, (QLatin1String("x"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrY, (QLatin1String("y"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrTurnPoint, (QLatin1String("turnPoint"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrCurvePoint, (QLatin1String("curvePoint"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrId, (QLatin1String("id"))) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrUId, (QLatin1String("uid"))) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrAngle, (QLatin1String("angle"))) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrArrowDirection, (QLatin1String("arrowDirection"))) // NOLINT -//const QChar groupSep = QLatin1Char(';'); +const QChar groupSep = QLatin1Char(';'); const QChar coordintatesSep = QLatin1Char(','); const QChar pointsSep = QLatin1Char(' '); //const QChar itemsSep = QLatin1Char('*'); @@ -92,6 +97,13 @@ auto StringV0_1_2ToPath(const QString &path) -> QVector return p; } + +//--------------------------------------------------------------------------------------------------------------------- +template auto NumberToString(T number) -> QString +{ + const QLocale locale = QLocale::c(); + return locale.toString(number, 'g', 12).remove(LocaleGroupSeparator(locale)); +} } // namespace //--------------------------------------------------------------------------------------------------------------------- @@ -120,13 +132,13 @@ auto VLayoutConverter::GetFormatVersionStr() const -> QString //--------------------------------------------------------------------------------------------------------------------- auto VLayoutConverter::XSDSchemas() -> QHash { - static auto schemas = QHash - { + static auto schemas = QHash{ std::make_pair(FormatVersion(0, 1, 0), QStringLiteral("://schema/layout/v0.1.0.xsd")), std::make_pair(FormatVersion(0, 1, 1), QStringLiteral("://schema/layout/v0.1.1.xsd")), std::make_pair(FormatVersion(0, 1, 2), QStringLiteral("://schema/layout/v0.1.2.xsd")), std::make_pair(FormatVersion(0, 1, 3), QStringLiteral("://schema/layout/v0.1.3.xsd")), - std::make_pair(FormatVersion(0, 1, 4), CurrentSchema), + std::make_pair(FormatVersion(0, 1, 4), QStringLiteral("://schema/layout/v0.1.4.xsd")), + std::make_pair(FormatVersion(0, 1, 5), CurrentSchema), }; return schemas; @@ -159,10 +171,11 @@ void VLayoutConverter::ApplyPatches() ToV0_1_3(); Q_FALLTHROUGH(); case (FormatVersion(0, 1, 3)): - ToV0_1_4(); + case (FormatVersion(0, 1, 4)): + ToV0_1_5(); ValidateXML(CurrentSchema); Q_FALLTHROUGH(); - case (FormatVersion(0, 1, 4)): + case (FormatVersion(0, 1, 5)): break; default: InvalidVersion(m_ver); @@ -264,6 +277,100 @@ void VLayoutConverter::ConvertPathToV0_1_3(QDomElement &node) } } +//--------------------------------------------------------------------------------------------------------------------- +void VLayoutConverter::ConvertPiecesToV0_1_5() +{ + // TODO. Delete if minimal supported version is 0.1.5 + Q_STATIC_ASSERT_X(VLayoutConverter::LayoutMinVer < FormatVersion(0, 1, 5), "Time to refactor the code."); + + QDomNodeList grainlineTags = elementsByTagName(*strGrainlineTag); + for (int i = 0; i < grainlineTags.size(); ++i) + { + QDomElement node = grainlineTags.at(i).toElement(); + if (node.isElement()) + { + // remove angle attribute + if (node.hasAttribute(*strAttrAngle)) + { + node.removeAttribute(*strAttrAngle); + } + + // convert arrowDirection + if (node.hasAttribute(*strAttrArrowDirection)) + { + QString arrowDirection = node.attribute(*strAttrArrowDirection); + + const QStringList arrows{ + "atFront", // 0 + "atRear", // 1 + "atFourWay", // 2 + "atBoth" // 3 + }; + + switch (arrows.indexOf(arrowDirection)) + { + case 0: // at front + SetAttribute(node, *strAttrArrowDirection, QLatin1String("oneWayUp")); + break; + case 1: // at rear + SetAttribute(node, *strAttrArrowDirection, QLatin1String("oneWayDown")); + break; + case 2: // at four way + SetAttribute(node, *strAttrArrowDirection, QLatin1String("fourWays")); + break; + case 3: // at both + default: + SetAttribute(node, *strAttrArrowDirection, QLatin1String("twoWaysUpDown")); + break; + } + } + + auto StringToPath = [](const QString &path) -> QVector + { + auto StringToPoint = [](const QString &point) -> QPointF + { + QStringList coordinates = point.split(coordintatesSep); + if (coordinates.count() == 2) + { + return {coordinates.at(0).toDouble(), coordinates.at(1).toDouble()}; + } + + return {}; + }; + + QVector p; + if (path.isEmpty()) + { + return p; + } + + QStringList points = path.split(pointsSep); + p.reserve(points.size()); + for (const auto &point : points) + { + p.append(StringToPoint(point)); + } + + return p; + }; + + const QVector path = StringToPath(node.text()); + if (not path.isEmpty()) + { + auto LineToString = [](const QLineF &line) -> QString + { + auto PointToString = [](const QPointF &p) -> QString + { return NumberToString(p.x()) + coordintatesSep + NumberToString(p.y()); }; + + return PointToString(line.p1()) + groupSep + PointToString(line.p2()); + }; + + node.firstChild().toText().setData(LineToString(QLineF(ConstFirst(path), ConstLast(path)))); + } + } + } +} + //--------------------------------------------------------------------------------------------------------------------- void VLayoutConverter::ToV0_1_3() { @@ -277,11 +384,11 @@ void VLayoutConverter::ToV0_1_3() } //--------------------------------------------------------------------------------------------------------------------- -void VLayoutConverter::ToV0_1_4() +void VLayoutConverter::ToV0_1_5() { - // TODO. Delete if minimal supported version is 0.1.4 - Q_STATIC_ASSERT_X(VLayoutConverter::LayoutMinVer < FormatVersion(0, 1, 4), - "Time to refactor the code."); - SetVersion(QStringLiteral("0.1.4")); + // TODO. Delete if minimal supported version is 0.1.5 + Q_STATIC_ASSERT_X(VLayoutConverter::LayoutMinVer < FormatVersion(0, 1, 5), "Time to refactor the code."); + ConvertPiecesToV0_1_5(); + SetVersion(QStringLiteral("0.1.5")); Save(); } diff --git a/src/libs/ifc/xml/vlayoutconverter.h b/src/libs/ifc/xml/vlayoutconverter.h index 604af5289..51cdc2345 100644 --- a/src/libs/ifc/xml/vlayoutconverter.h +++ b/src/libs/ifc/xml/vlayoutconverter.h @@ -46,7 +46,7 @@ public: static const QString LayoutMaxVerStr; static const QString CurrentSchema; static Q_DECL_CONSTEXPR const unsigned LayoutMinVer = FormatVersion(0, 1, 0); - static Q_DECL_CONSTEXPR const unsigned LayoutMaxVer = FormatVersion(0, 1, 4); + static Q_DECL_CONSTEXPR const unsigned LayoutMaxVer = FormatVersion(0, 1, 5); static auto XSDSchemas() -> QHash ; @@ -69,8 +69,10 @@ protected: void ConvertPiecesToV0_1_3(); void ConvertPathToV0_1_3(QDomElement &node); + void ConvertPiecesToV0_1_5(); + void ToV0_1_3(); - void ToV0_1_4(); + void ToV0_1_5(); private: Q_DISABLE_COPY_MOVE(VLayoutConverter) // NOLINT diff --git a/src/libs/vdxf/vdxfengine.cpp b/src/libs/vdxf/vdxfengine.cpp index 3ab383328..ba3d1c5f8 100644 --- a/src/libs/vdxf/vdxfengine.cpp +++ b/src/libs/vdxf/vdxfengine.cpp @@ -27,8 +27,8 @@ *************************************************************************/ #include "vdxfengine.h" - #include + #include #include #include @@ -866,10 +866,10 @@ void VDxfEngine::ExportAAMANotch(const QSharedPointer &detailBloc //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::ExportAAMAGrainline(const QSharedPointer &detailBlock, const VLayoutPiece &detail) { - const QVector grainline = detail.GetMappedGrainline(); - if (grainline.count() > 1) + const QLineF grainlineMainLine = detail.GetMappedGrainlineMainLine(); + if (not grainlineMainLine.isNull()) { - if (DRW_Entity *e = AAMALine(QLineF(ConstFirst(grainline), ConstLast(grainline)), *layer7)) + if (DRW_Entity *e = AAMALine(grainlineMainLine, *layer7)) { detailBlock->ent.push_back(e); } diff --git a/src/libs/vlayout/vabstractpiece.cpp b/src/libs/vlayout/vabstractpiece.cpp index b3960cf31..20ea45bdb 100644 --- a/src/libs/vlayout/vabstractpiece.cpp +++ b/src/libs/vlayout/vabstractpiece.cpp @@ -27,6 +27,8 @@ *************************************************************************/ #include "vabstractpiece.h" +#include "qline.h" +#include "qmath.h" #include "vabstractpiece_p.h" #include "../vmisc/vabstractvalapplication.h" #include "../vgeometry/vpointf.h" @@ -37,7 +39,7 @@ #include "../vpatterndb/floatItemData/vgrainlinedata.h" #include "../vpatterndb/vcontainer.h" #include "../vpatterndb/calculator.h" -#include "testpath.h" +#include "../vwidgets/vpiecegrainline.h" #include "vrawsapoint.h" #include @@ -1603,7 +1605,6 @@ auto VAbstractPiece::RollbackSeamAllowance(QVector points, const QL return points; } - //--------------------------------------------------------------------------------------------------------------------- auto VAbstractPiece::IsItemContained(const QRectF &parentBoundingRect, const QVector &shape, qreal &dX, qreal &dY) -> bool @@ -1749,81 +1750,48 @@ auto VAbstractPiece::FindGrainlineGeometry(const VGrainlineData& geom, const VCo } //--------------------------------------------------------------------------------------------------------------------- -auto VAbstractPiece::GrainlinePoints(const VGrainlineData &geom, const VContainer *pattern, const QRectF &boundingRect, - qreal &dAng) -> QVector +auto VAbstractPiece::GrainlineMainLine(const VGrainlineData &geom, const VContainer *pattern, + const QRectF &boundingRect) -> QLineF { SCASSERT(pattern != nullptr) QPointF pt1; qreal dLen = 0; - if ( not FindGrainlineGeometry(geom, pattern, dLen, dAng, pt1)) + qreal dAng = 0; + if (not FindGrainlineGeometry(geom, pattern, dLen, dAng, pt1)) { return {}; } - qreal rotation = dAng; + QPointF pt2(pt1.x() + dLen * qCos(dAng), pt1.y() - dLen * qSin(dAng)); - QPointF pt2(pt1.x() + dLen * qCos(rotation), pt1.y() - dLen * qSin(rotation)); - - const qreal dArrowLen = ToPixel(0.5, *pattern->GetPatternUnit()); - const qreal dArrowAng = M_PI/9; + VPieceGrainline grainline(QLineF(pt1, pt2), geom.GetArrowType()); QVector v; - v << pt1; - - if (geom.GetArrowType() != GrainlineArrowDirection::atFront) + if (grainline.IsFourWays()) { - v << QPointF(pt1.x() + dArrowLen * qCos(rotation + dArrowAng), - pt1.y() - dArrowLen * qSin(rotation + dArrowAng)); - v << QPointF(pt1.x() + dArrowLen * qCos(rotation - dArrowAng), - pt1.y() - dArrowLen * qSin(rotation - dArrowAng)); - v << pt1; - - if (geom.GetArrowType() == GrainlineArrowDirection::atFourWay) - { // second double arrow - QLineF line(pt2, pt1); - line.setLength(line.length() - dArrowLen - dArrowLen*0.5); - - v << line.p2(); - v << QPointF(line.p2().x() + dArrowLen * qCos(rotation + dArrowAng), - line.p2().y() - dArrowLen * qSin(rotation + dArrowAng)); - v << QPointF(line.p2().x() + dArrowLen * qCos(rotation - dArrowAng), - line.p2().y() - dArrowLen * qSin(rotation - dArrowAng)); - v << line.p2(); - } + QLineF mainLine = grainline.GetMainLine(); + QLineF secondaryLine = grainline.SecondaryLine(); + v = {mainLine.p1(), mainLine.p2(), secondaryLine.p1(), secondaryLine.p2()}; + } + else + { + QLineF mainLine = grainline.GetMainLine(); + v = {mainLine.p1(), mainLine.p2()}; } - if (geom.GetArrowType() != GrainlineArrowDirection::atFourWay) + qreal dX = 0; + qreal dY = 0; + if (not IsItemContained(boundingRect, v, dX, dY)) { - v << pt2; + pt1.rx() = + dX; + pt1.ry() = + dY; + + pt2.rx() = + dX; + pt2.ry() = + dY; } - if (geom.GetArrowType() != GrainlineArrowDirection::atRear) - { - rotation += M_PI; - - if (geom.GetArrowType() == GrainlineArrowDirection::atFourWay) - { // first double arrow - QLineF line(pt1, pt2); - line.setLength(line.length() - dArrowLen - dArrowLen*0.5); - - v << line.p2(); - v << QPointF(line.p2().x() + dArrowLen * qCos(rotation + dArrowAng), - line.p2().y() - dArrowLen * qSin(rotation + dArrowAng)); - v << QPointF(line.p2().x() + dArrowLen * qCos(rotation - dArrowAng), - line.p2().y() - dArrowLen * qSin(rotation - dArrowAng)); - v << line.p2(); - v << pt2; - } - - v << QPointF(pt2.x() + dArrowLen * qCos(rotation + dArrowAng), - pt2.y() - dArrowLen * qSin(rotation + dArrowAng)); - v << QPointF(pt2.x() + dArrowLen * qCos(rotation - dArrowAng), - pt2.y() - dArrowLen * qSin(rotation - dArrowAng)); - v << pt2; - } - - return CorrectPosition(boundingRect, v); + return {pt1, pt2}; } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vlayout/vabstractpiece.h b/src/libs/vlayout/vabstractpiece.h index 4661e799a..639453405 100644 --- a/src/libs/vlayout/vabstractpiece.h +++ b/src/libs/vlayout/vabstractpiece.h @@ -126,8 +126,8 @@ public: static auto RollbackSeamAllowance(QVector points, const QLineF &cuttingEdge, bool *success) -> QVector; - static auto GrainlinePoints(const VGrainlineData &geom, const VContainer *pattern, - const QRectF &boundingRect, qreal &dAng) -> QVector; + static auto GrainlineMainLine(const VGrainlineData &geom, const VContainer *pattern, + const QRectF &boundingRect) -> QLineF; friend auto operator<< (QDataStream& dataStream, const VAbstractPiece& piece) -> QDataStream&; friend auto operator>> (QDataStream& dataStream, VAbstractPiece& piece) -> QDataStream&; diff --git a/src/libs/vlayout/vgraphicsfillitem.cpp b/src/libs/vlayout/vgraphicsfillitem.cpp index 8520c2a1f..af66f2ec3 100644 --- a/src/libs/vlayout/vgraphicsfillitem.cpp +++ b/src/libs/vlayout/vgraphicsfillitem.cpp @@ -33,6 +33,11 @@ VGraphicsFillItem::VGraphicsFillItem(QGraphicsItem *parent) :QGraphicsPathItem(parent) {} +//--------------------------------------------------------------------------------------------------------------------- +VGraphicsFillItem::VGraphicsFillItem(const QPainterPath &path, QGraphicsItem *parent) + :QGraphicsPathItem(path, parent) +{} + //--------------------------------------------------------------------------------------------------------------------- VGraphicsFillItem::~VGraphicsFillItem() {} @@ -54,6 +59,8 @@ void VGraphicsFillItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* { pen = painter->pen(); pen.setWidthF(width); + pen.setCapStyle(Qt::RoundCap); + pen.setJoinStyle(Qt::RoundJoin); } painter->setPen(pen); diff --git a/src/libs/vlayout/vgraphicsfillitem.h b/src/libs/vlayout/vgraphicsfillitem.h index 5a70231a9..f6511f461 100644 --- a/src/libs/vlayout/vgraphicsfillitem.h +++ b/src/libs/vlayout/vgraphicsfillitem.h @@ -41,6 +41,8 @@ public: * @brief VGraphicsFillItem Constructor */ explicit VGraphicsFillItem(QGraphicsItem *parent = nullptr); + + VGraphicsFillItem(const QPainterPath &path, QGraphicsItem *parent = nullptr); /** * @brief ~VGraphicsFillItem Destructor */ diff --git a/src/libs/vlayout/vlayoutpiece.cpp b/src/libs/vlayout/vlayoutpiece.cpp index 9de02d710..fa6c430f7 100644 --- a/src/libs/vlayout/vlayoutpiece.cpp +++ b/src/libs/vlayout/vlayoutpiece.cpp @@ -46,23 +46,27 @@ #include #include -#include "../vpatterndb/floatItemData/vpatternlabeldata.h" -#include "../vpatterndb/floatItemData/vpiecelabeldata.h" -#include "../vpatterndb/floatItemData/vgrainlinedata.h" -#include "../vpatterndb/variables/vmeasurement.h" -#include "../vmisc/vabstractvalapplication.h" +#include "../vgeometry/vlayoutplacelabel.h" +#include "../vgeometry/vplacelabelitem.h" +#include "../vgeometry/vpointf.h" #include "../vmisc/compatibility.h" #include "../vmisc/literals.h" -#include "../vpatterndb/vcontainer.h" +#include "../vmisc/vabstractvalapplication.h" #include "../vpatterndb/calculator.h" +#include "../vpatterndb/floatItemData/vgrainlinedata.h" +#include "../vpatterndb/floatItemData/vpatternlabeldata.h" +#include "../vpatterndb/floatItemData/vpiecelabeldata.h" +#include "../vpatterndb/variables/vmeasurement.h" +#include "../vpatterndb/vcontainer.h" #include "../vpatterndb/vpassmark.h" #include "../vpatterndb/vpiecenode.h" -#include "../vgeometry/vpointf.h" -#include "../vgeometry/vplacelabelitem.h" -#include "vlayoutpiece_p.h" -#include "vtextmanager.h" +#include "qline.h" +#include "qpainterpath.h" +#include "vgobject.h" #include "vgraphicsfillitem.h" -#include "../vgeometry/vlayoutplacelabel.h" +#include "vlayoutpiece_p.h" +#include "vpiecegrainline.h" +#include "vtextmanager.h" namespace { @@ -751,6 +755,19 @@ auto VLayoutPiece::Map(QVector points) const -> QVec return points; } +//--------------------------------------------------------------------------------------------------------------------- +auto VLayoutPiece::Map(const GrainlineShape &shape) const -> GrainlineShape +{ + GrainlineShape mappedShape; + mappedShape.reserve(shape.size()); + + for (auto subShape : shape) + { + mappedShape.append(Map(subShape)); + } + return mappedShape; +} + //--------------------------------------------------------------------------------------------------------------------- // cppcheck-suppress unusedFunction auto VLayoutPiece::GetMappedContourPoints() const -> QVector @@ -977,77 +994,59 @@ void VLayoutPiece::SetPatternLabelData(const VTextManager &data) d->m_tmPattern = data; } +//--------------------------------------------------------------------------------------------------------------------- +void VLayoutPiece::SetGrainline(const VPieceGrainline &grainline) +{ + d->m_grainline = grainline; +} + //--------------------------------------------------------------------------------------------------------------------- void VLayoutPiece::SetGrainline(const VGrainlineData& geom, const VContainer* pattern) { - qreal dAng = 0; - QScopedPointer item(GetMainPathItem()); - const QVector v = GrainlinePoints(geom, pattern, item->boundingRect(), dAng); - if (v.isEmpty()) + QLineF mainLine = GrainlineMainLine(geom, pattern, item->boundingRect()); + if (mainLine.isNull()) { return; } - - d->m_grainlineEnabled = true; - d->m_grainlineArrowType = geom.GetArrowType(); - d->m_grainlineAngle = qRadiansToDegrees(dAng); - d->m_grainlinePoints = v; + d->m_grainline = VPieceGrainline(mainLine, geom.GetArrowType()); } //--------------------------------------------------------------------------------------------------------------------- -auto VLayoutPiece::GetMappedGrainline() const -> QVector +auto VLayoutPiece::GetGrainline() const -> VPieceGrainline { - return Map(d->m_grainlinePoints); + return d->m_grainline; } //--------------------------------------------------------------------------------------------------------------------- -auto VLayoutPiece::GetGrainline() const -> QVector +auto VLayoutPiece::GetMappedGrainlineShape() const -> GrainlineShape { - return d->m_grainlinePoints; + return Map(d->m_grainline.Shape()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VLayoutPiece::GetGrainlineShape() const -> GrainlineShape +{ + return d->m_grainline.Shape(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VLayoutPiece::GetMappedGrainlineMainLine() const -> QLineF +{ + return d->m_matrix.map(d->m_grainline.GetMainLine()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VLayoutPiece::GetGrainlineMainLine() const -> QLineF +{ + return d->m_grainline.GetMainLine(); } //--------------------------------------------------------------------------------------------------------------------- auto VLayoutPiece::IsGrainlineEnabled() const -> bool { - return d->m_grainlineEnabled; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VLayoutPiece::SetGrainlineEnabled(bool enabled) -{ - d->m_grainlineEnabled = enabled; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VLayoutPiece::SetGrainlineAngle(qreal angle) -{ - d->m_grainlineAngle = angle; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VLayoutPiece::SetGrainlineArrowType(GrainlineArrowDirection type) -{ - d->m_grainlineArrowType = type; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VLayoutPiece::SetGrainlinePoints(const QVector &points) -{ - d->m_grainlinePoints = points; -} - -//--------------------------------------------------------------------------------------------------------------------- -auto VLayoutPiece::GrainlineAngle() const -> qreal -{ - return d->m_grainlineAngle; -} - -//--------------------------------------------------------------------------------------------------------------------- -auto VLayoutPiece::GrainlineArrowType() const -> GrainlineArrowDirection -{ - return d->m_grainlineArrowType; + return d->m_grainline.IsEnabled(); } //--------------------------------------------------------------------------------------------------------------------- @@ -1451,17 +1450,7 @@ void VLayoutPiece::DrawMiniature(QPainter &painter) const painter.drawPath(LabelShapePath(label)); } - QVector gPoints = GetGrainline(); - if (not gPoints.isEmpty()) - { - QPainterPath path; - path.moveTo(gPoints.at(0)); - for (auto p : qAsConst(gPoints)) - { - path.lineTo(p); - } - painter.drawPath(path); - } + painter.drawPath(VLayoutPiece::GrainlinePath(GetGrainlineShape())); } //--------------------------------------------------------------------------------------------------------------------- @@ -1547,6 +1536,23 @@ auto VLayoutPiece::BoundingRect(QVector points) -> QRectF return QPolygonF(points).boundingRect(); } +//--------------------------------------------------------------------------------------------------------------------- +auto VLayoutPiece::GrainlinePath(const GrainlineShape &shape) -> QPainterPath +{ + QPainterPath shapePath; + for (auto subShape : shape) + { + QPainterPath path; + path.moveTo(subShape.at(0)); + for (auto p : qAsConst(subShape)) + { + path.lineTo(p); + } + shapePath.addPath(path); + } + return shapePath; +} + //--------------------------------------------------------------------------------------------------------------------- void VLayoutPiece::CreateLabelStrings(QGraphicsItem *parent, const QVector &labelShape, const VTextManager &tm, bool textAsPaths) const @@ -1650,22 +1656,13 @@ void VLayoutPiece::CreateGrainlineItem(QGraphicsItem *parent) const { SCASSERT(parent != nullptr) - if (not d->m_grainlineEnabled || d->m_grainlinePoints.count() < 2) + if (not d->m_grainline.IsEnabled()) { return; } - auto* item = new VGraphicsFillItem(parent); + + auto *item = new VGraphicsFillItem(VLayoutPiece::GrainlinePath(GetMappedGrainlineShape()), parent); item->SetWidth(VAbstractApplication::VApp()->Settings()->WidthHairLine()); - - QPainterPath path; - - QVector gPoints = GetMappedGrainline(); - path.moveTo(gPoints.at(0)); - for (auto p : qAsConst(gPoints)) - { - path.lineTo(p); - } - item->setPath(path); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vlayout/vlayoutpiece.h b/src/libs/vlayout/vlayoutpiece.h index 02c8c4b91..526aa5d72 100644 --- a/src/libs/vlayout/vlayoutpiece.h +++ b/src/libs/vlayout/vlayoutpiece.h @@ -41,9 +41,11 @@ #include #include -#include "vabstractpiece.h" #include "../vmisc/typedef.h" #include "../vpatterndb/floatItemData/floatitemdef.h" +#include "../vwidgets/vpiecegrainline.h" +#include "qpainterpath.h" +#include "vabstractpiece.h" #if __cplusplus >= 201703L // C++17 #include @@ -124,11 +126,12 @@ public: const VContainer *pattern); void SetGrainline(const VGrainlineData& geom, const VContainer *pattern); - auto GetMappedGrainline() const -> QVector; - auto GetGrainline() const -> QVector; + auto GetGrainline() const -> VPieceGrainline; + auto GetMappedGrainlineShape() const -> GrainlineShape; + auto GetGrainlineShape() const -> GrainlineShape; + auto GetMappedGrainlineMainLine() const -> QLineF; + auto GetGrainlineMainLine() const -> QLineF; auto IsGrainlineEnabled() const -> bool; - auto GrainlineAngle() const -> qreal; - auto GrainlineArrowType() const -> GrainlineArrowDirection; auto GetMatrix() const -> QTransform; void SetMatrix(const QTransform &matrix); @@ -174,6 +177,8 @@ public: static auto BoundingRect(QVector points) -> QRectF; + static auto GrainlinePath(const GrainlineShape &shape) -> QPainterPath; + auto isNull() const -> bool; auto Square() const -> qint64; @@ -195,10 +200,7 @@ public: auto MapPlaceLabelShape(PlaceLabelImg shape) const -> PlaceLabelImg; protected: - void SetGrainlineEnabled(bool enabled); - void SetGrainlineAngle(qreal angle); - void SetGrainlineArrowType(GrainlineArrowDirection type); - void SetGrainlinePoints(const QVector &points); + void SetGrainline(const VPieceGrainline &grainline); auto GetPieceLabelRect() const -> QVector; void SetPieceLabelRect(const QVector &rect); @@ -226,6 +228,7 @@ private: template auto Map(QVector points) const -> QVector; + auto Map(const GrainlineShape &shape) const -> GrainlineShape; auto Edge(const QVector &path, int i) const -> QLineF; auto EdgeByPoint(const QVector &path, const QPointF &p1) const -> EdgeIndex; diff --git a/src/libs/vlayout/vlayoutpiece_p.h b/src/libs/vlayout/vlayoutpiece_p.h index 7efe933b5..9f214e94f 100644 --- a/src/libs/vlayout/vlayoutpiece_p.h +++ b/src/libs/vlayout/vlayoutpiece_p.h @@ -35,6 +35,8 @@ #include #include "../vpatterndb/floatItemData/floatitemdef.h" +#include "../vwidgets/vpiecegrainline.h" +#include "compatibility.h" #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) #include "../vmisc/diagnostic.h" #endif // QT_VERSION < QT_VERSION_CHECK(5, 5, 0) @@ -92,12 +94,7 @@ public: /** @brief patternInfo pattern info rectangle */ QVector m_patternInfo{}; // NOLINT(misc-non-private-member-variables-in-classes) - /** @brief grainlineInfo line */ - QVector m_grainlinePoints{}; // NOLINT(misc-non-private-member-variables-in-classes) - - GrainlineArrowDirection m_grainlineArrowType{GrainlineArrowDirection::atFront}; // NOLINT(misc-non-private-member-variables-in-classes) - qreal m_grainlineAngle{0}; // NOLINT(misc-non-private-member-variables-in-classes) - bool m_grainlineEnabled{false}; // NOLINT(misc-non-private-member-variables-in-classes) + VPieceGrainline m_grainline{}; // NOLINT(misc-non-private-member-variables-in-classes) /** @brief m_tmDetail text manager for laying out detail info */ VTextManager m_tmDetail{}; // NOLINT(misc-non-private-member-variables-in-classes) @@ -124,7 +121,7 @@ private: Q_DISABLE_ASSIGN_MOVE(VLayoutPieceData) // NOLINT static constexpr quint32 streamHeader{0x80D7D009}; // CRC-32Q string "VLayoutPieceData" - static constexpr quint16 classVersion{4}; + static constexpr quint16 classVersion{5}; }; QT_WARNING_POP @@ -141,7 +138,6 @@ inline auto operator<<(QDataStream &dataStream, const VLayoutPieceData &piece) - { dataStream << VLayoutPieceData::streamHeader << VLayoutPieceData::classVersion; - // Added in classVersion = 1 dataStream << piece.m_contour; dataStream << piece.m_seamAllowance; dataStream << piece.m_layoutAllowance; @@ -152,23 +148,16 @@ inline auto operator<<(QDataStream &dataStream, const VLayoutPieceData &piece) - dataStream << piece.m_mirror; dataStream << piece.m_detailLabel; dataStream << piece.m_patternInfo; - dataStream << piece.m_grainlinePoints; - dataStream << piece.m_grainlineArrowType; - dataStream << piece.m_grainlineAngle; - dataStream << piece.m_grainlineEnabled; dataStream << piece.m_placeLabels; dataStream << piece.m_square; - - // Added in classVersion = 2 dataStream << piece.m_quantity; dataStream << piece.m_id; - - // Added in classVersion = 3 dataStream << piece.m_tmDetail; dataStream << piece.m_tmPattern; dataStream << piece.m_gradationId; dataStream << piece.m_xScale; dataStream << piece.m_yScale; + dataStream << piece.m_grainline; return dataStream; } @@ -181,7 +170,7 @@ inline auto operator>>(QDataStream &dataStream, VLayoutPieceData &piece) -> QDat if (actualStreamHeader != VLayoutPieceData::streamHeader) { - QString message = QCoreApplication::tr("VRawLayoutData prefix mismatch error: actualStreamHeader = 0x%1 and " + QString message = QCoreApplication::tr("VLayoutPieceData prefix mismatch error: actualStreamHeader = 0x%1 and " "streamHeader = 0x%2") .arg(actualStreamHeader, 8, 0x10, QChar('0')) .arg(VLayoutPieceData::streamHeader, 8, 0x10, QChar('0')); @@ -193,7 +182,7 @@ inline auto operator>>(QDataStream &dataStream, VLayoutPieceData &piece) -> QDat if (actualClassVersion > VLayoutPieceData::classVersion) { - QString message = QCoreApplication::tr("VRawLayoutData compatibility error: actualClassVersion = %1 and " + QString message = QCoreApplication::tr("VLayoutPieceData compatibility error: actualClassVersion = %1 and " "classVersion = %2") .arg(actualClassVersion).arg(VLayoutPieceData::classVersion); throw VException(message); @@ -218,6 +207,7 @@ inline auto operator>>(QDataStream &dataStream, VLayoutPieceData &piece) -> QDat dataStream >> piece.m_contour; dataStream >> piece.m_seamAllowance; } + dataStream >> piece.m_layoutAllowance; dataStream >> piece.m_passmarks; dataStream >> piece.m_internalPaths; @@ -226,10 +216,23 @@ inline auto operator>>(QDataStream &dataStream, VLayoutPieceData &piece) -> QDat dataStream >> piece.m_mirror; dataStream >> piece.m_detailLabel; dataStream >> piece.m_patternInfo; - dataStream >> piece.m_grainlinePoints; - dataStream >> piece.m_grainlineArrowType; - dataStream >> piece.m_grainlineAngle; - dataStream >> piece.m_grainlineEnabled; + + QVector shape; + GrainlineArrowDirection arrowType = GrainlineArrowDirection::oneWayUp; + bool grainlineEnabled = false; + + if (actualClassVersion < 5) + { + dataStream >> shape; + + dataStream >> arrowType; + + qreal grainlineAngle; + dataStream >> grainlineAngle; + + dataStream >> grainlineEnabled; + } + dataStream >> piece.m_placeLabels; dataStream >> piece.m_square; @@ -248,6 +251,25 @@ inline auto operator>>(QDataStream &dataStream, VLayoutPieceData &piece) -> QDat dataStream >> piece.m_yScale; } + if (actualClassVersion >= 5) + { + dataStream >> piece.m_grainline; + } + else + { + if (shape.size() >= 2) + { + piece.m_grainline = VPieceGrainline(QLineF(ConstFirst(shape), ConstLast(shape)), arrowType); + piece.m_grainline.SetEnabled(false); + } + else + { + piece.m_grainline = VPieceGrainline(); + piece.m_grainline.SetArrowType(arrowType); + piece.m_grainline.SetEnabled(grainlineEnabled); + } + } + return dataStream; } diff --git a/src/libs/vlayout/vposition.cpp b/src/libs/vlayout/vposition.cpp index 6c196ea91..505637f5d 100644 --- a/src/libs/vlayout/vposition.cpp +++ b/src/libs/vlayout/vposition.cpp @@ -47,10 +47,11 @@ #include #include -#include "../vmisc/def.h" #include "../ifc/exception/vexception.h" -#include "../vpatterndb/floatItemData/floatitemdef.h" #include "../vlayout/vlayoutpoint.h" +#include "../vmisc/def.h" +#include "../vpatterndb/floatItemData/floatitemdef.h" +#include "vpiecegrainline.h" namespace { @@ -557,8 +558,9 @@ void VPosition::FollowGrainline() return; } + VPieceGrainline pieceGrainline = m_data.detail.GetGrainline(); QLineF detailGrainline(10, 10, 100, 10); - detailGrainline.setAngle(m_data.detail.GrainlineAngle()); + detailGrainline.setAngle(pieceGrainline.GetMainLine().angle()); if (m_data.detail.IsForceFlipping()) { @@ -574,8 +576,7 @@ void VPosition::FollowGrainline() const qreal angle = detailGrainline.angleTo(FabricGrainline()); - if (m_data.detail.GrainlineArrowType() == GrainlineArrowDirection::atBoth || - m_data.detail.GrainlineArrowType() == GrainlineArrowDirection::atFront) + if (pieceGrainline.IsArrowUpEnabled()) { RotateOnAngle(angle); } @@ -585,8 +586,7 @@ void VPosition::FollowGrainline() return; } - if (m_data.detail.GrainlineArrowType() == GrainlineArrowDirection::atBoth || - m_data.detail.GrainlineArrowType() == GrainlineArrowDirection::atRear) + if (pieceGrainline.IsArrowDownEnabled()) { RotateOnAngle(angle + 180); } @@ -596,15 +596,18 @@ void VPosition::FollowGrainline() return; } - if (m_data.detail.GrainlineArrowType() == GrainlineArrowDirection::atFourWay) + if (pieceGrainline.IsArrowLeftEnabled()) { RotateOnAngle(angle + 90); + } - if (stop->load()) - { - return; - } + if (stop->load()) + { + return; + } + if (pieceGrainline.IsArrowRightEnabled()) + { RotateOnAngle(angle - 90); } } diff --git a/src/libs/vpatterndb/floatItemData/floatitemdef.h b/src/libs/vpatterndb/floatItemData/floatitemdef.h index cd115b2f8..61123c2f0 100644 --- a/src/libs/vpatterndb/floatItemData/floatitemdef.h +++ b/src/libs/vpatterndb/floatItemData/floatitemdef.h @@ -29,16 +29,23 @@ #ifndef FLOATITEMDEF_H #define FLOATITEMDEF_H -#include -#include +#include // denotes the type of arrow for the grainline enum class GrainlineArrowDirection : qint8 { - atBoth, - atFront, - atRear, - atFourWay + twoWaysUpDown = 0, + oneWayUp = 1, + oneWayDown = 2, + fourWays = 3, + twoWaysUpLeft = 4, + twoWaysUpRight = 5, + twoWaysDownLeft = 6, + twoWaysDownRight = 7, + threeWaysUpDownLeft = 8, + threeWaysUpDownRight = 9, + threeWaysUpLeftRight = 10, + threeWaysDownLeftRight = 11 }; #endif // FLOATITEMDEF_H diff --git a/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp b/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp index 0c1c0dcda..06f24d64a 100644 --- a/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp +++ b/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp @@ -379,7 +379,12 @@ void DialogSeamAllowance::SetPiece(const VPiece &piece) uiTabLabels->groupBoxDetailLabel->setEnabled(not m_templateLines.isEmpty()); - uiTabGrainline->comboBoxArrow->setCurrentIndex(int(piece.GetGrainlineGeometry().GetArrowType())); + int index = uiTabGrainline->comboBoxArrow->findData(static_cast(piece.GetGrainlineGeometry().GetArrowType())); + if (index == -1) + { + index = 0; + } + uiTabGrainline->comboBoxArrow->setCurrentIndex(index); uiTabLabels->groupBoxDetailLabel->setChecked(ppData.IsVisible()); ChangeCurrentData(uiTabLabels->comboBoxDLCenterPin, ppData.CenterPin()); @@ -2656,7 +2661,7 @@ VPiece DialogSeamAllowance::CreatePiece() const piece.GetGrainlineGeometry().SetVisible(uiTabGrainline->groupBoxGrainline->isChecked()); piece.GetGrainlineGeometry().SetArrowType( - static_cast(uiTabGrainline->comboBoxArrow->currentIndex())); + static_cast(uiTabGrainline->comboBoxArrow->currentData().toInt())); if (not flagGPin) { @@ -3380,10 +3385,30 @@ void DialogSeamAllowance::InitGrainlineTab() EnabledGrainline(); - uiTabGrainline->comboBoxArrow->addItem(tr("Both")); - uiTabGrainline->comboBoxArrow->addItem(tr("Just front")); - uiTabGrainline->comboBoxArrow->addItem(tr("Just rear")); - uiTabGrainline->comboBoxArrow->addItem(tr("Four way")); + uiTabGrainline->comboBoxArrow->addItem(tr("Two ways (Up/Down)", "grainline direction"), + static_cast(GrainlineArrowDirection::twoWaysUpDown)); + uiTabGrainline->comboBoxArrow->addItem(tr("One way (Up)", "grainline direction"), + static_cast(GrainlineArrowDirection::oneWayUp)); + uiTabGrainline->comboBoxArrow->addItem(tr("One way (Down)", "grainline direction"), + static_cast(GrainlineArrowDirection::oneWayDown)); + uiTabGrainline->comboBoxArrow->addItem(tr("Four ways", "grainline direction"), + static_cast(GrainlineArrowDirection::fourWays)); + uiTabGrainline->comboBoxArrow->addItem(tr("Two ways (Up/Left)", "grainline direction"), + static_cast(GrainlineArrowDirection::twoWaysUpLeft)); + uiTabGrainline->comboBoxArrow->addItem(tr("Two ways (Up/Right)", "grainline direction"), + static_cast(GrainlineArrowDirection::twoWaysUpRight)); + uiTabGrainline->comboBoxArrow->addItem(tr("Two ways (Down/Right)", "grainline direction"), + static_cast(GrainlineArrowDirection::twoWaysDownLeft)); + uiTabGrainline->comboBoxArrow->addItem(tr("Two ways (Down/Right)", "grainline direction"), + static_cast(GrainlineArrowDirection::twoWaysDownRight)); + uiTabGrainline->comboBoxArrow->addItem(tr("Three ways (Up/Down/Left)", "grainline direction"), + static_cast(GrainlineArrowDirection::threeWaysUpDownLeft)); + uiTabGrainline->comboBoxArrow->addItem(tr("Three ways (Up/Down/Right)", "grainline direction"), + static_cast(GrainlineArrowDirection::threeWaysUpDownRight)); + uiTabGrainline->comboBoxArrow->addItem(tr("Three ways (Up/Left/Right)", "grainline direction"), + static_cast(GrainlineArrowDirection::threeWaysUpLeftRight)); + uiTabGrainline->comboBoxArrow->addItem(tr("Three ways (Down/Left/Right)", "grainline direction"), + static_cast(GrainlineArrowDirection::threeWaysDownLeftRight)); m_iRotBaseHeight = uiTabGrainline->lineEditRotFormula->height(); m_iLenBaseHeight = uiTabGrainline->lineEditLenFormula->height(); diff --git a/src/libs/vtools/tools/vtoolseamallowance.cpp b/src/libs/vtools/tools/vtoolseamallowance.cpp index 979d47f7e..a0e8341e2 100644 --- a/src/libs/vtools/tools/vtoolseamallowance.cpp +++ b/src/libs/vtools/tools/vtoolseamallowance.cpp @@ -27,31 +27,32 @@ *************************************************************************/ #include "vtoolseamallowance.h" -#include "../dialogs/tools/piece/dialogseamallowance.h" #include "../dialogs/tools/piece/dialogduplicatedetail.h" -#include "../vpatterndb/vpiecenode.h" -#include "../vpatterndb/vpiecepath.h" -#include "../vpatterndb/calculator.h" -#include "../vpatterndb/floatItemData/vpatternlabeldata.h" -#include "../vpatterndb/floatItemData/vpiecelabeldata.h" -#include "../vpatterndb/variables/vincrement.h" -#include "../vgeometry/varc.h" -#include "../vgeometry/vpointf.h" -#include "../vgeometry/vplacelabelitem.h" -#include "../vgeometry/vellipticalarc.h" -#include "../ifc/xml/vpatternconverter.h" +#include "../dialogs/tools/piece/dialogseamallowance.h" #include "../ifc/exception/vexceptionwrongid.h" #include "../ifc/xml/vlabeltemplateconverter.h" +#include "../ifc/xml/vpatternconverter.h" +#include "../qmuparser/qmutokenparser.h" #include "../undocommands/addpiece.h" #include "../undocommands/deletepiece.h" #include "../undocommands/movepiece.h" #include "../undocommands/savepieceoptions.h" #include "../undocommands/togglepiecestate.h" +#include "../vgeometry/varc.h" +#include "../vgeometry/vellipticalarc.h" +#include "../vgeometry/vplacelabelitem.h" +#include "../vgeometry/vpointf.h" +#include "../vpatterndb/calculator.h" +#include "../vpatterndb/floatItemData/vpatternlabeldata.h" +#include "../vpatterndb/floatItemData/vpiecelabeldata.h" +#include "../vpatterndb/variables/vincrement.h" +#include "../vpatterndb/vpiecenode.h" +#include "../vpatterndb/vpiecepath.h" +#include "../vwidgets/global.h" +#include "../vwidgets/vabstractmainwindow.h" #include "../vwidgets/vmaingraphicsview.h" #include "../vwidgets/vnobrushscalepathitem.h" -#include "../vwidgets/vabstractmainwindow.h" -#include "../vwidgets/global.h" -#include "../qmuparser/qmutokenparser.h" +#include "../vwidgets/vpiecegrainline.h" #include "toolsdef.h" #if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) #include "../vmisc/backport/qoverload.h" @@ -2158,32 +2159,14 @@ auto VToolSeamAllowance::SelectedTools() const -> QList //--------------------------------------------------------------------------------------------------------------------- auto VToolSeamAllowance::IsGrainlinePositionValid() const -> bool { - QVector grainLine = m_grainLine->Grainline(); + VPieceGrainline grainLine = m_grainLine->Grainline(); const VPiece detail = VAbstractTool::data.GetPiece(m_id); QVector contourPoints; detail.IsSeamAllowance() && not detail.IsSeamAllowanceBuiltIn() ? CastTo(detail.SeamAllowancePoints(getData()), contourPoints) : CastTo(detail.MainPathPoints(getData()), contourPoints); - for (auto line : grainLine) - { - QVector points = VAbstractCurve::CurveIntersectLine(contourPoints, line); - for (auto &point : points) - { - if (not VFuzzyComparePoints(line.p1(), point) && not VFuzzyComparePoints(line.p2(), point)) - { - return false; - } - } - } - - QPainterPath grainLinePath; - for (auto line : grainLine) - { - grainLinePath.addPath(VGObject::PainterPath(QVector{line.p1(), line.p2()})); - } - const QPainterPath contourPath = VGObject::PainterPath(contourPoints); - return contourPath.contains(grainLinePath); + return grainLine.IsPositionValid(contourPoints); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vwidgets/vgrainlineitem.cpp b/src/libs/vwidgets/vgrainlineitem.cpp index 3698b5a1c..275f6010d 100644 --- a/src/libs/vwidgets/vgrainlineitem.cpp +++ b/src/libs/vwidgets/vgrainlineitem.cpp @@ -26,7 +26,7 @@ ** *************************************************************************/ -#include +#include #include #include @@ -36,20 +36,17 @@ #include #include "../vmisc/def.h" -#include "../vmisc/vmath.h" -#include "../vmisc/vabstractvalapplication.h" +#include "../vmisc/vabstractapplication.h" #include "../vmisc/literals.h" #include "global.h" +#include "vpiecegrainline.h" #include "vgrainlineitem.h" -#define ARROW_ANGLE M_PI/9 -#define ARROW_LENGTH 15 -#define RECT_WIDTH 30 -#define RESIZE_RECT_SIZE 10 -#define ROTATE_CIRC_R 7 -#define ACTIVE_Z 10 -#define LINE_PEN_WIDTH 3 +constexpr int rectWidth = 30; +constexpr int resizeRectSize = 10; +constexpr int rotateCircR = 7; +constexpr int activeZ = 10; //--------------------------------------------------------------------------------------------------------------------- /** @@ -58,19 +55,6 @@ */ VGrainlineItem::VGrainlineItem(QGraphicsItem* pParent) : VPieceItem(pParent), - m_dRotation(0), - m_dStartRotation(0), - m_dLength(0), - m_polyBound(), - m_ptStartPos(), - m_ptStartMove(), - m_polyResize(), - m_dStartLength(0), - m_ptStart(), - m_ptFinish(), - m_ptCenter(), - m_dAngle(0), - m_eArrowType(GrainlineArrowDirection::atBoth), m_penWidth(VAbstractApplication::VApp()->Settings()->WidthMainLine()) { setAcceptHoverEvents(true); @@ -80,18 +64,16 @@ VGrainlineItem::VGrainlineItem(QGraphicsItem* pParent) } //--------------------------------------------------------------------------------------------------------------------- -QPainterPath VGrainlineItem::shape() const +auto VGrainlineItem::shape() const -> QPainterPath { if (m_eMode == mNormal) { return MainShape(); } - else - { - QPainterPath path; - path.addPolygon(m_polyBound); - return path; - } + + QPainterPath path; + path.addPolygon(m_polyBound); + return path; } //--------------------------------------------------------------------------------------------------------------------- @@ -110,37 +92,39 @@ void VGrainlineItem::paint(QPainter* pP, const QStyleOptionGraphicsItem* pOption const qreal width = ScaleWidth(VAbstractApplication::VApp()->Settings()->WidthHairLine(), SceneScale(scene())); pP->setPen(QPen(clr, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); - pP->setRenderHints(QPainter::Antialiasing); - // line - const QLineF mainLine = MainLine(); + + VPieceGrainline grainline(QPointF(), m_dLength, m_dRotation, m_eArrowType); + // main line + const QLineF mainLine = grainline.GetMainLine(); pP->drawLine(mainLine.p1(), mainLine.p2()); pP->setBrush(clr); - qreal dArrLen = ARROW_LENGTH; - if (m_eArrowType != GrainlineArrowDirection::atRear) + if (grainline.IsArrowUpEnabled()) { - // first arrow - pP->drawPolygon(FirstArrow(MainLine().p2(), dArrLen)); - - if (m_eArrowType == GrainlineArrowDirection::atFourWay) - { // first double arrow - QLineF line = MainLine(); - line.setLength(line.length() - dArrLen - dArrLen*0.5); - pP->drawPolygon(FirstArrow(line.p2(), dArrLen)); - } + pP->drawPolygon(grainline.ArrowUp()); } - if (m_eArrowType != GrainlineArrowDirection::atFront) - { - // second arrow - pP->drawPolygon(SecondArrow(MainLine().p1(), dArrLen)); - if (m_eArrowType == GrainlineArrowDirection::atFourWay) - { // second double arrow - QLineF line(MainLine().p2(), MainLine().p1()); - line.setLength(line.length() - dArrLen - dArrLen*0.5); - pP->drawPolygon(SecondArrow(line.p2(), dArrLen)); + if (grainline.IsArrowDownEnabled()) + { + pP->drawPolygon(grainline.ArrowDown()); + } + + if (grainline.IsFourWays()) + { + // secondary line + const QLineF secondaryLine = grainline.SecondaryLine(); + pP->drawLine(secondaryLine.p1(), secondaryLine.p2()); + + if (grainline.IsArrowLeftEnabled()) + { + pP->drawPolygon(grainline.ArrowLeft()); + } + + if (grainline.IsArrowRightEnabled()) + { + pP->drawPolygon(grainline.ArrowRight()); } } @@ -170,7 +154,7 @@ void VGrainlineItem::paint(QPainter* pP, const QStyleOptionGraphicsItem* pOption if (m_eMode == mRotate) { QPointF ptC = (m_polyBound.at(0) + m_polyBound.at(2))/2; - qreal dRad = ROTATE_CIRC_R; + qreal dRad = rotateCircR; pP->setBrush(clr); pP->drawEllipse(ptC, dRad, dRad); @@ -178,9 +162,9 @@ void VGrainlineItem::paint(QPainter* pP, const QStyleOptionGraphicsItem* pOption pP->save(); pP->translate(ptC); pP->rotate(qRadiansToDegrees(-m_dRotation)); - int iX = int(qRound(m_dLength/2 - 0.5*dRad)); - int iY = int(qRound(RECT_WIDTH - 0.5*dRad)); - int iR = int(qRound(dRad*3)); + int iX = qRound(m_dLength/2 - 0.5*dRad); + int iY = grainline.IsFourWays() ? qRound((m_dLength/2) - 0.8*dRad) : qRound(rectWidth - 0.5*dRad); + int iR = qRound(dRad*3); pP->drawArc(iX - iR, iY - iR, iR, iR, 0*16, -90*16); pP->drawArc(-iX, iY - iR, iR, iR, 270*16, -90*16); pP->drawArc(-iX, -iY, iR, iR, 180*16, -90*16); @@ -202,89 +186,27 @@ void VGrainlineItem::UpdateGeometry(const QPointF& ptPos, qreal dRotation, qreal { m_dRotation = qDegreesToRadians(dRotation); m_dLength = dLength; + m_eArrowType = eAT; + VPieceGrainline grainline(ptPos, m_dLength, m_dRotation, m_eArrowType); qreal dX; qreal dY; QPointF pt = ptPos; - if (not IsContained(pt, m_dRotation, dX, dY)) + if (not grainline.IsContained(parentItem()->boundingRect(), dX, dY)) { pt.setX(pt.x() + dX); pt.setY(pt.y() + dY); } setPos(pt); - m_eArrowType = eAT; UpdateRectangle(); Update(); } //--------------------------------------------------------------------------------------------------------------------- -/** - * @brief VGrainlineItem::IsContained checks, if both ends of the grainline, starting at pt, are contained in - * parent widget. - * @param pt starting point of the grainline. - * @param dRot rotation of the grainline in [rad] - * @param dX horizontal translation needed to put the arrow inside parent item - * @param dY vertical translation needed to put the arrow inside parent item - * @return true, if both ends of the grainline, starting at pt, are contained in the parent widget and - * false otherwise. - */ -bool VGrainlineItem::IsContained(const QPointF& pt, qreal dRot, qreal &dX, qreal &dY) const +auto VGrainlineItem::Grainline() const -> VPieceGrainline { - dX = 0; - dY = 0; - QPointF apt[2]; - apt[0] = pt; - apt[1].setX(pt.x() + m_dLength * cos(dRot)); - apt[1].setY(pt.y() - m_dLength * sin(dRot)); - // single point differences - qreal dPtX; - qreal dPtY; - bool bInside = true; - - QRectF rectParent = parentItem()->boundingRect(); - for (int i = 0; i < 2; ++i) - { - dPtX = 0; - dPtY = 0; - if (rectParent.contains(apt[i]) == false) - { - if (apt[i].x() < rectParent.left()) - { - dPtX = rectParent.left() - apt[i].x(); - } - else if (apt[i].x() > rectParent.right()) - { - dPtX = rectParent.right() - apt[i].x(); - } - if (apt[i].y() < rectParent.top()) - { - dPtY = rectParent.top() - apt[i].y(); - } - else if (apt[i].y() > rectParent.bottom()) - { - dPtY = rectParent.bottom() - apt[i].y(); - } - - if (fabs(dPtX) > fabs(dX)) - { - dX = dPtX; - } - if (fabs(dPtY) > fabs(dY)) - { - dY = dPtY; - } - - bInside = false; - } - } - return bInside; -} - -//--------------------------------------------------------------------------------------------------------------------- -QLineF VGrainlineItem::Grainline() const -{ - return {m_ptStart, m_ptFinish}; + return {QLineF(m_ptStart, m_ptFinish), m_eArrowType}; } //--------------------------------------------------------------------------------------------------------------------- @@ -315,7 +237,7 @@ void VGrainlineItem::mousePressEvent(QGraphicsSceneMouseEvent* pME) if ((m_moveType & AllModifications ) == AllModifications) { AllUserModifications(pME->pos()); - setZValue(ACTIVE_Z); + setZValue(activeZ); Update(); } else if (m_moveType & IsRotatable) @@ -333,7 +255,7 @@ void VGrainlineItem::mousePressEvent(QGraphicsSceneMouseEvent* pME) m_eMode = mRotate; SetItemOverrideCursor(this, cursorArrowCloseHand, 1, 1); } - setZValue(ACTIVE_Z); + setZValue(activeZ); Update(); } else if (m_moveType & IsResizable) @@ -346,7 +268,7 @@ void VGrainlineItem::mousePressEvent(QGraphicsSceneMouseEvent* pME) { UserMoveAndResize(pME->pos()); } - setZValue(ACTIVE_Z); + setZValue(activeZ); Update(); } else if (m_moveType & IsMovable) @@ -365,7 +287,7 @@ void VGrainlineItem::mousePressEvent(QGraphicsSceneMouseEvent* pME) SetItemOverrideCursor(this, cursorArrowCloseHand, 1, 1); } - setZValue(ACTIVE_Z); + setZValue(activeZ); Update(); } else @@ -388,7 +310,8 @@ void VGrainlineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* pME) if (m_eMode == mMove && m_moveType & IsMovable) { QPointF pt = m_ptStartPos + ptDiff; - if (IsContained(pt, m_dRotation, dX, dY) == false) + VPieceGrainline grainline(pt, m_dLength, m_dRotation, m_eArrowType); + if (not grainline.IsContained(parentItem()->boundingRect(), dX, dY)) { pt.setX(pt.x() + dX); pt.setY(pt.y() + dY); @@ -440,7 +363,8 @@ void VGrainlineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* pME) qreal dX; qreal dY; - if (IsContained(pos, m_dRotation, dX, dY) == false) + VPieceGrainline grainline(pos, m_dLength, m_dRotation, m_eArrowType); + if (not grainline.IsContained(parentItem()->boundingRect(), dX, dY)) { m_dLength = dPrevLen; } @@ -469,7 +393,8 @@ void VGrainlineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* pME) qreal dAng = GetAngle(mapToParent(pME->pos())) - m_dAngle; QPointF ptNewPos = Rotate(m_ptStartPos, m_ptRotCenter, dAng); - if (IsContained(ptNewPos, m_dStartRotation + dAng, dX, dY) == true) + VPieceGrainline grainline(ptNewPos, m_dLength, m_dStartRotation + dAng, m_eArrowType); + if (grainline.IsContained(parentItem()->boundingRect(), dX, dY)) { setPos(ptNewPos); m_dRotation = m_dStartRotation + dAng; @@ -487,54 +412,57 @@ void VGrainlineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* pME) */ void VGrainlineItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* pME) { - if (pME->button() == Qt::LeftButton) + if (pME->button() != Qt::LeftButton) { - if ((m_eMode == mMove || m_eMode == mRotate || m_eMode == mResize) && (flags() & QGraphicsItem::ItemIsMovable)) - { - SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1); - } + VPieceItem::mouseReleaseEvent(pME); + return; + } - QPointF ptDiff = pME->scenePos() - m_ptStartMove; - qreal dLen = qSqrt(ptDiff.x()*ptDiff.x() + ptDiff.y()*ptDiff.y()); - bool bShort = (dLen < 2); + if ((m_eMode == mMove || m_eMode == mRotate || m_eMode == mResize) && (flags() & QGraphicsItem::ItemIsMovable)) + { + SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1); + } - if (m_eMode == mMove || m_eMode == mResize) + QPointF ptDiff = pME->scenePos() - m_ptStartMove; + qreal dLen = qSqrt(ptDiff.x()*ptDiff.x() + ptDiff.y()*ptDiff.y()); + bool bShort = (dLen < 2); + + if (m_eMode == mMove || m_eMode == mResize) + { + if (bShort) { - if (bShort == true) + if (m_bReleased && m_moveType & IsRotatable) { - if (m_bReleased == true && m_moveType & IsRotatable) - { - m_eMode = mRotate; - Update(); - } - } - else - { - if (m_eMode == mMove && m_moveType & IsMovable) - { - emit SignalMoved(pos()); - } - else if (m_moveType & IsResizable) - { - emit SignalResized(m_dLength); - } + m_eMode = mRotate; Update(); } } else { - if (bShort == true) + if (m_eMode == mMove && m_moveType & IsMovable) { - m_eMode = mMove; + emit SignalMoved(pos()); } - else if (m_moveType & IsRotatable) + else if (m_moveType & IsResizable) { - emit SignalRotated(m_dRotation, m_ptStart); + emit SignalResized(m_dLength); } Update(); } - m_bReleased = true; } + else + { + if (bShort) + { + m_eMode = mMove; + } + else if (m_moveType & IsRotatable) + { + emit SignalRotated(m_dRotation, m_ptStart); + } + Update(); + } + m_bReleased = true; } //--------------------------------------------------------------------------------------------------------------------- @@ -574,22 +502,41 @@ void VGrainlineItem::Update() */ void VGrainlineItem::UpdateRectangle() { - QPointF pt1(0, 0); - QPointF pt2(pt1.x() + m_dLength * cos(m_dRotation), pt1.y() - m_dLength * sin(m_dRotation)); + VPieceGrainline grainline(QPointF(), m_dLength, m_dRotation, m_eArrowType); + const QLineF mainLine = grainline.GetMainLine(); - m_ptStart = mapToParent(pt1); - m_ptFinish = mapToParent(pt2); + m_ptStart = mapToParent(mainLine.p1()); + m_ptFinish = mapToParent(mainLine.p2()); m_ptCenter = (m_ptStart + m_ptFinish)/2; m_polyBound.clear(); - m_polyBound << QPointF(pt1.x() + RECT_WIDTH*cos(m_dRotation + M_PI/2), - pt1.y() - RECT_WIDTH*sin(m_dRotation + M_PI/2)); - m_polyBound << QPointF(pt1.x() + RECT_WIDTH*cos(m_dRotation - M_PI/2), - pt1.y() - RECT_WIDTH*sin(m_dRotation - M_PI/2)); - m_polyBound << QPointF(pt2.x() + RECT_WIDTH*cos(m_dRotation - M_PI/2), - pt2.y() - RECT_WIDTH*sin(m_dRotation - M_PI/2)); - m_polyBound << QPointF(pt2.x() + RECT_WIDTH*cos(m_dRotation + M_PI/2), - pt2.y() - RECT_WIDTH*sin(m_dRotation + M_PI/2)); + + if (grainline.IsFourWays()) + { + m_polyBound << QPointF(mainLine.p1().x() + (m_dLength/2)*cos(m_dRotation + M_PI/2), + mainLine.p1().y() - (m_dLength/2)*sin(m_dRotation + M_PI/2)); + m_polyBound << QPointF(mainLine.p1().x() + (m_dLength/2)*cos(m_dRotation - M_PI/2), + mainLine.p1().y() - (m_dLength/2)*sin(m_dRotation - M_PI/2)); + m_polyBound << QPointF(mainLine.p2().x() + (m_dLength/2)*cos(m_dRotation - M_PI/2), + mainLine.p2().y() - (m_dLength/2)*sin(m_dRotation - M_PI/2)); + m_polyBound << QPointF(mainLine.p2().x() + (m_dLength/2)*cos(m_dRotation + M_PI/2), + mainLine.p2().y() - (m_dLength/2)*sin(m_dRotation + M_PI/2)); + + const QLineF secondaryLine = grainline.SecondaryLine(); + m_ptSecondaryStart = mapToParent(secondaryLine.p1()); + m_ptSecondaryFinish = mapToParent(secondaryLine.p2()); + } + else + { + m_polyBound << QPointF(mainLine.p1().x() + rectWidth*cos(m_dRotation + M_PI/2), + mainLine.p1().y() - rectWidth*sin(m_dRotation + M_PI/2)); + m_polyBound << QPointF(mainLine.p1().x() + rectWidth*cos(m_dRotation - M_PI/2), + mainLine.p1().y() - rectWidth*sin(m_dRotation - M_PI/2)); + m_polyBound << QPointF(mainLine.p2().x() + rectWidth*cos(m_dRotation - M_PI/2), + mainLine.p2().y() - rectWidth*sin(m_dRotation - M_PI/2)); + m_polyBound << QPointF(mainLine.p2().x() + rectWidth*cos(m_dRotation + M_PI/2), + mainLine.p2().y() - rectWidth*sin(m_dRotation + M_PI/2)); + } m_rectBoundingBox = m_polyBound.boundingRect().adjusted(-2, -2, 2, 2); setTransformOriginPoint(m_rectBoundingBox.center()); @@ -598,7 +545,7 @@ void VGrainlineItem::UpdateRectangle() } //--------------------------------------------------------------------------------------------------------------------- -double VGrainlineItem::GetAngle(const QPointF &pt) const +auto VGrainlineItem::GetAngle(const QPointF &pt) const -> double { return -VPieceItem::GetAngle(pt); } @@ -612,7 +559,7 @@ double VGrainlineItem::GetAngle(const QPointF &pt) const * @param dAng angle of rotation * @return point, which is a result of rotating pt around ptCenter by angle dAng */ -QPointF VGrainlineItem::Rotate(const QPointF& pt, const QPointF& ptCenter, qreal dAng) const +auto VGrainlineItem::Rotate(const QPointF& pt, const QPointF& ptCenter, qreal dAng) -> QPointF { QPointF ptRel = pt - ptCenter; QPointF ptFinal; @@ -630,7 +577,7 @@ QPointF VGrainlineItem::Rotate(const QPointF& pt, const QPointF& ptCenter, qreal * @param dDist distance * @return resulting point */ -QPointF VGrainlineItem::GetInsideCorner(int i, qreal dDist) const +auto VGrainlineItem::GetInsideCorner(int i, qreal dDist) const -> QPointF { QPointF pt1 = m_polyBound.at((i + 1) % m_polyBound.count()) - m_polyBound.at(i); QPointF pt2 = m_polyBound.at((i + m_polyBound.count() - 1) % m_polyBound.count()) - m_polyBound.at(i); @@ -642,42 +589,10 @@ QPointF VGrainlineItem::GetInsideCorner(int i, qreal dDist) const } //--------------------------------------------------------------------------------------------------------------------- -QLineF VGrainlineItem::MainLine() const +auto VGrainlineItem::MainShape() const -> QPainterPath { - QPointF pt1; - QPointF pt2(pt1.x() + m_dLength * cos(m_dRotation), pt1.y() - m_dLength * sin(m_dRotation)); - return QLineF(pt1, pt2); -} - -//--------------------------------------------------------------------------------------------------------------------- -QPolygonF VGrainlineItem::FirstArrow(const QPointF &pt, qreal dArrLen) const -{ - QPolygonF poly; - poly << pt; - poly << QPointF(pt.x() + dArrLen*cos(M_PI + m_dRotation + ARROW_ANGLE), - pt.y() - dArrLen*sin(M_PI + m_dRotation + ARROW_ANGLE)); - poly << QPointF(pt.x() + dArrLen*cos(M_PI + m_dRotation - ARROW_ANGLE), - pt.y() - dArrLen*sin(M_PI + m_dRotation - ARROW_ANGLE)); - return poly; -} - -//--------------------------------------------------------------------------------------------------------------------- -QPolygonF VGrainlineItem::SecondArrow(const QPointF &pt, qreal dArrLen) const -{ - QPolygonF poly; - poly << pt; - poly << QPointF(pt.x() + dArrLen*cos(m_dRotation + ARROW_ANGLE), - pt.y() - dArrLen*sin(m_dRotation + ARROW_ANGLE)); - poly << QPointF(pt.x() + dArrLen*cos(m_dRotation - ARROW_ANGLE), - pt.y() - dArrLen*sin(m_dRotation - ARROW_ANGLE)); - return poly; -} - -//--------------------------------------------------------------------------------------------------------------------- -QPainterPath VGrainlineItem::MainShape() const -{ - QPainterPath path; - const QLineF mainLine = MainLine(); + VPieceGrainline grainline(QPointF(), m_dLength, m_dRotation, m_eArrowType); + const QLineF mainLine = grainline.GetMainLine(); QPainterPath linePath; linePath.moveTo(mainLine.p1()); linePath.lineTo(mainLine.p2()); @@ -685,43 +600,57 @@ QPainterPath VGrainlineItem::MainShape() const QPainterPathStroker stroker; stroker.setWidth(m_penWidth); + QPainterPath path; path.addPath((stroker.createStroke(linePath) + linePath).simplified()); path.closeSubpath(); - const qreal dArrLen = ARROW_LENGTH; - if (m_eArrowType != GrainlineArrowDirection::atRear) + if (grainline.IsArrowUpEnabled()) { - // first arrow QPainterPath polyPath; - polyPath.addPolygon(FirstArrow(MainLine().p2(), dArrLen)); - - if (m_eArrowType == GrainlineArrowDirection::atFourWay) - { // first double arrow - QLineF line = MainLine(); - line.setLength(line.length() - dArrLen - 0.5); - polyPath.addPolygon(FirstArrow(line.p2(), dArrLen)); - } + polyPath.addPolygon(grainline.ArrowUp()); path.addPath((stroker.createStroke(polyPath) + polyPath).simplified()); path.closeSubpath(); } - if (m_eArrowType != GrainlineArrowDirection::atFront) + if (grainline.IsArrowDownEnabled()) { - // second arrow QPainterPath polyPath; - polyPath.addPolygon(SecondArrow(MainLine().p1(), dArrLen)); - - if (m_eArrowType == GrainlineArrowDirection::atFourWay) - { // second double arrow - QLineF line(MainLine().p2(), MainLine().p1()); - line.setLength(line.length() - dArrLen - 0.5); - polyPath.addPolygon(SecondArrow(line.p2(), dArrLen)); - } + polyPath.addPolygon(grainline.ArrowDown()); path.addPath((stroker.createStroke(polyPath) + polyPath).simplified()); path.closeSubpath(); } + + if (grainline.IsFourWays()) + { + const QLineF secondaryLine = grainline.SecondaryLine(); + QPainterPath secondaryLinePath; + secondaryLinePath.moveTo(secondaryLine.p1()); + secondaryLinePath.lineTo(secondaryLine.p2()); + secondaryLinePath.closeSubpath(); + + path.addPath((stroker.createStroke(secondaryLinePath) + secondaryLinePath).simplified()); + path.closeSubpath(); + + if (grainline.IsArrowLeftEnabled()) + { + QPainterPath polyPath; + polyPath.addPolygon(grainline.ArrowLeft()); + + path.addPath((stroker.createStroke(polyPath) + polyPath).simplified()); + path.closeSubpath(); + } + + if (grainline.IsArrowRightEnabled()) + { + QPainterPath polyPath; + polyPath.addPolygon(grainline.ArrowRight()); + + path.addPath((stroker.createStroke(polyPath) + polyPath).simplified()); + path.closeSubpath(); + } + } return path; } @@ -751,7 +680,7 @@ void VGrainlineItem::UserRotateAndMove() //--------------------------------------------------------------------------------------------------------------------- void VGrainlineItem::UserMoveAndResize(const QPointF &pos) { - if (m_polyResize.containsPoint(pos, Qt::OddEvenFill) == true) + if (m_polyResize.containsPoint(pos, Qt::OddEvenFill)) { m_eMode = mResize; setCursor(Qt::SizeFDiagCursor); @@ -769,7 +698,7 @@ void VGrainlineItem::UpdatePolyResize() m_polyResize.clear(); QPointF ptA = m_polyBound.at(1); m_polyResize << ptA; - const double dSize = RESIZE_RECT_SIZE; + const double dSize = resizeRectSize; ptA.setX(ptA.x() - dSize*cos(m_dRotation - M_PI/2)); ptA.setY(ptA.y() + dSize*sin(m_dRotation - M_PI/2)); diff --git a/src/libs/vwidgets/vgrainlineitem.h b/src/libs/vwidgets/vgrainlineitem.h index 43ea382c5..09fd128b8 100644 --- a/src/libs/vwidgets/vgrainlineitem.h +++ b/src/libs/vwidgets/vgrainlineitem.h @@ -30,68 +30,66 @@ #define VGRAINLINEITEM_H #include "vpieceitem.h" -#include "../vpatterndb/floatItemData/vgrainlinedata.h" +#include "../vpatterndb/floatItemData/floatitemdef.h" #include "../vmisc/def.h" +class VPieceGrainline; + class VGrainlineItem final : public VPieceItem { Q_OBJECT // NOLINT public: explicit VGrainlineItem(QGraphicsItem* pParent = nullptr); - virtual ~VGrainlineItem() = default; + ~VGrainlineItem() override = default; - virtual QPainterPath shape() const override; + auto shape() const -> QPainterPath override; - virtual void paint(QPainter* pP, const QStyleOptionGraphicsItem* pOption, QWidget* pWidget) override; - void UpdateGeometry(const QPointF& ptPos, qreal dRotation, qreal dLength, GrainlineArrowDirection eAT); + void paint(QPainter* pP, const QStyleOptionGraphicsItem* pOption, QWidget* pWidget) override; + void UpdateGeometry(const QPointF& ptPos, qreal dRotation, qreal dLength, GrainlineArrowDirection eAT); - virtual int type() const override {return Type;} + auto type() const -> int override {return Type;} enum { Type = UserType + static_cast(Vis::GrainlineItem)}; - bool IsContained(const QPointF &pt, qreal dRot, qreal &dX, qreal &dY) const; - - QLineF Grainline() const; + auto Grainline() const -> VPieceGrainline; signals: void SignalResized(qreal dLength); void SignalRotated(qreal dRot, const QPointF& ptNewPos); protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent* pME) override; - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* pME) override; - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* pME) override; - virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* pME) override; - virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* pME) override; - virtual void Update() override; - void UpdateRectangle(); + void mousePressEvent(QGraphicsSceneMouseEvent* pME) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent* pME) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent* pME) override; + void hoverEnterEvent(QGraphicsSceneHoverEvent* pME) override; + void hoverLeaveEvent(QGraphicsSceneHoverEvent* pME) override; + void Update() override; + void UpdateRectangle(); - virtual double GetAngle(const QPointF &pt) const override; + auto GetAngle(const QPointF &pt) const -> double override; - QPointF Rotate(const QPointF& pt, const QPointF& ptCenter, qreal dAng) const; - QPointF GetInsideCorner(int i, qreal dDist) const; + static auto Rotate(const QPointF& pt, const QPointF& ptCenter, qreal dAng) -> QPointF; + auto GetInsideCorner(int i, qreal dDist) const -> QPointF; private: Q_DISABLE_COPY_MOVE(VGrainlineItem) // NOLINT - qreal m_dRotation; - qreal m_dStartRotation; - qreal m_dLength; - QPolygonF m_polyBound; - QPointF m_ptStartPos; - QPointF m_ptStartMove; - QPolygonF m_polyResize; - qreal m_dStartLength; - QPointF m_ptStart; - QPointF m_ptFinish; - QPointF m_ptCenter; - qreal m_dAngle; - GrainlineArrowDirection m_eArrowType; - double m_penWidth{1}; + qreal m_dRotation{0}; + qreal m_dStartRotation{0}; + qreal m_dLength{0}; + QPolygonF m_polyBound{}; + QPointF m_ptStartPos{}; + QPointF m_ptStartMove{}; + QPolygonF m_polyResize{}; + qreal m_dStartLength{0}; + QPointF m_ptStart{}; + QPointF m_ptFinish{}; + QPointF m_ptSecondaryStart{}; + QPointF m_ptSecondaryFinish{}; + QPointF m_ptCenter{}; + qreal m_dAngle{0}; + GrainlineArrowDirection m_eArrowType{GrainlineArrowDirection::twoWaysUpDown}; + double m_penWidth{1}; - QLineF MainLine() const; - QPolygonF FirstArrow(const QPointF &pt, qreal dArrLen) const; - QPolygonF SecondArrow(const QPointF &pt, qreal dArrLen) const; - - QPainterPath MainShape() const; + auto MainShape() const -> QPainterPath; void AllUserModifications(const QPointF &pos); void UserRotateAndMove(); diff --git a/src/libs/vwidgets/vpiecegrainline.cpp b/src/libs/vwidgets/vpiecegrainline.cpp new file mode 100644 index 000000000..ea5485af7 --- /dev/null +++ b/src/libs/vwidgets/vpiecegrainline.cpp @@ -0,0 +1,449 @@ +/************************************************************************ + ** + ** @file vgrainline.cpp + ** @author Roman Telezhynskyi + ** @date 27 4, 2023 + ** + ** @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) 2023 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 "vpiecegrainline.h" +#include "../vgeometry/vabstractcurve.h" +#include "qmath.h" +#include "vpiecegrainline_p.h" + +#include + +namespace +{ +constexpr qreal arrowAngle = M_PI/9; +constexpr int arrowLength = 15; +} + +// VPieceGrainlinePrivate +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainlinePrivate::MainLine(const QPointF &p1, qreal length, qreal angle) -> QLineF +{ + QPointF pt2(p1.x() + length * cos(angle), p1.y() - length * sin(angle)); + return {p1, pt2}; +} + +// VPieceGrainline +//--------------------------------------------------------------------------------------------------------------------- +VPieceGrainline::VPieceGrainline() + :d(new VPieceGrainlinePrivate) +{} + +//--------------------------------------------------------------------------------------------------------------------- +VPieceGrainline::~VPieceGrainline() //NOLINT(modernize-use-equals-default) +{} + +//--------------------------------------------------------------------------------------------------------------------- +VPieceGrainline::VPieceGrainline(const QLineF &mainLine, GrainlineArrowDirection arrowType) + :d (new VPieceGrainlinePrivate(mainLine, arrowType)) +{} + +//--------------------------------------------------------------------------------------------------------------------- +VPieceGrainline::VPieceGrainline(const QPointF &p1, qreal length, qreal angle, GrainlineArrowDirection arrowType) + :d (new VPieceGrainlinePrivate(VPieceGrainlinePrivate::MainLine(p1, length, angle), arrowType)) +{} + +//--------------------------------------------------------------------------------------------------------------------- +VPieceGrainline::VPieceGrainline(const VPieceGrainline &other) //NOLINT(modernize-use-equals-default) + :d (other.d) +{} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::operator=(const VPieceGrainline &grainline) -> VPieceGrainline & +{ + if ( &grainline == this ) + { + return *this; + } + d = grainline.d; + return *this; +} + +#ifdef Q_COMPILER_RVALUE_REFS +//--------------------------------------------------------------------------------------------------------------------- +VPieceGrainline::VPieceGrainline(VPieceGrainline &&grainline) Q_DECL_NOTHROW + : d(std::move(grainline.d)) +{} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::operator=(VPieceGrainline &&grainline) Q_DECL_NOTHROW -> VPieceGrainline & +{ + std::swap(d, grainline.d); + return *this; +} +#endif + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::GetMainLine() const -> QLineF +{ + return d->m_mainLine; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceGrainline::SetMainLine(const QLineF &mainLine) +{ + d->m_mainLine = mainLine; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::GetArrowType() const -> GrainlineArrowDirection +{ + return d->m_arrowType; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceGrainline::SetArrowType(GrainlineArrowDirection arrowType) +{ + d->m_arrowType = arrowType; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::IsEnabled() const -> bool +{ + return d->m_enabled; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceGrainline::SetEnabled(bool enabled) +{ + d->m_enabled = enabled; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::SecondaryLine() const -> QLineF +{ + QLineF mainLine = GetMainLine(); + QLineF secondaryLine = mainLine; + QTransform t; + t.translate(mainLine.center().x(), mainLine.center().y()); + t.rotate(90); + t.translate(-mainLine.center().x(), -mainLine.center().y()); + secondaryLine = t.map(secondaryLine); + return secondaryLine; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::IsFourWays() const -> bool +{ + return d->m_arrowType == GrainlineArrowDirection::fourWays || + d->m_arrowType == GrainlineArrowDirection::twoWaysUpLeft || + d->m_arrowType == GrainlineArrowDirection::twoWaysUpRight || + d->m_arrowType == GrainlineArrowDirection::twoWaysDownLeft || + d->m_arrowType == GrainlineArrowDirection::twoWaysDownRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpDownLeft || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpDownRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpLeftRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysDownLeftRight; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::IsArrowUpEnabled() const -> bool +{ + return d->m_arrowType == GrainlineArrowDirection::oneWayUp || + d->m_arrowType == GrainlineArrowDirection::twoWaysUpDown || + d->m_arrowType == GrainlineArrowDirection::twoWaysUpLeft || + d->m_arrowType == GrainlineArrowDirection::twoWaysUpRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpDownLeft || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpDownRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpLeftRight || + d->m_arrowType == GrainlineArrowDirection::fourWays; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::IsArrowDownEnabled() const -> bool +{ + return d->m_arrowType == GrainlineArrowDirection::oneWayDown || + d->m_arrowType == GrainlineArrowDirection::twoWaysUpDown || + d->m_arrowType == GrainlineArrowDirection::twoWaysDownLeft || + d->m_arrowType == GrainlineArrowDirection::twoWaysDownRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpDownLeft || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpDownRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysDownLeftRight || + d->m_arrowType == GrainlineArrowDirection::fourWays; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::IsArrowLeftEnabled() const -> bool +{ + return d->m_arrowType == GrainlineArrowDirection::fourWays || + d->m_arrowType == GrainlineArrowDirection::twoWaysUpLeft || + d->m_arrowType == GrainlineArrowDirection::twoWaysDownLeft || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpDownLeft || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpLeftRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysDownLeftRight; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::IsArrowRightEnabled() const -> bool +{ + return d->m_arrowType == GrainlineArrowDirection::fourWays || + d->m_arrowType == GrainlineArrowDirection::twoWaysUpRight || + d->m_arrowType == GrainlineArrowDirection::twoWaysDownRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpDownRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysUpLeftRight || + d->m_arrowType == GrainlineArrowDirection::threeWaysDownLeftRight; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::ArrowUp() const -> QPolygonF +{ + const QLineF mainLine = GetMainLine(); + const qreal rotation = M_PI + qDegreesToRadians(mainLine.angle()); + const QPointF pt = mainLine.p2(); + + return { + pt, + QPointF(pt.x() + arrowLength * cos(rotation + arrowAngle), pt.y() - arrowLength * sin(rotation + arrowAngle)), + QPointF(pt.x() + arrowLength * cos(rotation - arrowAngle), pt.y() - arrowLength * sin(rotation - arrowAngle)), + pt}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::ArrowDown() const -> QPolygonF +{ + const QLineF mainLine = GetMainLine(); + const qreal rotation = qDegreesToRadians(mainLine.angle()); + const QPointF pt = mainLine.p1(); + + return { + pt, + QPointF(pt.x() + arrowLength * cos(rotation + arrowAngle), pt.y() - arrowLength * sin(rotation + arrowAngle)), + QPointF(pt.x() + arrowLength * cos(rotation - arrowAngle), pt.y() - arrowLength * sin(rotation - arrowAngle)), + pt}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::ArrowLeft() const -> QPolygonF +{ + const qreal rotation = 3 * M_PI / 2 + qDegreesToRadians(GetMainLine().angle()); + const QPointF pt = SecondaryLine().p1(); + + return { + pt, + QPointF(pt.x() + arrowLength * cos(rotation - arrowAngle), pt.y() - arrowLength * sin(rotation - arrowAngle)), + QPointF(pt.x() + arrowLength * cos(rotation + arrowAngle), pt.y() - arrowLength * sin(rotation + arrowAngle)), + pt}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::ArrowRight() const -> QPolygonF +{ + const qreal rotation = M_PI / 2 + qDegreesToRadians(GetMainLine().angle()); + const QPointF pt = SecondaryLine().p2(); + + return { + pt, + QPointF(pt.x() + arrowLength * cos(rotation + arrowAngle), pt.y() - arrowLength * sin(rotation + arrowAngle)), + QPointF(pt.x() + arrowLength * cos(rotation - arrowAngle), pt.y() - arrowLength * sin(rotation - arrowAngle)), + pt}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::Shape() const -> GrainlineShape +{ + const QLineF mainLine = GetMainLine(); + if (mainLine.isNull()) + { + return {}; + } + + // main arrow + QVector arrow1; + + if (IsArrowDownEnabled()) + { + arrow1 << ArrowDown(); + } + else + { + arrow1 << mainLine.p1(); + } + + if (IsArrowUpEnabled()) + { + arrow1 << ArrowUp(); + } + else + { + arrow1 << mainLine.p2(); + } + + if (IsFourWays()) + { + // secondary arrow + QVector arrow2; + const QLineF secondaryLine = SecondaryLine(); + + if (IsArrowLeftEnabled()) + { + arrow2 << ArrowLeft(); + } + else + { + arrow2 << secondaryLine.p1(); + } + + if (IsArrowRightEnabled()) + { + arrow2 << ArrowRight(); + } + else + { + arrow2 << secondaryLine.p2(); + } + + return {arrow1, arrow2}; + } + + return {arrow1}; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief VPieceGrainline::IsContained checks, if all ends of the grainline, starting at pt, are contained in + * parent widget. + * @param boundingRect bounding rect of piece + * @param dX horizontal translation needed to put the arrow inside parent item + * @param dY vertical translation needed to put the arrow inside parent item + * @return true, if all ends of the grainline, starting at pt, are contained in the bounding rect of piece and + * false otherwise. + */ +auto VPieceGrainline::IsContained(const QRectF &boundingRect, qreal &dX, qreal &dY) const -> bool +{ + dX = 0; + dY = 0; + + const QLineF mainLine = GetMainLine(); + QVector apt = {mainLine.p1(), mainLine.p2()}; + if (IsFourWays()) + { + const QLineF secondaryLine = SecondaryLine(); + apt.append(secondaryLine.p1()); + apt.append(secondaryLine.p2()); + } + + // single point differences + qreal dPtX; + qreal dPtY; + bool bInside = true; + + for (auto item : apt) + { + dPtX = 0; + dPtY = 0; + if (boundingRect.contains(item)) + { + continue; + } + + if (item.x() < boundingRect.left()) + { + dPtX = boundingRect.left() - item.x(); + } + else if (item.x() > boundingRect.right()) + { + dPtX = boundingRect.right() - item.x(); + } + if (item.y() < boundingRect.top()) + { + dPtY = boundingRect.top() - item.y(); + } + else if (item.y() > boundingRect.bottom()) + { + dPtY = boundingRect.bottom() - item.y(); + } + + if (fabs(dPtX) > fabs(dX)) + { + dX = dPtX; + } + if (fabs(dPtY) > fabs(dY)) + { + dY = dPtY; + } + + bInside = false; + } + return bInside; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::IsPositionValid(const QVector &contourPoints) const -> bool +{ + QVector grainLine; + QLineF mainLine = GetMainLine(); + if (IsFourWays ()) + { + grainLine = {mainLine, SecondaryLine()}; + } + + grainLine = {mainLine}; + + for (auto line : grainLine) + { + QVector points = VAbstractCurve::CurveIntersectLine(contourPoints, line); + for (auto &point : points) + { + if (not VFuzzyComparePoints (line.p1 (), point) && not VFuzzyComparePoints (line.p2 (), point)) + { + return false; + } + } + } + + QPainterPath grainLinePath; + for (auto line : grainLine) + { + grainLinePath.addPath(VGObject::PainterPath(QVector{line.p1(), line.p2()})); + } + const QPainterPath contourPath = VGObject::PainterPath(contourPoints); + return contourPath.contains(grainLinePath); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPieceGrainline::IsShapeValid() const -> bool +{ + GrainlineShape shape = Shape(); + return std::ranges::all_of(shape, [](const auto& subShape) + { + return not subShape.isEmpty(); + }); +} + +// Friend functions +//--------------------------------------------------------------------------------------------------------------------- +auto operator<<(QDataStream &dataStream, const VPieceGrainline &grainline) -> QDataStream & +{ + dataStream << *grainline.d; + return dataStream; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto operator>>(QDataStream &dataStream, VPieceGrainline &grainline) -> QDataStream & +{ + dataStream >> *grainline.d; + return dataStream; +} diff --git a/src/libs/vwidgets/vpiecegrainline.h b/src/libs/vwidgets/vpiecegrainline.h new file mode 100644 index 000000000..11288f95c --- /dev/null +++ b/src/libs/vwidgets/vpiecegrainline.h @@ -0,0 +1,98 @@ +/************************************************************************ + ** + ** @file vpiecegrainline.h + ** @author Roman Telezhynskyi + ** @date 27 4, 2023 + ** + ** @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) 2023 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 . + ** + *************************************************************************/ +#ifndef VPIECEGRAINLINE_H +#define VPIECEGRAINLINE_H + +#include +#include +#include "../vpatterndb/floatItemData/floatitemdef.h" + +class QPointF; +class VPieceGrainlinePrivate; +class QLineF; +class QPolygonF; +class QRectF; + +using GrainlineShape = QVector>; + +class VPieceGrainline +{ +public: + VPieceGrainline(); + VPieceGrainline(const QLineF &mainLine, GrainlineArrowDirection arrowType); + VPieceGrainline(const QPointF &p1, qreal length, qreal angle, GrainlineArrowDirection arrowType); + VPieceGrainline(const VPieceGrainline &other); + + ~VPieceGrainline(); + + auto operator=(const VPieceGrainline &grainline) -> VPieceGrainline &; +#ifdef Q_COMPILER_RVALUE_REFS + VPieceGrainline(VPieceGrainline &&grainline) Q_DECL_NOTHROW; + auto operator=(VPieceGrainline &&grainline) Q_DECL_NOTHROW -> VPieceGrainline &; +#endif + + auto GetMainLine() const -> QLineF; + void SetMainLine(const QLineF &mainLine); + + auto GetArrowType() const -> GrainlineArrowDirection; + void SetArrowType(GrainlineArrowDirection arrowType); + + auto IsEnabled() const -> bool; + void SetEnabled(bool enabled); + + auto SecondaryLine() const -> QLineF; + + auto IsFourWays() const -> bool; + + auto IsArrowUpEnabled() const -> bool; + auto IsArrowDownEnabled() const -> bool; + auto IsArrowLeftEnabled() const -> bool; + auto IsArrowRightEnabled() const -> bool; + + auto ArrowUp() const -> QPolygonF; + auto ArrowDown() const -> QPolygonF; + auto ArrowLeft() const -> QPolygonF; + auto ArrowRight() const -> QPolygonF; + + auto Shape() const -> GrainlineShape; + + auto IsContained(const QRectF &boundingRect, qreal &dX, qreal &dY) const -> bool; + auto IsPositionValid(const QVector &contourPoints) const -> bool; + + auto IsShapeValid() const -> bool; + + friend auto operator<< (QDataStream& dataStream, const VPieceGrainline& grainline) -> QDataStream&; + friend auto operator>> (QDataStream& dataStream, VPieceGrainline& grainline) -> QDataStream&; +private: + QSharedDataPointer d; +}; + +Q_DECLARE_METATYPE(VPieceGrainline) +Q_DECLARE_TYPEINFO(VPieceGrainline, Q_MOVABLE_TYPE); // NOLINT + +#endif // VPIECEGRAINLINE_H diff --git a/src/libs/vwidgets/vpiecegrainline_p.h b/src/libs/vwidgets/vpiecegrainline_p.h new file mode 100644 index 000000000..7086977e0 --- /dev/null +++ b/src/libs/vwidgets/vpiecegrainline_p.h @@ -0,0 +1,125 @@ +/************************************************************************ + ** + ** @file vpiecegrainline_p.h + ** @author Roman Telezhynskyi + ** @date 27 4, 2023 + ** + ** @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) 2023 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 . + ** + *************************************************************************/ +#ifndef VPIECEGRAINLINE_P_H +#define VPIECEGRAINLINE_P_H + +#include +#include +#include "../vmisc/defglobal.h" +#include "../ifc/exception/vexception.h" +#include "vpatterndb/floatItemData/floatitemdef.h" + +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Weffc++") +QT_WARNING_DISABLE_GCC("-Wnon-virtual-dtor") + +class VPieceGrainlinePrivate : public QSharedData +{ +public: + VPieceGrainlinePrivate(){} // NOLINT(modernize-use-equals-default) + VPieceGrainlinePrivate(const QLineF &mainLine, GrainlineArrowDirection arrowType) + : m_mainLine(mainLine), + m_arrowType(arrowType), + m_enabled(true) + {} + + VPieceGrainlinePrivate(const VPieceGrainlinePrivate &data) = default; + ~VPieceGrainlinePrivate() = default; + + static auto MainLine(const QPointF &p1, qreal length, qreal angle) -> QLineF; + + friend auto operator<<(QDataStream& dataStream, const VPieceGrainlinePrivate& data) -> QDataStream&; + friend auto operator>>(QDataStream& dataStream, VPieceGrainlinePrivate& data) -> QDataStream&; + + QLineF m_mainLine{}; // NOLINT(misc-non-private-member-variables-in-classes) + GrainlineArrowDirection m_arrowType{GrainlineArrowDirection::oneWayUp}; // NOLINT(misc-non-private-member-variables-in-classes) + bool m_enabled{false}; // NOLINT(misc-non-private-member-variables-in-classes) + +private: + Q_DISABLE_ASSIGN_MOVE(VPieceGrainlinePrivate) // NOLINT + + static constexpr quint32 streamHeader{0x5C5D5B3B}; // CRC-32Q string "VGrainlineData" + static constexpr quint16 classVersion{1}; +}; + +QT_WARNING_POP + +// See https://stackoverflow.com/a/46719572/3045403 +#if __cplusplus < 201703L // C++17 +constexpr quint32 VPieceGrainlinePrivate::streamHeader; // NOLINT(readability-redundant-declaration) +constexpr quint16 VPieceGrainlinePrivate::classVersion; // NOLINT(readability-redundant-declaration) +#endif + +// Friend functions +//--------------------------------------------------------------------------------------------------------------------- +inline auto operator<<(QDataStream &dataStream, const VPieceGrainlinePrivate &data) -> QDataStream & +{ + dataStream << VPieceGrainlinePrivate::streamHeader << VPieceGrainlinePrivate::classVersion; + + // Added in classVersion = 1 + dataStream << data.m_enabled; + dataStream << data.m_arrowType; + dataStream << data.m_mainLine; + + return dataStream; +} + +//--------------------------------------------------------------------------------------------------------------------- +inline auto operator>>(QDataStream &dataStream, VPieceGrainlinePrivate &data) -> QDataStream & +{ + quint32 actualStreamHeader = 0; + dataStream >> actualStreamHeader; + + if (actualStreamHeader != VPieceGrainlinePrivate::streamHeader) + { + QString message = QCoreApplication::tr("VPieceGrainlinePrivate prefix mismatch error: actualStreamHeader = " + "0x%1 and streamHeader = 0x%2") + .arg(actualStreamHeader, 8, 0x10, QChar('0')) + .arg(VPieceGrainlinePrivate::streamHeader, 8, 0x10, QChar('0')); + throw VException(message); + } + + quint16 actualClassVersion = 0; + dataStream >> actualClassVersion; + + if (actualClassVersion > VPieceGrainlinePrivate::classVersion) + { + QString message = QCoreApplication::tr("VPieceGrainlinePrivate compatibility error: actualClassVersion = %1 " + "and classVersion = %2") + .arg(actualClassVersion).arg(VPieceGrainlinePrivate::classVersion); + throw VException(message); + } + + dataStream >> data.m_enabled; + dataStream >> data.m_arrowType; + dataStream >> data.m_mainLine; + + return dataStream; +} + +#endif // VPIECEGRAINLINE_P_H diff --git a/src/libs/vwidgets/vwidgets.pri b/src/libs/vwidgets/vwidgets.pri index 023e5efb0..aca055560 100644 --- a/src/libs/vwidgets/vwidgets.pri +++ b/src/libs/vwidgets/vwidgets.pri @@ -28,7 +28,8 @@ SOURCES += \ $$PWD/scalesceneitems.cpp \ $$PWD/vlineedit.cpp \ $$PWD/vplaintextedit.cpp \ - $$PWD/vhighlighter.cpp + $$PWD/vhighlighter.cpp \ + $$PWD/vpiecegrainline.cpp *msvc*:SOURCES += $$PWD/stable.cpp @@ -60,4 +61,6 @@ HEADERS += \ $$PWD/scalesceneitems.h \ $$PWD/vlineedit.h \ $$PWD/vplaintextedit.h \ - $$PWD/vhighlighter.h + $$PWD/vhighlighter.h \ + $$PWD/vpiecegrainline.h \ + $$PWD/vpiecegrainline_p.h diff --git a/src/libs/vwidgets/vwidgets.qbs b/src/libs/vwidgets/vwidgets.qbs index d3cab934f..7403753b8 100644 --- a/src/libs/vwidgets/vwidgets.qbs +++ b/src/libs/vwidgets/vwidgets.qbs @@ -4,6 +4,7 @@ VLib { Depends { name: "Qt"; submodules: ["core", "widgets"] } Depends { name: "VMiscLib" } Depends { name: "VPropertyExplorerLib" } + Depends { name: "VPatternDBLib" } Depends { name: "Qt.openglwidgets"; @@ -65,7 +66,10 @@ VLib { "scalesceneitems.h", "vlineedit.h", "vplaintextedit.h", - "vhighlighter.h" + "vhighlighter.h", + "vpiecegrainline.h", + "vpiecegrainline.cpp", + "vpiecegrainline_p.h" ] Export {