Resolved issue #818. Improve Piece path validation. Check uniqueness.

--HG--
branch : develop
This commit is contained in:
Roman Telezhynskyi 2018-03-05 12:05:59 +02:00
parent 5f500e9b4d
commit cb5b7fcfcd
16 changed files with 1215 additions and 57 deletions

View File

@ -46,6 +46,7 @@
- [#667] Check for updates - Test version.
- [#808] New feature. Global line width option.
- [#814] Make "\" valid character.
- [#818] Improve Piece path validation. Check uniqueness.
# Version 0.5.1
- [#683] Tool Seam allowance's dialog is off screen on small resolutions.

View File

@ -48,6 +48,7 @@
<file>schema/pattern/v0.7.4.xsd</file>
<file>schema/pattern/v0.7.5.xsd</file>
<file>schema/pattern/v0.7.6.xsd</file>
<file>schema/pattern/v0.7.7.xsd</file>
<file>schema/standard_measurements/v0.3.0.xsd</file>
<file>schema/standard_measurements/v0.4.0.xsd</file>
<file>schema/standard_measurements/v0.4.1.xsd</file>

File diff suppressed because it is too large Load Diff

View File

@ -129,6 +129,7 @@ const QString VAbstractPattern::AttrEnd = QStringLiteral("end");
const QString VAbstractPattern::AttrIncludeAs = QStringLiteral("includeAs");
const QString VAbstractPattern::AttrRotation = QStringLiteral("rotation");
const QString VAbstractPattern::AttrNumber = QStringLiteral("number");
const QString VAbstractPattern::AttrCheckUniqueness = QStringLiteral("checkUniqueness");
const QString VAbstractPattern::AttrAll = QStringLiteral("all");
@ -686,6 +687,7 @@ VPieceNode VAbstractPattern::ParseSANode(const QDomElement &domElement)
const quint32 id = VDomDocument::GetParametrUInt(domElement, AttrIdObject, NULL_ID_STR);
const bool reverse = VDomDocument::GetParametrUInt(domElement, VAbstractPattern::AttrNodeReverse, "0");
const bool excluded = VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrNodeExcluded, falseStr);
const bool uniqeness = VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrCheckUniqueness, trueStr);
const QString saBefore = VDomDocument::GetParametrString(domElement, VAbstractPattern::AttrSABefore,
currentSeamAllowance);
const QString saAfter = VDomDocument::GetParametrString(domElement, VAbstractPattern::AttrSAAfter,
@ -738,6 +740,7 @@ VPieceNode VAbstractPattern::ParseSANode(const QDomElement &domElement)
node.SetFormulaSAAfter(saAfter);
node.SetAngleType(angle);
node.SetExcluded(excluded);
node.SetCheckUniqueness(uniqeness);
node.SetShowSecondPassmark(showSecond);
node.SetPassmark(passmark);
node.SetPassmarkLineType(passmarkLine);

View File

@ -271,6 +271,7 @@ public:
static const QString AttrIncludeAs;
static const QString AttrRotation;
static const QString AttrNumber;
static const QString AttrCheckUniqueness;
static const QString AttrAll;

View File

@ -58,8 +58,8 @@ class QDomElement;
*/
const QString VPatternConverter::PatternMinVerStr = QStringLiteral("0.1.0");
const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.7.6");
const QString VPatternConverter::CurrentSchema = QStringLiteral("://schema/pattern/v0.7.6.xsd");
const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.7.7");
const QString VPatternConverter::CurrentSchema = QStringLiteral("://schema/pattern/v0.7.7.xsd");
//VPatternConverter::PatternMinVer; // <== DON'T FORGET TO UPDATE TOO!!!!
//VPatternConverter::PatternMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!!
@ -222,7 +222,8 @@ QString VPatternConverter::XSDSchema(int ver) const
std::make_pair(0x000703, QStringLiteral("://schema/pattern/v0.7.3.xsd")),
std::make_pair(0x000704, QStringLiteral("://schema/pattern/v0.7.4.xsd")),
std::make_pair(0x000705, QStringLiteral("://schema/pattern/v0.7.5.xsd")),
std::make_pair(0x000706, CurrentSchema)
std::make_pair(0x000706, QStringLiteral("://schema/pattern/v0.7.6.xsd")),
std::make_pair(0x000707, CurrentSchema)
};
if (schemas.contains(ver))
@ -429,6 +430,10 @@ void VPatternConverter::ApplyPatches()
ValidateXML(XSDSchema(0x000706), m_convertedFileName);
V_FALLTHROUGH
case (0x000706):
ToV0_7_7();
ValidateXML(XSDSchema(0x000707), m_convertedFileName);
V_FALLTHROUGH
case (0x000707):
break;
default:
InvalidVersion(m_ver);
@ -446,7 +451,7 @@ void VPatternConverter::DowngradeToCurrentMaxVersion()
bool VPatternConverter::IsReadOnly() const
{
// Check if attribute readOnly was not changed in file format
Q_STATIC_ASSERT_X(VPatternConverter::PatternMaxVer == CONVERTER_VERSION_CHECK(0, 7, 6),
Q_STATIC_ASSERT_X(VPatternConverter::PatternMaxVer == CONVERTER_VERSION_CHECK(0, 7, 7),
"Check attribute readOnly.");
// Possibly in future attribute readOnly will change position etc.
@ -980,6 +985,16 @@ void VPatternConverter::ToV0_7_6()
Save();
}
//---------------------------------------------------------------------------------------------------------------------
void VPatternConverter::ToV0_7_7()
{
// TODO. Delete if minimal supported version is 0.7.7
Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 7, 7),
"Time to refactor the code.");
SetVersion(QStringLiteral("0.7.7"));
Save();
}
//---------------------------------------------------------------------------------------------------------------------
void VPatternConverter::TagUnitToV0_2_0()
{

View File

@ -53,7 +53,7 @@ public:
static const QString PatternMaxVerStr;
static const QString CurrentSchema;
static Q_DECL_CONSTEXPR const int PatternMinVer = CONVERTER_VERSION_CHECK(0, 1, 0);
static Q_DECL_CONSTEXPR const int PatternMaxVer = CONVERTER_VERSION_CHECK(0, 7, 6);
static Q_DECL_CONSTEXPR const int PatternMaxVer = CONVERTER_VERSION_CHECK(0, 7, 7);
protected:
virtual int MinVer() const Q_DECL_OVERRIDE;
@ -119,6 +119,7 @@ private:
void ToV0_7_4();
void ToV0_7_5();
void ToV0_7_6();
void ToV0_7_7();
void TagUnitToV0_2_0();
void TagIncrementToV0_2_0();

View File

@ -311,6 +311,18 @@ void VPieceNode::SetShowSecondPassmark(bool value)
d->m_isShowSecondPassmark = value;
}
//---------------------------------------------------------------------------------------------------------------------
bool VPieceNode::IsCheckUniqueness() const
{
return d->m_checkUniqueness;
}
//---------------------------------------------------------------------------------------------------------------------
void VPieceNode::SetCheckUniqueness(bool value)
{
d->m_checkUniqueness = (d->m_typeTool == Tool::NodePoint ? value : true);
}
//---------------------------------------------------------------------------------------------------------------------
bool VPieceNode::IsExcluded() const
{

View File

@ -99,6 +99,9 @@ public:
bool IsShowSecondPassmark() const;
void SetShowSecondPassmark(bool value);
bool IsCheckUniqueness() const;
void SetCheckUniqueness(bool value);
private:
QSharedDataPointer<VPieceNodeData> d;
};

View File

@ -53,7 +53,8 @@ public:
m_angleType(PieceNodeAngle::ByLength),
m_passmarkLineType(PassmarkLineType::OneLine),
m_passmarkAngleType(PassmarkAngleType::Straightforward),
m_isShowSecondPassmark(true)
m_isShowSecondPassmark(true),
m_checkUniqueness(true)
{}
VPieceNodeData(quint32 id, Tool typeTool, bool reverse)
@ -68,7 +69,8 @@ public:
m_angleType(PieceNodeAngle::ByLength),
m_passmarkLineType(PassmarkLineType::OneLine),
m_passmarkAngleType(PassmarkAngleType::Straightforward),
m_isShowSecondPassmark(true)
m_isShowSecondPassmark(true),
m_checkUniqueness(true)
{
if (m_typeTool == Tool::NodePoint)
{
@ -89,7 +91,8 @@ public:
m_angleType(node.m_angleType),
m_passmarkLineType(node.m_passmarkLineType),
m_passmarkAngleType(node.m_passmarkAngleType),
m_isShowSecondPassmark(node.m_isShowSecondPassmark)
m_isShowSecondPassmark(node.m_isShowSecondPassmark),
m_checkUniqueness(node.m_checkUniqueness)
{}
~VPieceNodeData() Q_DECL_EQ_DEFAULT;
@ -126,6 +129,11 @@ public:
bool m_isShowSecondPassmark;
/** @brief m_checkUniqueness need in cases where different points have the same coordinates, become one point.
* By default the check enabled. Disable it only if in a path cannot be used just one point. For example if
* gradation change a piece shape and the seond point should be remaind.*/
bool m_checkUniqueness;
private:
VPieceNodeData &operator=(const VPieceNodeData &) Q_DECL_EQ_DELETE;
};

View File

@ -95,6 +95,40 @@ VPieceNode RowNode(QListWidget *listWidget, int i)
SCASSERT(rowItem != nullptr);
return qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
}
//---------------------------------------------------------------------------------------------------------------------
bool DoublePoint(const VPieceNode &firstNode, const VPieceNode &secondNode, const VContainer *data)
{
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;
}
// But ignore the same coordinate if a user wants
if (not firstNode.IsCheckUniqueness() || not secondNode.IsCheckUniqueness())
{
return false;
}
try
{
const QSharedPointer<VPointF> firstPoint = data->GeometricObject<VPointF>(firstNode.GetId());
const QSharedPointer<VPointF> secondPoint = data->GeometricObject<VPointF>(secondNode.GetId());
return firstPoint->toQPointF() == secondPoint->toQPointF();
}
catch(const VExceptionBadId &)
{
return true;
}
}
return false;
}
}
//---------------------------------------------------------------------------------------------------------------------
@ -508,20 +542,7 @@ bool DialogTool::FirstPointEqualLast(QListWidget *listWidget, const VContainer *
const VPieceNode topNode = RowNode(listWidget, FindNotExcludedNodeDown(listWidget, 0));
const VPieceNode bottomNode = RowNode(listWidget, FindNotExcludedNodeUp(listWidget, listWidget->count()-1));
QSharedPointer<VPointF> firstPoint;
if (topNode.GetTypeTool() == Tool::NodePoint)
{
firstPoint = data->GeometricObject<VPointF>(topNode.GetId());
}
QSharedPointer<VPointF> secondPoint;
if (bottomNode.GetTypeTool() == Tool::NodePoint)
{
secondPoint = data->GeometricObject<VPointF>(bottomNode.GetId());
}
return topNode.GetId() == bottomNode.GetId() || (not firstPoint.isNull() && not secondPoint.isNull()
&& firstPoint->toQPointF() == secondPoint->toQPointF());
return DoublePoint(topNode, bottomNode, data);
}
return false;
}
@ -536,20 +557,7 @@ bool DialogTool::DoublePoints(QListWidget *listWidget, const VContainer *data)
const VPieceNode firstNode = RowNode(listWidget, firstIndex);
const VPieceNode secondNode = RowNode(listWidget, FindNotExcludedNodeDown(listWidget, firstIndex+1));
QSharedPointer<VPointF> firstPoint;
if (firstNode.GetTypeTool() == Tool::NodePoint && not (firstNode.GetId() == NULL_ID))
{
firstPoint = data->GeometricObject<VPointF>(firstNode.GetId());
}
QSharedPointer<VPointF> secondPoint;
if (secondNode.GetTypeTool() == Tool::NodePoint && not (secondNode.GetId() == NULL_ID))
{
secondPoint = data->GeometricObject<VPointF>(secondNode.GetId());
}
if (firstNode.GetId() == secondNode.GetId() || (not firstPoint.isNull() && not secondPoint.isNull()
&& firstPoint->toQPointF() == secondPoint->toQPointF()))
if (DoublePoint(firstNode, secondNode, data))
{
return true;
}
@ -616,27 +624,35 @@ QString DialogTool::GetNodeName(const VPieceNode &node, bool showPassmark) const
name = QLatin1String("- ") + name;
}
}
else if (showPassmark && node.IsPassmark())
else
{
switch(node.GetPassmarkLineType())
if (showPassmark && node.IsPassmark())
{
case PassmarkLineType::OneLine:
name += QLatin1Char('|');
break;
case PassmarkLineType::TwoLines:
name += QLatin1Literal("||");
break;
case PassmarkLineType::ThreeLines:
name += QLatin1Literal("|||");
break;
case PassmarkLineType::TMark:
name += QString("");
break;
case PassmarkLineType::VMark:
name += QLatin1Char('^');
break;
default:
break;
switch(node.GetPassmarkLineType())
{
case PassmarkLineType::OneLine:
name += QLatin1Char('|');
break;
case PassmarkLineType::TwoLines:
name += QLatin1Literal("||");
break;
case PassmarkLineType::ThreeLines:
name += QLatin1Literal("|||");
break;
case PassmarkLineType::TMark:
name += QString("");
break;
case PassmarkLineType::VMark:
name += QLatin1Char('^');
break;
default:
break;
}
}
if (not node.IsCheckUniqueness())
{
name = QLatin1Char('[') + name + QLatin1Char(']');
}
}

