From cb036e8d43e13c2f8aa1ec4c7ba59b57f1e9164b Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Wed, 24 Nov 2021 14:15:21 +0200 Subject: [PATCH] New path validation Invalid segment. --- ChangeLog.txt | 1 + src/libs/vtools/dialogs/dialogtoolbox.cpp | 229 +++++++++++++++--- src/libs/vtools/dialogs/dialogtoolbox.h | 9 +- .../dialogs/tools/piece/dialogpiecepath.cpp | 26 +- .../tools/piece/dialogseamallowance.cpp | 27 ++- 5 files changed, 248 insertions(+), 44 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 6dafedc44..a17a41f5a 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -26,6 +26,7 @@ - Improve for a search bar. - Backport fix vulnerability CVE-2021-21900. - Improved main path validations. +- New path validation Invalid segment. # Valentina 0.7.49 July 1, 2021 - Fix crash. diff --git a/src/libs/vtools/dialogs/dialogtoolbox.cpp b/src/libs/vtools/dialogs/dialogtoolbox.cpp index 2f3eeeced..fafca7ab6 100644 --- a/src/libs/vtools/dialogs/dialogtoolbox.cpp +++ b/src/libs/vtools/dialogs/dialogtoolbox.cpp @@ -64,17 +64,12 @@ namespace const int dialogMaxFormulaHeight = 80; //--------------------------------------------------------------------------------------------------------------------- -auto DoublePoint(const VPieceNode &firstNode, const VPieceNode &secondNode, const VContainer *data) -> bool +auto DoublePoint(const VPieceNode &firstNode, const VPieceNode &secondNode, const VContainer *data, + QString &error) -> bool { if (firstNode.GetTypeTool() == Tool::NodePoint && not (firstNode.GetId() == NULL_ID) && secondNode.GetTypeTool() == Tool::NodePoint && not (secondNode.GetId() == NULL_ID)) { - // don't ignore the same point twice - if (firstNode.GetId() == secondNode.GetId()) - { - return true; - } - QSharedPointer firstPoint; QSharedPointer secondPoint; @@ -85,6 +80,13 @@ auto DoublePoint(const VPieceNode &firstNode, const VPieceNode &secondNode, cons } catch(const VExceptionBadId &) { + return false; + } + + // don't ignore the same point twice + if (firstNode.GetId() == secondNode.GetId()) + { + error = QObject::tr("Point '%1' repeats twice").arg(firstPoint->name()); return true; } @@ -92,6 +94,7 @@ auto DoublePoint(const VPieceNode &firstNode, const VPieceNode &secondNode, cons if (firstPoint->getIdObject() != NULL_ID && secondPoint->getIdObject() != NULL_ID && firstPoint->getIdObject() == secondPoint->getIdObject()) { + error = QObject::tr("Point '%1' repeats twice").arg(firstPoint->name()); return true; } @@ -101,39 +104,52 @@ auto DoublePoint(const VPieceNode &firstNode, const VPieceNode &secondNode, cons return false; } - return firstPoint->toQPointF() == secondPoint->toQPointF(); + bool sameCoordinates = VFuzzyComparePoints(firstPoint->toQPointF(), secondPoint->toQPointF()); + if (sameCoordinates) + { + error = QObject::tr("Points '%1' and '%2' have the same coordinates.") + .arg(firstPoint->name(), secondPoint->name()); + } + + return sameCoordinates; } return false; } //--------------------------------------------------------------------------------------------------------------------- -auto DoubleCurve(const VPieceNode &firstNode, const VPieceNode &secondNode, const VContainer *data) -> bool +auto DoubleCurve(const VPieceNode &firstNode, const VPieceNode &secondNode, const VContainer *data, + QString &error) -> bool { if (firstNode.GetTypeTool() != Tool::NodePoint && not (firstNode.GetId() == NULL_ID) && secondNode.GetTypeTool() != Tool::NodePoint && not (secondNode.GetId() == NULL_ID)) { - // don't ignore the same curve twice - if (firstNode.GetId() == secondNode.GetId()) - { - return true; - } + QSharedPointer curve1; + QSharedPointer curve2; try { - // The same curve, but different modeling objects - const QSharedPointer curve1 = data->GetGObject(firstNode.GetId()); - const QSharedPointer curve2 = data->GetGObject(secondNode.GetId()); - - if (curve1->getIdObject() == curve2->getIdObject()) - { - return true; - } + curve1 = data->GetGObject(firstNode.GetId()); + curve2 = data->GetGObject(secondNode.GetId()); } catch (const VExceptionBadId &) { return false; } + + // don't ignore the same curve twice + if (firstNode.GetId() == secondNode.GetId()) + { + error = QObject::tr("Leave only one copy of curve '%1'").arg(curve1->name()); + return true; + } + + // The same curve, but different modeling objects + if (curve1->getIdObject() == curve2->getIdObject()) + { + error = QObject::tr("Leave only one copy of curve '%1'").arg(curve1->name()); + return true; + } } return false; @@ -422,7 +438,7 @@ int FindNotExcludedNodeUp(QListWidget *listWidget, int candidate) } //--------------------------------------------------------------------------------------------------------------------- -bool FirstPointEqualLast(QListWidget *listWidget, const VContainer *data) +bool FirstPointEqualLast(QListWidget *listWidget, const VContainer *data, QString &error) { SCASSERT(listWidget != nullptr); if (listWidget->count() > 1) @@ -430,13 +446,13 @@ bool FirstPointEqualLast(QListWidget *listWidget, const VContainer *data) const VPieceNode topNode = RowNode(listWidget, FindNotExcludedNodeDown(listWidget, 0)); const VPieceNode bottomNode = RowNode(listWidget, FindNotExcludedNodeUp(listWidget, listWidget->count()-1)); - return DoublePoint(topNode, bottomNode, data); + return DoublePoint(topNode, bottomNode, data, error); } return false; } //--------------------------------------------------------------------------------------------------------------------- -bool DoublePoints(QListWidget *listWidget, const VContainer *data) +bool DoublePoints(QListWidget *listWidget, const VContainer *data, QString &error) { SCASSERT(listWidget != nullptr); for (int i=0, sz = listWidget->count()-1; i bool +auto DoubleCurves(QListWidget *listWidget, const VContainer *data, QString &error) -> bool { SCASSERT(listWidget != nullptr); for (int i=0, sz = listWidget->count()-1; i bool const VPieceNode firstNode = RowNode(listWidget, firstIndex); const VPieceNode secondNode = RowNode(listWidget, FindNotExcludedNodeDown(listWidget, firstIndex+1)); - if (DoubleCurve(firstNode, secondNode, data)) + if (DoubleCurve(firstNode, secondNode, data, error)) { return true; } @@ -659,3 +675,160 @@ QString GetNodeName(const VContainer *data, const VPieceNode &node, bool showPas return name; } + +//--------------------------------------------------------------------------------------------------------------------- +auto FindNotExcludedPointDown(QListWidget *listWidget, int start) -> int +{ + SCASSERT(listWidget != nullptr); + + int index = -1; + if (start < 0 || start >= listWidget->count()) + { + return index; + } + + int i = start; + int count = 0; + do + { + const QListWidgetItem *rowItem = listWidget->item(i); + SCASSERT(rowItem != nullptr); + auto rowNode = qvariant_cast(rowItem->data(Qt::UserRole)); + + if (not rowNode.IsExcluded() && rowNode.GetTypeTool() == Tool::NodePoint && rowNode.GetId() != NULL_ID) + { + index = i; + break; + } + + ++i; + if (i >= listWidget->count()) + { + i = 0; + } + + ++count; + } + while (count < listWidget->count()); + + return index; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto FindNotExcludedCurveDown(QListWidget *listWidget, int start) -> int +{ + SCASSERT(listWidget != nullptr); + + int index = -1; + if (start < 0 || start >= listWidget->count()) + { + return index; + } + + int i = start; + int count = 0; + do + { + const QListWidgetItem *rowItem = listWidget->item(i); + SCASSERT(rowItem != nullptr); + auto rowNode = qvariant_cast(rowItem->data(Qt::UserRole)); + + if (not rowNode.IsExcluded() && rowNode.GetTypeTool() != Tool::NodePoint && rowNode.GetId() != NULL_ID) + { + index = i; + break; + } + + ++i; + if (i >= listWidget->count()) + { + i = 0; + } + + ++count; + } + while (count < listWidget->count()); + + return index; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto InvalidSegment(QListWidget *listWidget, const VContainer *data, QString &error) -> bool +{ + SCASSERT(listWidget != nullptr); + + for (int index=0; index < listWidget->count(); ++index) + { + int firstCurveIndex = -1; + int pointIndex = -1; + int secondCurveIndex = -1; + + auto FindPair = [listWidget, &firstCurveIndex, &pointIndex, &secondCurveIndex]( int start) + { + for (int i=start; i < listWidget->count(); ++i) + { + firstCurveIndex = FindNotExcludedCurveDown(listWidget, i); + if (firstCurveIndex == -1) + { + continue; + } + + pointIndex = FindNotExcludedPointDown(listWidget, firstCurveIndex+1); + if (pointIndex == -1) + { + continue; + } + + secondCurveIndex = FindNotExcludedCurveDown(listWidget, pointIndex+1); + if (secondCurveIndex == -1 || firstCurveIndex == secondCurveIndex) + { + continue; + } + + return true; + } + + return false; + }; + + if (not FindPair(index)) + { + continue; + } + + const VPieceNode firstCurveNode = RowNode(listWidget, firstCurveIndex); + const VPieceNode secondCurveNode = RowNode(listWidget, secondCurveIndex); + + QString errorDoubleCurve; + if (not DoubleCurve(firstCurveNode, secondCurveNode, data, errorDoubleCurve)) + { + continue; + } + + const VPieceNode pointNode = RowNode(listWidget, pointIndex); + if (pointNode.GetId() == NULL_ID) + { + continue; + } + + try + { + const QSharedPointer curve1 = data->GeometricObject(firstCurveNode.GetId()); + const QSharedPointer point = data->GeometricObject(pointNode.GetId()); + + error = QObject::tr("Point '%1' does not lie on a curve '%2'").arg(point->name(), curve1->name()); + + bool validSegment = curve1->IsPointOnCurve(point->toQPointF()); + if (not validSegment) + { + return true; + } + } + catch (const VExceptionBadId &) + { + continue; + } + } + + return false; +} diff --git a/src/libs/vtools/dialogs/dialogtoolbox.h b/src/libs/vtools/dialogs/dialogtoolbox.h index 99e4ab41b..c35f8d420 100644 --- a/src/libs/vtools/dialogs/dialogtoolbox.h +++ b/src/libs/vtools/dialogs/dialogtoolbox.h @@ -80,10 +80,13 @@ void CheckPointLabel(QDialog *dialog, QLineEdit* edit, QLabel *labelEditNamePo const VContainer *data, bool &flag); int FindNotExcludedNodeDown(QListWidget *listWidget, int candidate); int FindNotExcludedNodeUp(QListWidget *listWidget, int candidate); -bool FirstPointEqualLast(QListWidget *listWidget, const VContainer *data); -bool DoublePoints(QListWidget *listWidget, const VContainer *data); -bool DoubleCurves(QListWidget *listWidget, const VContainer *data); +int FindNotExcludedPointDown(QListWidget *listWidget, int start); +int FindNotExcludedCurveDown(QListWidget *listWidget, int start); +bool FirstPointEqualLast(QListWidget *listWidget, const VContainer *data, QString &error); +bool DoublePoints(QListWidget *listWidget, const VContainer *data, QString &error); +bool DoubleCurves(QListWidget *listWidget, const VContainer *data, QString &error); bool EachPointLabelIsUnique(QListWidget *listWidget); +bool InvalidSegment(QListWidget *listWidget, const VContainer *data, QString &error); QString DialogWarningIcon(); QFont NodeFont(QFont font, bool nodeExcluded = false); void CurrentCurveLength(vidtype curveId, VContainer *data); diff --git a/src/libs/vtools/dialogs/tools/piece/dialogpiecepath.cpp b/src/libs/vtools/dialogs/tools/piece/dialogpiecepath.cpp index 88d6e5016..6544e58fa 100644 --- a/src/libs/vtools/dialogs/tools/piece/dialogpiecepath.cpp +++ b/src/libs/vtools/dialogs/tools/piece/dialogpiecepath.cpp @@ -1631,22 +1631,27 @@ auto DialogPiecePath::PathIsValid() const -> bool return false; } - if (GetType() == PiecePathType::CustomSeamAllowance && FirstPointEqualLast(ui->listWidget, data)) + QString error; + if (GetType() == PiecePathType::CustomSeamAllowance && FirstPointEqualLast(ui->listWidget, data, error)) { - ui->helpLabel->setText(DialogWarningIcon() + - tr("First point of custom seam allowance cannot be equal to the last point!")); + ui->helpLabel->setText( + QString("%1%2 %3") + .arg(DialogWarningIcon(), + tr("First point of custom seam allowance cannot be equal to the last point!"), error)); return false; } - if (DoublePoints(ui->listWidget, data)) + error.clear(); + if (DoublePoints(ui->listWidget, data, error)) { - ui->helpLabel->setText(DialogWarningIcon() + tr("You have double points!")); + ui->helpLabel->setText(QString("%1%2 %3").arg(DialogWarningIcon(), tr("You have double points!"), error)); return false; } - if (DoubleCurves(ui->listWidget, data)) + error.clear(); + if (DoubleCurves(ui->listWidget, data, error)) { - ui->helpLabel->setText(DialogWarningIcon() + tr("The same curve repeats twice!")); + ui->helpLabel->setText(QString("%1%2 %3").arg(DialogWarningIcon(), tr("The same curve repeats twice!"), error)); return false; } @@ -1669,6 +1674,13 @@ auto DialogPiecePath::PathIsValid() const -> bool return false; } + error.clear(); + if (InvalidSegment(ui->listWidget, data, error)) + { + ui->helpLabel->setText(QString("%1%2 %3").arg(DialogWarningIcon(), tr("Invalid segment!"), error)); + return false; + } + ui->helpLabel->setText(tr("Ready!")); return true; } diff --git a/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp b/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp index 5bdd987f9..3191aa1fa 100644 --- a/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp +++ b/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp @@ -2698,21 +2698,28 @@ auto DialogSeamAllowance::MainPathIsValid() const -> bool return false; } - if (FirstPointEqualLast(uiTabPaths->listWidgetMainPath, data)) + QString error; + if (FirstPointEqualLast(uiTabPaths->listWidgetMainPath, data, error)) { - uiTabPaths->helpLabel->setText(DialogWarningIcon() + tr("First point cannot be equal to the last point!")); + uiTabPaths->helpLabel->setText( + QString("%1%2 %3").arg(DialogWarningIcon(), + tr("First point cannot be equal to the last point!"), error)); return false; } - if (DoublePoints(uiTabPaths->listWidgetMainPath, data)) + error.clear(); + if (DoublePoints(uiTabPaths->listWidgetMainPath, data, error)) { - uiTabPaths->helpLabel->setText(DialogWarningIcon() + tr("You have double points!")); + uiTabPaths->helpLabel->setText(QString("%1%2 %3") + .arg(DialogWarningIcon(), tr("You have double points!"), error)); return false; } - if (DoubleCurves(uiTabPaths->listWidgetMainPath, data)) + error.clear(); + if (DoubleCurves(uiTabPaths->listWidgetMainPath, data, error)) { - uiTabPaths->helpLabel->setText(DialogWarningIcon() + tr("The same curve repeats twice!")); + uiTabPaths->helpLabel->setText(QString("%1%2 %3") + .arg(DialogWarningIcon(), tr("The same curve repeats twice!"), error)); return false; } @@ -2722,6 +2729,14 @@ auto DialogSeamAllowance::MainPathIsValid() const -> bool return false; } + error.clear(); + if (InvalidSegment(uiTabPaths->listWidgetMainPath, data, error)) + { + uiTabPaths->helpLabel->setText(QString("%1%2 %3") + .arg(DialogWarningIcon(), tr("Invalid segment!"), error)); + return false; + } + return true; }