diff --git a/src/app/valentina/xml/vpattern.cpp b/src/app/valentina/xml/vpattern.cpp index 338021003..b785a9aa7 100644 --- a/src/app/valentina/xml/vpattern.cpp +++ b/src/app/valentina/xml/vpattern.cpp @@ -520,6 +520,43 @@ void VPattern::customEvent(QEvent *event) } } +//--------------------------------------------------------------------------------------------------------------------- +VNodeDetail VPattern::ParseDetailNode(const QDomElement &domElement) const +{ + const quint32 id = GetParametrUInt(domElement, AttrIdObject, NULL_ID_STR); + const qreal mx = GetParametrDouble(domElement, AttrMx, "0.0"); + const qreal my = GetParametrDouble(domElement, AttrMy, "0.0"); + const bool reverse = GetParametrUInt(domElement, VAbstractPattern::AttrNodeReverse, "0"); + const NodeDetail nodeType = NodeDetail::Contour; + + const QString t = GetParametrString(domElement, AttrType, "NodePoint"); + Tool tool; + + QStringList types = QStringList() << VAbstractPattern::NodePoint + << VAbstractPattern::NodeArc + << VAbstractPattern::NodeSpline + << VAbstractPattern::NodeSplinePath; + switch (types.indexOf(t)) + { + case 0: // NodePoint + tool = Tool::NodePoint; + break; + case 1: // NodeArc + tool = Tool::NodeArc; + break; + case 2: // NodeSpline + tool = Tool::NodeSpline; + break; + case 3: // NodeSplinePath + tool = Tool::NodeSplinePath; + break; + default: + VException e(tr("Wrong tag name '%1'.").arg(t)); + throw e; + } + return VNodeDetail(id, tool, nodeType, mx, my, reverse); +} + //--------------------------------------------------------------------------------------------------------------------- VPieceNode VPattern::ParseSANode(const QDomElement &domElement) const { @@ -704,6 +741,8 @@ void VPattern::ParseDetailElement(const QDomElement &domElement, const Document detail.SetInLayout(GetParametrBool(domElement, AttrInLayout, trueStr)); detail.SetUnited(GetParametrBool(domElement, VToolSeamAllowance::AttrUnited, falseStr)); + const uint version = GetParametrUInt(domElement, VToolSeamAllowance::AttrVersion, "1"); + const QStringList tags = QStringList() << TagNodes << TagData << TagPatternInfo @@ -719,7 +758,18 @@ void VPattern::ParseDetailElement(const QDomElement &domElement, const Document switch (tags.indexOf(element.tagName())) { case 0:// TagNodes - ParseDetailNodes(element, detail); + if (version == 1) + { + // TODO. Delete if minimal supported version is 0.4.0 + Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 4, 0), + "Time to refactor the code."); + const bool closed = GetParametrUInt(domElement, AttrClosed, "1"); + ParseDetailNodes(element, detail, closed); + } + else + { + ParsePieceNodes(element, detail); + } break; case 1:// TagData break; @@ -818,7 +868,24 @@ void VPattern::ParseDetailElement(const QDomElement &domElement, const Document } //--------------------------------------------------------------------------------------------------------------------- -void VPattern::ParseDetailNodes(const QDomElement &domElement, VPiece &detail) const +void VPattern::ParseDetailNodes(const QDomElement &domElement, VPiece &detail, bool closed) const +{ + QVector oldNodes; + const QDomNodeList nodeList = domElement.childNodes(); + for (qint32 i = 0; i < nodeList.size(); ++i) + { + const QDomElement element = nodeList.at(i).toElement(); + if (not element.isNull() && element.tagName() == VAbstractPattern::TagNode) + { + oldNodes.append(ParseDetailNode(element)); + } + } + + detail.GetPath().SetNodes(VNodeDetail::Convert(data, oldNodes, detail.GetSAWidth(), closed)); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPattern::ParsePieceNodes(const QDomElement &domElement, VPiece &detail) const { const QDomNodeList nodeList = domElement.childNodes(); for (qint32 i = 0; i < nodeList.size(); ++i) diff --git a/src/app/valentina/xml/vpattern.h b/src/app/valentina/xml/vpattern.h index 9911da676..73caf79d5 100644 --- a/src/app/valentina/xml/vpattern.h +++ b/src/app/valentina/xml/vpattern.h @@ -114,12 +114,14 @@ private: VMainGraphicsScene *sceneDraw; VMainGraphicsScene *sceneDetail; + VNodeDetail ParseDetailNode(const QDomElement &domElement) const; VPieceNode ParseSANode(const QDomElement &domElement) const; void ParseDrawElement(const QDomNode& node, const Document &parse); void ParseDrawMode(const QDomNode& node, const Document &parse, const Draw &mode); void ParseDetailElement(const QDomElement &domElement, const Document &parse); - void ParseDetailNodes(const QDomElement &domElement, VPiece &detail) const; + void ParseDetailNodes(const QDomElement &domElement, VPiece &detail, bool closed) const; + void ParsePieceNodes(const QDomElement &domElement, VPiece &detail) const; void ParseDetailCSARecords(const QDomElement &domElement, VPiece &detail) const; void ParseDetails(const QDomElement &domElement, const Document &parse); diff --git a/src/libs/ifc/ifcdef.cpp b/src/libs/ifc/ifcdef.cpp index 450dede6e..bfb584913 100644 --- a/src/libs/ifc/ifcdef.cpp +++ b/src/libs/ifc/ifcdef.cpp @@ -136,6 +136,7 @@ const QString AttrArc = QStringLiteral("arc"); const QString AttrSuffix = QStringLiteral("suffix"); const QString AttrIdObject = QStringLiteral("idObject"); const QString AttrInLayout = QStringLiteral("inLayout"); +const QString AttrClosed = QStringLiteral("closed"); const QString TypeLineNone = QStringLiteral("none"); const QString TypeLineLine = QStringLiteral("hair"); diff --git a/src/libs/ifc/ifcdef.h b/src/libs/ifc/ifcdef.h index d3594f201..0b87156f2 100644 --- a/src/libs/ifc/ifcdef.h +++ b/src/libs/ifc/ifcdef.h @@ -137,6 +137,7 @@ extern const QString AttrArc; extern const QString AttrSuffix; extern const QString AttrIdObject; extern const QString AttrInLayout; +extern const QString AttrClosed; extern const QString TypeLineNone; extern const QString TypeLineLine; diff --git a/src/libs/ifc/schema/pattern/v0.4.0.xsd b/src/libs/ifc/schema/pattern/v0.4.0.xsd index e33dd7e8b..4a76b947a 100644 --- a/src/libs/ifc/schema/pattern/v0.4.0.xsd +++ b/src/libs/ifc/schema/pattern/v0.4.0.xsd @@ -429,6 +429,8 @@ + + @@ -460,6 +462,7 @@ + diff --git a/src/libs/ifc/xml/vpatternconverter.cpp b/src/libs/ifc/xml/vpatternconverter.cpp index 0e02b69e0..145c0fddb 100644 --- a/src/libs/ifc/xml/vpatternconverter.cpp +++ b/src/libs/ifc/xml/vpatternconverter.cpp @@ -1730,8 +1730,6 @@ void VPatternConverter::TagDetailToV0_4_0() dom.setAttribute(strSeamAllowance, dom.attribute(strSupplement, "0")); dom.removeAttribute(strSupplement); - dom.removeAttribute(strClosed); - dom.setAttribute(strVersion, "1"); const QStringList tags = QStringList() << strNode << strData << strPatternInfo << strGrainline; @@ -1760,6 +1758,16 @@ void VPatternConverter::TagDetailToV0_4_0() tagNode.setAttribute(strReverse, element.attribute(strReverse, "0")); } + if (element.hasAttribute(strMx)) + { + tagNode.setAttribute(strMx, element.attribute(strMx, "0")); + } + + if (element.hasAttribute(strMy)) + { + tagNode.setAttribute(strMy, element.attribute(strMy, "0")); + } + tagNode.setAttribute(strType, element.attribute(strType, "")); tagNodes.appendChild(tagNode); diff --git a/src/libs/vpatterndb/vnodedetail.cpp b/src/libs/vpatterndb/vnodedetail.cpp index decba2343..a26b86887 100644 --- a/src/libs/vpatterndb/vnodedetail.cpp +++ b/src/libs/vpatterndb/vnodedetail.cpp @@ -28,6 +28,13 @@ #include "vnodedetail.h" #include "vnodedetail_p.h" +#include "vpiecenode.h" +#include "vpiecepath.h" +#include "../vgeometry/vpointf.h" +#include "../vpatterndb/vcontainer.h" + +#include +#include //--------------------------------------------------------------------------------------------------------------------- VNodeDetail::VNodeDetail() @@ -146,3 +153,154 @@ void VNodeDetail::setReverse(bool reverse) d->reverse = reverse; } } + +//--------------------------------------------------------------------------------------------------------------------- +QVector VNodeDetail::Convert(const VContainer *data, const QVector &nodes, qreal width, + bool closed) +{ + if (width < 0) + { + width = 0; + } + + VPiecePath path; + for (int i = 0; i < nodes.size(); ++i) + { + const VNodeDetail &node = nodes.at(i); + path.Append(VPieceNode(node.getId(), node.getTypeTool(), node.getReverse())); + } + + auto LocalWidth = [width](qreal move) noexcept + { + qreal value = width + move; + if (value < 0) + { + value = 0; + } + return value; + }; + + if (path.PathPoints(data).size() > 2) + { + for (int i = 0; i < nodes.size(); ++i) + { + const VNodeDetail &node = nodes.at(i); + if (node.getTypeTool() == Tool::NodePoint) + { + if (not qFuzzyIsNull(node.getMx()) || not qFuzzyIsNull(node.getMy())) + { + const QPointF previosPoint = path.NodePreviousPoint(data, i); + const QPointF nextPoint = path.NodeNextPoint(data, i); + + const QPointF point = data->GeometricObject(node.getId())->toQPointF(); + + const QPointF xPoint(point.x()+node.getMx(), point.y()); + const QPointF yPoint(point.x(), point.y()+node.getMy()); + + if (IsSABefore(QLineF(point, previosPoint), QLineF(point, xPoint))) + { + path[i].SetSABefore(LocalWidth(node.getMx())); + + if (IsSAAfter(QLineF(point, nextPoint), QLineF(point, yPoint))) + { + path[i].SetSAAfter(LocalWidth(node.getMy())); + } + } + else if (IsSABefore(QLineF(point, previosPoint), QLineF(point, yPoint))) + { + path[i].SetSABefore(LocalWidth(node.getMy())); + + if (IsSAAfter(QLineF(point, nextPoint), QLineF(point, xPoint))) + { + path[i].SetSAAfter(LocalWidth(node.getMx())); + } + } + else if (IsSAAfter(QLineF(point, nextPoint), QLineF(point, xPoint))) + { + path[i].SetSAAfter(LocalWidth(node.getMx())); + } + else if (IsSAAfter(QLineF(point, nextPoint), QLineF(point, yPoint))) + { + path[i].SetSAAfter(LocalWidth(node.getMy())); + } + } + } + } + } + + if (not closed && path.CountNodes() > 1) + { + path[0].SetSABefore(0); + path[path.CountNodes()-1].SetSAAfter(0); + } + + return path.GetNodes(); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VNodeDetail::IsSABefore(const QLineF &saBaseLine, const QLineF &mLine) +{ + if (qFuzzyIsNull(mLine.length())) + { + return false; + } + + QLineF saLine = saBaseLine; + saLine.setAngle(saLine.angle() - 90); + + int saAngle = qRound(saLine.angle()); + if (saAngle >= 360) + { + saAngle = 0; + } + + int mTest1 = qRound(mLine.angle()); + if (mTest1 >= 360) + { + mTest1 = 0; + } + + QLineF mrLine = mLine; + mrLine.setAngle(mrLine.angle()+180); + int mTest2 = qRound(mrLine.angle()); + if (mTest2 >=360) + { + mTest2 = 0; + } + + return (saAngle == mTest1 || saAngle == mTest2); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VNodeDetail::IsSAAfter(const QLineF &saBaseLine, const QLineF &mLine) +{ + if (qFuzzyIsNull(mLine.length())) + { + return false; + } + + QLineF saLine = saBaseLine; + saLine.setAngle(saLine.angle() + 90); + + int saAngle = qRound(saLine.angle()); + if (saAngle >= 360) + { + saAngle = 0; + } + + int mTest1 = qRound(mLine.angle()); + if (mTest1 >= 360) + { + mTest1 = 0; + } + + QLineF mrLine = mLine; + mrLine.setAngle(mrLine.angle()+180); + int mTest2 = qRound(mrLine.angle()); + if (mTest2 >=360) + { + mTest2 = 0; + } + + return (saAngle == mTest1 || saAngle == mTest2); +} diff --git a/src/libs/vpatterndb/vnodedetail.h b/src/libs/vpatterndb/vnodedetail.h index d1c5ac152..ca6df9f04 100644 --- a/src/libs/vpatterndb/vnodedetail.h +++ b/src/libs/vpatterndb/vnodedetail.h @@ -37,6 +37,8 @@ #include "../vmisc/def.h" class VNodeDetailData; +class VPieceNode; +class VContainer; /** * @brief The VNodeDetail class keep information about detail node. @@ -122,8 +124,14 @@ public: bool getReverse() const; void setReverse(bool reverse); + + static QVector Convert(const VContainer *data, const QVector &nodes, qreal width, + bool closed); private: QSharedDataPointer d; + + static bool IsSABefore(const QLineF &saBaseLine, const QLineF &mLine); + static bool IsSAAfter(const QLineF &saBaseLine, const QLineF &mLine); }; Q_DECLARE_METATYPE(VNodeDetail) diff --git a/src/libs/vpatterndb/vpiecepath.cpp b/src/libs/vpatterndb/vpiecepath.cpp index 716058e95..cbaa5061a 100644 --- a/src/libs/vpatterndb/vpiecepath.cpp +++ b/src/libs/vpatterndb/vpiecepath.cpp @@ -293,36 +293,10 @@ VSAPoint VPiecePath::EndSegment(const VContainer *data, const QVector 2) { - if (i == nodes.size() - 1) - { - if (nodes.at(0).GetTypeTool() == Tool::NodePoint) - { - const VPieceNode &node = nodes.at(0); - const QPointF p = *data->GeometricObject(node.GetId()); - if (curve->IsPointOnCurve(p)) - { - end = VSAPoint(p); - end.SetSAAfter(node.GetSAAfter(*data->GetPatternUnit())); - end.SetSABefore(node.GetSABefore(*data->GetPatternUnit())); - end.SetAngleType(node.GetAngleType()); - } - } - } - else - { - if (nodes.at(i+1).GetTypeTool() == Tool::NodePoint) - { - const VPieceNode &node = nodes.at(i+1); - const QPointF p = *data->GeometricObject(node.GetId()); - if (curve->IsPointOnCurve(p)) - { - end = VSAPoint(p); - end.SetSAAfter(node.GetSAAfter(*data->GetPatternUnit())); - end.SetSABefore(node.GetSABefore(*data->GetPatternUnit())); - end.SetAngleType(node.GetAngleType()); - } - } - } + int index = 0; + i == nodes.size() - 1 ? index = 0 : index = i+1; + + end = CurvePoint(end, data, nodes.at(index), curve); } return end; } @@ -387,6 +361,107 @@ VSAPoint VPiecePath::EndSegment(const VContainer *data, int i, bool reverse) con return EndSegment(data, d->m_nodes, i, reverse); } +//--------------------------------------------------------------------------------------------------------------------- +QPointF VPiecePath::NodePreviousPoint(const VContainer *data, int i) const +{ + if (i < 0 || i > d->m_nodes.size()-1) + { + return QPointF(); + } + + if (d->m_nodes.size() > 1) + { + int index = 0; + if (i == 0) + { + index = d->m_nodes.size()-1; + } + else + { + index = i-1; + } + + const VPieceNode &node = d->m_nodes.at(index); + switch (node.GetTypeTool()) + { + case (Tool::NodePoint): + return *data->GeometricObject(node.GetId()); + case (Tool::NodeArc): + case (Tool::NodeSpline): + case (Tool::NodeSplinePath): + { + const QSharedPointer curve = data->GeometricObject(node.GetId()); + + const VSAPoint begin = StartSegment(data, d->m_nodes, i, node.GetReverse()); + const VSAPoint end = EndSegment(data, d->m_nodes, i, node.GetReverse()); + + const QVector points = curve->GetSegmentPoints(begin, end, node.GetReverse()); + if (points.size() > 1) + { + return points.at(points.size()-2); + } + } + break; + default: + qDebug()<<"Get wrong tool type. Ignore."<< static_cast(node.GetTypeTool()); + break; + } + } + + return QPointF(); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPointF VPiecePath::NodeNextPoint(const VContainer *data, int i) const +{ + QPointF point; + if (i < 0 || i > d->m_nodes.size()-1) + { + return point; + } + + if (d->m_nodes.size() > 1) + { + int index = 0; + if (i == d->m_nodes.size() - 1) + { + index = 0; + } + else + { + index = i+1; + } + + const VPieceNode &node = d->m_nodes.at(index); + switch (node.GetTypeTool()) + { + case (Tool::NodePoint): + return *data->GeometricObject(node.GetId()); + case (Tool::NodeArc): + case (Tool::NodeSpline): + case (Tool::NodeSplinePath): + { + const QSharedPointer curve = data->GeometricObject(node.GetId()); + + const VSAPoint begin = StartSegment(data, d->m_nodes, i, node.GetReverse()); + const VSAPoint end = EndSegment(data, d->m_nodes, i, node.GetReverse()); + + const QVector points = curve->GetSegmentPoints(begin, end, node.GetReverse()); + if (points.size() > 1) + { + return points.at(1); + } + } + break; + default: + qDebug()<<"Get wrong tool type. Ignore."<< static_cast(node.GetTypeTool()); + break; + } + } + + return point; +} + //--------------------------------------------------------------------------------------------------------------------- VSAPoint VPiecePath::PreparePointEkv(const VPieceNode &node, const VContainer *data) { diff --git a/src/libs/vpatterndb/vpiecepath.h b/src/libs/vpatterndb/vpiecepath.h index dfbe580a5..63829bd0b 100644 --- a/src/libs/vpatterndb/vpiecepath.h +++ b/src/libs/vpatterndb/vpiecepath.h @@ -81,6 +81,9 @@ public: VSAPoint StartSegment(const VContainer *data, int i, bool reverse) const; VSAPoint EndSegment(const VContainer *data, int i, bool reverse) const; + QPointF NodePreviousPoint(const VContainer *data, int i) const; + QPointF NodeNextPoint(const VContainer *data, int i) const; + static VSAPoint StartSegment(const VContainer *data, const QVector &nodes, int i, bool reverse); static VSAPoint EndSegment(const VContainer *data, const QVector &nodes, int i, bool reverse); diff --git a/src/libs/vtools/tools/vtoolseamallowance.cpp b/src/libs/vtools/tools/vtoolseamallowance.cpp index 2a027a0ae..66f580c41 100644 --- a/src/libs/vtools/tools/vtoolseamallowance.cpp +++ b/src/libs/vtools/tools/vtoolseamallowance.cpp @@ -379,7 +379,21 @@ void VToolSeamAllowance::RefreshDataInFile() // TODO. Delete if minimal supported version is 0.4.0 Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 4, 0), "Time to refactor the code."); - doc->SetAttribute(domElement, AttrVersion, QString().setNum(pieceVersion)); + + const uint version = doc->GetParametrUInt(domElement, VToolSeamAllowance::AttrVersion, "1"); + if (version == 1) + { + const VPiece piece = VAbstractTool::data.GetPiece(id); + + doc->SetAttribute(domElement, AttrVersion, QString().setNum(pieceVersion)); + + doc->RemoveAllChildren(domElement);//Very important to clear before rewrite + AddPatternPieceData(doc, domElement, piece); + AddPatternInfo(doc, domElement, piece); + AddGrainline(doc, domElement, piece); + AddNodes(doc, domElement, piece); + AddCSARecords(doc, domElement, piece.GetCustomSARecords()); + } } } }