View File

@ -284,6 +284,7 @@ void DialogPiecePath::ShowContextMenu(const QPoint &pos)
VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
QAction *actionPassmark = nullptr;
QAction *actionUniqueness = nullptr;
QAction *actionReverse = nullptr;
if (rowNode.GetTypeTool() != Tool::NodePoint)
{
@ -296,6 +297,10 @@ void DialogPiecePath::ShowContextMenu(const QPoint &pos)
actionPassmark = menu->addAction(tr("Passmark"));
actionPassmark->setCheckable(true);
actionPassmark->setChecked(rowNode.IsPassmark());
actionUniqueness = menu->addAction(tr("Check uniqueness"));
actionUniqueness->setCheckable(true);
actionUniqueness->setChecked(rowNode.IsCheckUniqueness());
}
QAction *actionDelete = menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete"));
@ -317,6 +322,12 @@ void DialogPiecePath::ShowContextMenu(const QPoint &pos)
rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
rowItem->setText(GetNodeName(rowNode, true));
}
else if (selectedAction == actionUniqueness)
{
rowNode.SetCheckUniqueness(not rowNode.IsCheckUniqueness());
rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
rowItem->setText(GetNodeName(rowNode, true));
}
ValidObjects(PathIsValid());
ListChanged();

View File

