From 22f9fb1e260f26c49e123d37e50e0795d1befc7e Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Thu, 3 Nov 2016 20:15:53 +0200 Subject: [PATCH] Added class VAbstractPiece. --HG-- branch : feature --- src/libs/vlayout/vabstractpiece.cpp | 301 ++++++++++++++++++++++++++++ src/libs/vlayout/vabstractpiece.h | 53 +++++ src/libs/vlayout/vlayout.pri | 10 +- src/libs/vpatterndb/vpiece.cpp | 121 ++++++++++- src/libs/vpatterndb/vpiece.h | 13 +- 5 files changed, 491 insertions(+), 7 deletions(-) create mode 100644 src/libs/vlayout/vabstractpiece.cpp create mode 100644 src/libs/vlayout/vabstractpiece.h diff --git a/src/libs/vlayout/vabstractpiece.cpp b/src/libs/vlayout/vabstractpiece.cpp new file mode 100644 index 000000000..0309df112 --- /dev/null +++ b/src/libs/vlayout/vabstractpiece.cpp @@ -0,0 +1,301 @@ +/************************************************************************ + ** + ** @file + ** @author Roman Telezhynskyi + ** @date 3 11, 2016 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2016 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 "vabstractpiece.h" + +#include +#include +#include +#include + +#include "../vgeometry/vgobject.h" + +//--------------------------------------------------------------------------------------------------------------------- +VAbstractPiece::VAbstractPiece() +{} + +//--------------------------------------------------------------------------------------------------------------------- +VAbstractPiece::VAbstractPiece(const VAbstractPiece &piece) +{ + Q_UNUSED(piece) +} + +//--------------------------------------------------------------------------------------------------------------------- +VAbstractPiece &VAbstractPiece::operator=(const VAbstractPiece &piece) +{ + if ( &piece == this ) + { + return *this; + } + return *this; +} + +//--------------------------------------------------------------------------------------------------------------------- +VAbstractPiece::~VAbstractPiece() +{} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VAbstractPiece::SumTrapezoids(const QVector &points) +{ + // Calculation a polygon area through the sum of the areas of trapezoids + qreal s, res = 0; + const int n = points.size(); + + if(n > 2) + { + for (int i = 0; i < n; ++i) + { + if (i == 0) + { + //if i == 0, then y[i-1] replace on y[n-1] + s = points.at(i).x()*(points.at(n-1).y() - points.at(i+1).y()); + res += s; + } + else + { + if (i == n-1) + { + // if i == n-1, then y[i+1] replace on y[0] + s = points.at(i).x()*(points.at(i-1).y() - points.at(0).y()); + res += s; + } + else + { + s = points.at(i).x()*(points.at(i-1).y() - points.at(i+1).y()); + res += s; + } + } + } + } + return res; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief CheckLoops seek and delete loops in equidistant. + * @param points vector of points of equidistant. + * @return vector of points of equidistant. + */ +QVector VAbstractPiece::CheckLoops(const QVector &points) +{ + const int count = points.size(); + /*If we got less than 4 points no need seek loops.*/ + if (count < 4) + { + qDebug()<<"Less then 4 points. Doesn't need check for loops."; + return points; + } + + const bool pathClosed = (points.first() == points.last()); + + QVector ekvPoints; + + qint32 i, j, jNext = 0; + for (i = 0; i < count; ++i) + { + /*Last three points no need check.*/ + /*Triangle has not contain loops*/ + if (i > count-3) + { + ekvPoints.append(points.at(i)); + continue; + } + + enum LoopIntersectType { NoIntersection, BoundedIntersection, ParallelIntersection }; + + QPointF crosPoint; + LoopIntersectType status = NoIntersection; + const QLineF line1(points.at(i), points.at(i+1)); + // Because a path can contains several loops we will seek the last and only then remove the loop(s) + // That's why we parse from the end + for (j = count-1; j >= i+2; --j) + { + + j == count-1 ? jNext = 0 : jNext = j+1; + QLineF line2(points.at(j), points.at(jNext)); + + if(qFuzzyIsNull(line2.length())) + {//If a path is closed the edge (count-1;0) length will be 0 + continue; + } + + QSet uniqueVertices; + uniqueVertices << i << i+1 << j; + + // For closed path last point is equal to first. Using index of the first. + pathClosed && jNext == count-1 ? uniqueVertices << 0 : uniqueVertices << jNext; + + const QLineF::IntersectType intersect = line1.intersect(line2, &crosPoint); + if (intersect == QLineF::NoIntersection) + { // According to the documentation QLineF::NoIntersection indicates that the lines do not intersect; + // i.e. they are parallel. But parallel also mean they can be on the same line. + // Method IsPointOnLineviaPDP will check it. + if (VGObject::IsPointOnLineviaPDP(points.at(j), points.at(i), points.at(i+1)) + // Lines are not neighbors + && uniqueVertices.size() == 4 + && line1.p2() != line2.p2() + && line1.p1() != line2.p1() + && line1.p2() != line2.p1() + && line1.p1() != line2.p2()) + { + // Left to catch case where segments are on the same line, but do not have real intersections. + QLineF tmpLine1 = line1; + QLineF tmpLine2 = line2; + + tmpLine1.setAngle(tmpLine1.angle()+90); + + QPointF tmpCrosPoint; + const QLineF::IntersectType tmpIntrs1 = tmpLine1.intersect(tmpLine2, &tmpCrosPoint); + + tmpLine1 = line1; + tmpLine2.setAngle(tmpLine2.angle()+90); + + const QLineF::IntersectType tmpIntrs2 = tmpLine1.intersect(tmpLine2, &tmpCrosPoint); + + if (tmpIntrs1 == QLineF::BoundedIntersection || tmpIntrs2 == QLineF::BoundedIntersection) + { // Now we really sure that lines are on the same lines and have real intersections. + status = ParallelIntersection; + break; + } + } + } + else if (intersect == QLineF::BoundedIntersection) + { + if (uniqueVertices.size() == 4 + && line1.p1() != crosPoint + && line1.p2() != crosPoint + && line2.p1() != crosPoint + && line2.p2() != crosPoint) + { // Break, but not if lines are neighbors + status = BoundedIntersection; + break; + } + } + status = NoIntersection; + } + + switch (status) + { + case ParallelIntersection: + /*We have found a loop.*/ + // Theoretically there is no big difference which point j or jNext to select. + // In the end we will draw a line in any case. + ekvPoints.append(points.at(i)); + ekvPoints.append(points.at(jNext)); + i = j; + break; + case BoundedIntersection: + /*We have found a loop.*/ + ekvPoints.append(points.at(i)); + ekvPoints.append(crosPoint); + i = j; + break; + case NoIntersection: + /*We have not found loop.*/ + ekvPoints.append(points.at(i)); + break; + default: + break; + } + } + return ekvPoints; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief CorrectEquidistantPoints clear equivalent points and remove point on line from equdistant. + * @param points list of points equdistant. + * @return corrected list. + */ +QVector VAbstractPiece::CorrectEquidistantPoints(const QVector &points, bool removeFirstAndLast) +{ + if (points.size()<4)//Better don't check if only three points. We can destroy equidistant. + { + qDebug()<<"Only three points."; + return points; + } + + //Clear equivalent points + QVector correctPoints = RemoveDublicates(points, removeFirstAndLast); + + if (correctPoints.size()<3) + { + return correctPoints; + } + + //Remove point on line + for (qint32 i = 1; i VAbstractPiece::RemoveDublicates(const QVector &points, bool removeFirstAndLast) +{ + QVector p = points; + + if (removeFirstAndLast) + { + if (not p.isEmpty() && p.size() > 1) + { + // Path can't be closed + if (p.first() == p.last()) + { + #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0) + p.remove(p.size() - 1); + #else + p.removeLast(); + #endif + } + } + } + + for (int i = 0; i < p.size()-1; ++i) + { + if (p.at(i) == p.at(i+1)) + { + if (not removeFirstAndLast && (i == p.size()-1)) + { + continue; + } + + p.erase(p.begin() + i + 1); + --i; + continue; + } + } + + return p; +} diff --git a/src/libs/vlayout/vabstractpiece.h b/src/libs/vlayout/vabstractpiece.h new file mode 100644 index 000000000..78caab9bd --- /dev/null +++ b/src/libs/vlayout/vabstractpiece.h @@ -0,0 +1,53 @@ +/************************************************************************ + ** + ** @file + ** @author Roman Telezhynskyi + ** @date 3 11, 2016 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2016 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 VABSTRACTPIECE_H +#define VABSTRACTPIECE_H + +#include + +template class QVector; +class QPointF; + +class VAbstractPiece +{ +public: + VAbstractPiece(); + VAbstractPiece(const VAbstractPiece &piece); + VAbstractPiece &operator=(const VAbstractPiece &piece); + virtual ~VAbstractPiece(); + + static qreal SumTrapezoids(const QVector &points); + static QVector CheckLoops(const QVector &points); + static QVector CorrectEquidistantPoints(const QVector &points, bool removeFirstAndLast = true); + +protected: + static QVector RemoveDublicates(const QVector &points, bool removeFirstAndLast = true); +}; + +#endif // VABSTRACTPIECE_H diff --git a/src/libs/vlayout/vlayout.pri b/src/libs/vlayout/vlayout.pri index 6d82d469f..434680020 100644 --- a/src/libs/vlayout/vlayout.pri +++ b/src/libs/vlayout/vlayout.pri @@ -17,8 +17,9 @@ HEADERS += \ $$PWD/vbestsquare.h \ $$PWD/vposition.h \ $$PWD/vtextmanager.h \ - vposter.h \ - vgraphicsfillitem.h + $$PWD/vposter.h \ + $$PWD/vgraphicsfillitem.h \ + $$PWD/vabstractpiece.h SOURCES += \ $$PWD/vlayoutgenerator.cpp \ @@ -30,7 +31,8 @@ SOURCES += \ $$PWD/vbestsquare.cpp \ $$PWD/vposition.cpp \ $$PWD/vtextmanager.cpp \ - vposter.cpp \ - vgraphicsfillitem.cpp + $$PWD/vposter.cpp \ + $$PWD/vgraphicsfillitem.cpp \ + $$PWD/vabstractpiece.cpp win32-msvc*:SOURCES += $$PWD/stable.cpp diff --git a/src/libs/vpatterndb/vpiece.cpp b/src/libs/vpatterndb/vpiece.cpp index 372231fc0..ef57752f0 100644 --- a/src/libs/vpatterndb/vpiece.cpp +++ b/src/libs/vpatterndb/vpiece.cpp @@ -28,15 +28,21 @@ #include "vpiece.h" #include "vpiece_p.h" +#include "../vgeometry/vpointf.h" +#include "../vgeometry/vabstractcurve.h" +#include "vcontainer.h" + +#include +#include //--------------------------------------------------------------------------------------------------------------------- VPiece::VPiece() - : d(new VPieceData) + : VAbstractPiece(), d(new VPieceData) {} //--------------------------------------------------------------------------------------------------------------------- VPiece::VPiece(const VPiece &piece) - : d (piece.d) + : VAbstractPiece(piece), d (piece.d) {} //--------------------------------------------------------------------------------------------------------------------- @@ -46,6 +52,7 @@ VPiece &VPiece::operator=(const VPiece &piece) { return *this; } + VAbstractPiece::operator=(piece); d = piece.d; return *this; } @@ -130,3 +137,113 @@ void VPiece::SetNodes(const QVector &nodes) { d->nodes = nodes; } + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPiece::MainPathPoints(const VContainer *data) const +{ + QVector points; + for (int i = 0; i < CountNode(); ++i) + { + switch (at(i).GetTypeTool()) + { + case (Tool::NodePoint): + { + const QSharedPointer point = data->GeometricObject(at(i).GetId()); + points.append(*point); + } + break; + case (Tool::NodeArc): + case (Tool::NodeSpline): + case (Tool::NodeSplinePath): + { + const QSharedPointer curve = data->GeometricObject(at(i).GetId()); + + const QPointF begin = StartSegment(data, i, at(i).GetReverse()); + const QPointF end = EndSegment(data, i, at(i).GetReverse()); + + points << curve->GetSegmentPoints(begin, end, at(i).GetReverse()); + } + break; + default: + qDebug()<<"Get wrong tool type. Ignore."<< static_cast(at(i).GetTypeTool()); + break; + } + } + + points = CheckLoops(CorrectEquidistantPoints(points));//A path can contains loops + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPointF VPiece::StartSegment(const VContainer *data, const int &i, bool reverse) const +{ + if (i < 0 && i > CountNode()-1) + { + return QPointF(); + } + + const QSharedPointer curve = data->GeometricObject(at(i).GetId()); + + QVector points = curve->GetPoints(); + if (reverse) + { + points = VGObject::GetReversePoints(points); + } + + QPointF begin = points.first(); + if (CountNode() > 1) + { + if (i == 0) + { + if (at(CountNode()-1).GetTypeTool() == Tool::NodePoint) + { + begin = *data->GeometricObject(at(CountNode()-1).GetId()); + } + } + else + { + if (at(i-1).GetTypeTool() == Tool::NodePoint) + { + begin = *data->GeometricObject(at(i-1).GetId()); + } + } + } + return begin; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPointF VPiece::EndSegment(const VContainer *data, const int &i, bool reverse) const +{ + if (i < 0 && i > CountNode()-1) + { + return QPointF(); + } + + const QSharedPointer curve = data->GeometricObject(at(i).GetId()); + + QVector points = curve->GetPoints(); + if (reverse) + { + points = VGObject::GetReversePoints(points); + } + + QPointF end = points.last(); + if (CountNode() > 2) + { + if (i == CountNode() - 1) + { + if (at(0).GetTypeTool() == Tool::NodePoint) + { + end = *data->GeometricObject(at(0).GetId()); + } + } + else + { + if (at(i+1).GetTypeTool() == Tool::NodePoint) + { + end = *data->GeometricObject(at(i+1).GetId()); + } + } + } + return end; +} diff --git a/src/libs/vpatterndb/vpiece.h b/src/libs/vpatterndb/vpiece.h index 90dc2ddc4..18c093f6a 100644 --- a/src/libs/vpatterndb/vpiece.h +++ b/src/libs/vpatterndb/vpiece.h @@ -32,10 +32,15 @@ #include #include +#include "../vlayout/vabstractpiece.h" + class VPieceData; class VPieceNode; +class QPointF; +class VContainer; +template class QVector; -class VPiece +class VPiece : public VAbstractPiece { public: VPiece(); @@ -53,8 +58,14 @@ public: QVector GetNodes() const; void SetNodes(const QVector &nodes); + + QVector MainPathPoints(const VContainer *data) const; + private: QSharedDataPointer d; + + QPointF StartSegment(const VContainer *data, const int &i, bool reverse) const; + QPointF EndSegment(const VContainer *data, const int &i, bool reverse) const; }; Q_DECLARE_TYPEINFO(VPiece, Q_MOVABLE_TYPE);