@ -613,6 +613,7 @@ void DialogSeamAllowance::ShowMainPathContextMenu(const QPoint &pos)
VPieceNode rowNode = qvariant_cast<VPieceNode>(rowItem->data(Qt::UserRole));
QAction *actionPassmark = nullptr;
QAction *actionUniqueness = nullptr;
QAction *actionReverse = nullptr;
if (rowNode.GetTypeTool() != Tool::NodePoint)
{
@ -625,6 +626,10 @@ void DialogSeamAllowance::ShowMainPathContextMenu(const QPoint &pos)
actionPassmark = menu->addAction(tr("Passmark"));
actionPassmark->setCheckable(true);
actionPassmark->setChecked(rowNode.IsPassmark());
actionUniqueness = menu->addAction(tr("Check uniqueness"));
actionUniqueness->setCheckable(true);
actionUniqueness->setChecked(rowNode.IsCheckUniqueness());
}
QAction *actionExcluded = menu->addAction(tr("Excluded"));
@ -657,6 +662,12 @@ void DialogSeamAllowance::ShowMainPathContextMenu(const QPoint &pos)
rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
rowItem->setText(GetNodeName(rowNode, true));
}
else if (selectedAction == actionUniqueness)
{
rowNode.SetCheckUniqueness(not rowNode.IsCheckUniqueness());
rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode));
rowItem->setText(GetNodeName(rowNode, true));
}
ValidObjects(MainPathIsValid());
ListChanged();

View File

@ -535,6 +535,18 @@ QDomElement VAbstractTool::AddSANode(VAbstractPattern *doc, const QString &tagNa
}
}
{
const bool uniqueness = node.IsCheckUniqueness();
if (not uniqueness)
{
doc->SetAttribute(nod, VAbstractPattern::AttrCheckUniqueness, uniqueness);
}
else
{ // For backward compatebility.
nod.removeAttribute(VAbstractPattern::AttrCheckUniqueness);
}
}
switch (type)
{
case (Tool::NodeArc):

View File

@ -179,7 +179,8 @@ bool SavePieceOptions::mergeWith(const QUndoCommand *command)
for (int i = 0; i < nodes.size(); ++i)
{
if (nodes.at(i).IsExcluded() != candidateNodes.at(i).IsExcluded())
if (nodes.at(i).IsExcluded() != candidateNodes.at(i).IsExcluded()
|| nodes.at(i).IsCheckUniqueness() != candidateNodes.at(i).IsCheckUniqueness())
{
return false;
}

View File

@ -150,7 +150,8 @@ bool SavePiecePathOptions::mergeWith(const QUndoCommand *command)
for (int i = 0; i < nodes.size(); ++i)
{
if (nodes.at(i).IsExcluded() != candidateNodes.at(i).IsExcluded())
if (nodes.at(i).IsExcluded() != candidateNodes.at(i).IsExcluded()
|| nodes.at(i).IsCheckUniqueness() != candidateNodes.at(i).IsCheckUniqueness())
{
return false;
}