From bca10e71fb40d0370c88c251c0017a5c25af6566 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Wed, 14 Sep 2016 16:12:08 +0300 Subject: [PATCH] Fixed issue #548. Bug Detail tool. Case when seam allowance is wrong. --HG-- branch : develop --- src/libs/vlayout/vabstractdetail.cpp | 142 ++++++++++++---- src/libs/vlayout/vabstractdetail.h | 5 +- .../ValentinaTest/tst_vabstractdetail.cpp | 159 ++++++++++++++---- src/test/ValentinaTest/tst_vabstractdetail.h | 17 +- 4 files changed, 257 insertions(+), 66 deletions(-) diff --git a/src/libs/vlayout/vabstractdetail.cpp b/src/libs/vlayout/vabstractdetail.cpp index 967581e0f..77e25bc21 100644 --- a/src/libs/vlayout/vabstractdetail.cpp +++ b/src/libs/vlayout/vabstractdetail.cpp @@ -226,7 +226,10 @@ QVector VAbstractDetail::Equidistant(const QVector &points, co } if (i == p.size()-1 && eqv == EquidistantType::CloseEquidistant) {//last point, polyline closed - ekvPoints.append(ekvPoints.at(0)); + if (not ekvPoints.isEmpty()) + { + ekvPoints.append(ekvPoints.at(0)); + } continue; } else if (i == p.size()-1 && eqv == EquidistantType::OpenEquidistant) @@ -238,25 +241,35 @@ QVector VAbstractDetail::Equidistant(const QVector &points, co //points in the middle of polyline ekvPoints< VAbstractDetail::RemoveDublicates(const QVector &points) +QVector VAbstractDetail::RemoveDublicates(const QVector &points, bool removeFirstAndLast) { QVector p = points; - if (not p.isEmpty() && p.size() > 1) + if (removeFirstAndLast) { - // Path can't be closed - if (p.first() == p.last()) + if (not p.isEmpty() && p.size() > 1) { - #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0) - p.remove(p.size() - 1); - #else - p.removeLast(); - #endif + // 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 + } } } @@ -264,6 +277,11 @@ QVector VAbstractDetail::RemoveDublicates(const QVector &point { if (p.at(i) == p.at(i+1)) { + if (not removeFirstAndLast && (i == p.size()-1)) + { + continue; + } + p.erase(p.begin() + i + 1); --i; continue; @@ -279,7 +297,7 @@ QVector VAbstractDetail::RemoveDublicates(const QVector &point * @param points list of points equdistant. * @return corrected list. */ -QVector VAbstractDetail::CorrectEquidistantPoints(const QVector &points) +QVector VAbstractDetail::CorrectEquidistantPoints(const QVector &points, bool removeFirstAndLast) { if (points.size()<4)//Better don't check if only three points. We can destroy equidistant. { @@ -288,12 +306,13 @@ QVector VAbstractDetail::CorrectEquidistantPoints(const QVector correctPoints = RemoveDublicates(points); + QVector correctPoints = RemoveDublicates(points, removeFirstAndLast); if (correctPoints.size()<3) { return correctPoints; } + //Remove point on line for (qint32 i = 1; i VAbstractDetail::CorrectEquidistantPoints(const QVector VAbstractDetail::CheckLoops(const QVector &points) return points; } + const bool pathClosed = (points.first() == points.last()); + QVector ekvPoints; - qint32 i, j; + qint32 i, j, jNext; for (i = 0; i < count; ++i) { /*Last three points no need check.*/ @@ -344,8 +366,20 @@ QVector VAbstractDetail::CheckLoops(const QVector &points) // That's why we parse from the end for (j = count-1; j >= i+2; --j) { - QLineF line2; - j == count-1 ? line2 = QLineF(points.at(j), points.at(0)) : line2 = QLineF(points.at(j), points.at(j+1)); + + 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) @@ -353,11 +387,12 @@ QVector VAbstractDetail::CheckLoops(const QVector &points) // 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)) - // Next cases are valid for us. - && line1.p2() != line2.p2() - && line1.p1() != line2.p1() - && line1.p2() != line2.p1() - && line1.p1() != line2.p2()) + // 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; @@ -380,11 +415,14 @@ QVector VAbstractDetail::CheckLoops(const QVector &points) } } } - else if (intersect == QLineF::BoundedIntersection && not (i == 0 && j == count-1)) - { // Break, but not if intersects the first edge and the last edge in closed path - if (line1.p1() != crosPoint && line1.p2() != crosPoint && - line2.p1() != crosPoint && line2.p2() != crosPoint) - { // Break, but not if loop creates crosPoint when it is first or last point of lines + 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; } @@ -396,10 +434,10 @@ QVector VAbstractDetail::CheckLoops(const QVector &points) { case ParallelIntersection: /*We have found a loop.*/ - // Theoretically there is no big difference which point j or j+1 to select. + // 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(j+1)); + ekvPoints.append(points.at(jNext)); i = j; break; case BoundedIntersection: @@ -440,8 +478,8 @@ QVector VAbstractDetail::EkvPoint(const QLineF &line1, const QLineF &li return QVector(); } QPointF CrosPoint; - QLineF bigLine1 = ParallelLine(line1, width ); - QLineF bigLine2 = ParallelLine(QLineF(line2.p2(), line2.p1()), width ); + const QLineF bigLine1 = ParallelLine(line1, width ); + const QLineF bigLine2 = ParallelLine(QLineF(line2.p2(), line2.p1()), width ); QLineF::IntersectType type = bigLine1.intersect( bigLine2, &CrosPoint ); switch (type) { @@ -451,7 +489,13 @@ QVector VAbstractDetail::EkvPoint(const QLineF &line1, const QLineF &li break; case (QLineF::UnboundedIntersection): { - QLineF line( line1.p2(), CrosPoint ); + QLineF line( line1.p2(), CrosPoint ); + + const int angle1 = BisectorAngle(line1.p1(), line1.p2(), line2.p1()); + const int angle2 = BisectorAngle(bigLine1.p1(), CrosPoint, bigLine2.p2()); + + if (angle1 == angle2) + {//Regular equdistant case const qreal length = line.length(); if (length > width*2.4) { // Cutting too long a cut angle @@ -482,6 +526,18 @@ QVector VAbstractDetail::EkvPoint(const QLineF &line1, const QLineF &li points.append(CrosPoint); return points; } + } + else + {// Dart. Ignore if going outside of equdistant + const QLineF bigEdge = ParallelLine(QLineF(line1.p1(), line2.p1()), width ); + QPointF px; + const QLineF::IntersectType type = bigEdge.intersect(line, &px); + if (type != QLineF::BoundedIntersection) + { + points.append(CrosPoint); + return points; + } + } break; } case (QLineF::NoIntersection): @@ -587,6 +643,30 @@ QPointF VAbstractDetail::SingleParallelPoint(const QLineF &line, const qreal &an return pLine.p2(); } +//--------------------------------------------------------------------------------------------------------------------- +int VAbstractDetail::BisectorAngle(const QPointF &p1, const QPointF &p2, const QPointF &p3) +{ + QLineF line1(p2, p1); + QLineF line2(p2, p3); + QLineF bLine; + + const qreal angle1 = line1.angleTo(line2); + const qreal angle2 = line2.angleTo(line1); + + if (angle1 <= angle2) + { + bLine = line1; + bLine.setAngle(bLine.angle() + angle1/2.0); + } + else + { + bLine = line2; + bLine.setAngle(bLine.angle() + angle2/2.0); + } + + return qRound(bLine.angle()); +} + //--------------------------------------------------------------------------------------------------------------------- qreal VAbstractDetail::SumTrapezoids(const QVector &points) { diff --git a/src/libs/vlayout/vabstractdetail.h b/src/libs/vlayout/vabstractdetail.h index b73ba99bd..78c3195c4 100644 --- a/src/libs/vlayout/vabstractdetail.h +++ b/src/libs/vlayout/vabstractdetail.h @@ -73,10 +73,10 @@ public: static QVector Equidistant(const QVector &points, const EquidistantType &eqv, qreal width); static qreal SumTrapezoids(const QVector &points); static QVector CheckLoops(const QVector &points); - static QVector CorrectEquidistantPoints(const QVector &points); + static QVector CorrectEquidistantPoints(const QVector &points, bool removeFirstAndLast = true); protected: - static QVector RemoveDublicates(const QVector &points); + static QVector RemoveDublicates(const QVector &points, bool removeFirstAndLast = true); private: QSharedDataPointer d; @@ -85,6 +85,7 @@ private: static QPointF UnclosedEkvPoint(const QLineF &line, const QLineF &helpLine, const qreal &width); static QLineF ParallelLine(const QLineF &line, qreal width ); static QPointF SingleParallelPoint(const QLineF &line, const qreal &angle, const qreal &width); + static int BisectorAngle(const QPointF &p1, const QPointF &p2, const QPointF &p3); }; Q_DECLARE_TYPEINFO(VAbstractDetail, Q_MOVABLE_TYPE); diff --git a/src/test/ValentinaTest/tst_vabstractdetail.cpp b/src/test/ValentinaTest/tst_vabstractdetail.cpp index c99ed0ba2..42b6be525 100644 --- a/src/test/ValentinaTest/tst_vabstractdetail.cpp +++ b/src/test/ValentinaTest/tst_vabstractdetail.cpp @@ -48,25 +48,45 @@ void TST_VAbstractDetail::EquidistantRemoveLoop_data() QTest::addColumn("width"); QTest::addColumn>("ekvOrig"); - QTest::newRow("Case1") << InputPointsCase1() - << static_cast(EquidistantType::CloseEquidistant) - << 75.5906 // seam allowance width - << OutputPointsCase1(); + // These are two real cases where equdistant has loop. + // See issue #298. Segmented Curve isn't selected in Seam Allowance tool. + // https://bitbucket.org/dismine/valentina/issue/298/segmented-curve-isnt-selected-in-seam + // Code should clean loops in path. + QTest::newRow("Issue 298. Case1") << InputPointsIssue298Case1() + << static_cast(EquidistantType::CloseEquidistant) + << 75.5906 // seam allowance width + << OutputPointsIssue298Case1(); - QTest::newRow("Case2") << InputPointsCase2() - << static_cast(EquidistantType::CloseEquidistant) - << 37.7953 // seam allowance width - << OutputPointsCase2(); + QTest::newRow("Issue 298. Case2") << InputPointsIssue298Case2() + << static_cast(EquidistantType::CloseEquidistant) + << 37.7953 // seam allowance width + << OutputPointsIssue298Case2(); + + // See issue #548. Bug Detail tool. Case when seam allowance is wrong. + // https://bitbucket.org/dismine/valentina/issues/548/bug-detail-tool-case-when-seam-allowance + // Files: Steampunk_trousers.val and marie.vit + // Actually buggy detail see in file src/app/share/collection/bugs/Steampunk_trousers_issue_#548.val + // Code should clean loops in path. + QTest::newRow("Issue 548. Case1") << InputPointsIssue548Case1() + << static_cast(EquidistantType::CloseEquidistant) + << 11.338582677165354 // seam allowance width (0.3 cm) + << OutputPointsIssue548Case1(); + + QTest::newRow("Issue 548. Case2") << InputPointsIssue548Case2() + << static_cast(EquidistantType::CloseEquidistant) + << 37.795275590551185 // seam allowance width (1.0 cm) + << OutputPointsIssue548Case2(); + + QTest::newRow("Issue 548. Case3") << InputPointsIssue548Case3() + << static_cast(EquidistantType::CloseEquidistant) + << 75.59055118110237 // seam allowance width (2.0 cm) + << OutputPointsIssue548Case3(); } //--------------------------------------------------------------------------------------------------------------------- // cppcheck-suppress unusedFunction void TST_VAbstractDetail::EquidistantRemoveLoop() const { - // These are two real cases where equdistant has loop. - // See issue #298. Segmented Curve isn't selected in Seam Allowance tool. - // https://bitbucket.org/dismine/valentina/issue/298/segmented-curve-isnt-selected-in-seam - // Code should clean loops in path. QFETCH(QVector, points); QFETCH(int, eqv); QFETCH(qreal, width); @@ -567,7 +587,7 @@ void TST_VAbstractDetail::Case5() const } //--------------------------------------------------------------------------------------------------------------------- -QVector TST_VAbstractDetail::InputPointsCase1() const +QVector TST_VAbstractDetail::InputPointsIssue298Case1() const { QVector points; @@ -641,7 +661,7 @@ QVector TST_VAbstractDetail::InputPointsCase1() const } //--------------------------------------------------------------------------------------------------------------------- -QVector TST_VAbstractDetail::OutputPointsCase1() const +QVector TST_VAbstractDetail::OutputPointsIssue298Case1() const { QVector points; @@ -650,20 +670,15 @@ QVector TST_VAbstractDetail::OutputPointsCase1() const points += QPointF(493.3486932130227, 473.81998224542247); points += QPointF(384.7625023736152, 506.7228642416019); points += QPointF(326.77984549201204, 417.71265429523794); - points += QPointF(280.4343843787976, 340.220616520921); + points += QPointF(280.4634857863002, 340.20574652273); points += QPointF(269.00223298277206, 346.06212334710335); points += QPointF(239.6571136552229, 350.73379418002804); points += QPointF(205.89523544191223, 345.8623563310819); points += QPointF(173.89027296099863, 332.6512960877336); - points += QPointF(145.31523414712046, 315.34576260355936); points += QPointF(117.9921341644787, 294.6948297428524); - points += QPointF(91.25349438209683, 270.93768759082707); points += QPointF(65.22541125346564, 244.39379519957222); - points += QPointF(40.34791988062461, 215.4153238967542); points += QPointF(17.205314383747528, 184.31949780808853); - points += QPointF(-3.534416178847685, 151.30687894362717); points += QPointF(-21.090087790322336, 116.33389217738734); - points += QPointF(-33.795079640648055, 80.66898804409438); points += QPointF(-38.441724866417594, 60.24852451858777); points += QPointF(-52.3724798442221, -35.5907); @@ -671,7 +686,7 @@ QVector TST_VAbstractDetail::OutputPointsCase1() const } //--------------------------------------------------------------------------------------------------------------------- -QVector TST_VAbstractDetail::InputPointsCase2() const +QVector TST_VAbstractDetail::InputPointsIssue298Case2() const { QVector points; @@ -745,31 +760,25 @@ QVector TST_VAbstractDetail::InputPointsCase2() const } //--------------------------------------------------------------------------------------------------------------------- -QVector TST_VAbstractDetail::OutputPointsCase2() const +QVector TST_VAbstractDetail::OutputPointsIssue298Case2() const { QVector points; points += QPointF(-2.7952999999999975, 5.7719918429762656); points += QPointF(65.32544836315374, -0.992801551243895); points += QPointF(75.43676015393824, 49.41505784459415); - points += QPointF(83.37769389516122, 71.70650391130641); points += QPointF(95.36495808942361, 95.58656052818594); - points += QPointF(110.83634280812595, 120.21325109595534); points += QPointF(128.9510900596877, 144.55333805162292); - points += QPointF(148.8122943732712, 167.68860240021857); points += QPointF(169.48075280895182, 188.76665620458672); - points += QPointF(189.9439329177606, 206.94808512857375); points += QPointF(209.03488292644147, 221.3771186982216); - points += QPointF(215.73126220022726, 225.4325608097815); + points += QPointF(215.50341461262016, 224.79215417684094); points += QPointF(215.09342206269645, 222.63086681417994); - points += QPointF(205.6867557893074, 194.5606373284329); points += QPointF(193.90240551299544, 154.91725528228594); points += QPointF(189.00923093023508, 130.4332749760628); points += QPointF(191.70730467606634, 97.53824783614445); points += QPointF(229.19819583315143, 77.54897644999551); points += QPointF(256.3345313737502, 91.70119126633715); points += QPointF(270.9082046450185, 107.89162042078927); - points += QPointF(294.3626891097502, 142.42241251279827); points += QPointF(355.51936324849004, 244.86019492195868); points += QPointF(422.97357725399365, 357.6471728523805); points += QPointF(486.8597146913536, 455.7199210117685); @@ -779,6 +788,98 @@ QVector TST_VAbstractDetail::OutputPointsCase2() const return points; } +//--------------------------------------------------------------------------------------------------------------------- +QVector TST_VAbstractDetail::InputPointsIssue548Case1() const +{ + QVector points; + + points += QPointF(236.97989607468364, 65.89325192030674); + points += QPointF(198.93409106041895, 172.04876297154925); + points += QPointF(260.32251114299453, 75.38027418944861); + points += QPointF(324.54110236213444, 101.48031496062993); + points += QPointF(29.858267716535437, 300.85039370078744); + points += QPointF(99.86433649395013, 10.166060970128015); + + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector TST_VAbstractDetail::OutputPointsIssue548Case1() const +{ + QVector points; + + points += QPointF(251.32210577118798, 59.48301432799721); + points += QPointF(243.9841262159756, 79.95746530820585); + points += QPointF(255.82424817748586, 61.31279754390509); + points += QPointF(348.48337789725855, 98.9717841021069); + points += QPointF(29.780382054543473, 314.59289909613994); + points += QPointF(17.01672179602679, 305.7450049304056); + points += QPointF(91.92616539550944, -5.299480329501037); + points += QPointF(251.32210577118798, 59.48301432799721); + + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector TST_VAbstractDetail::InputPointsIssue548Case2() const +{ + QVector points; + + points += QPointF(236.97989607468364, 65.89325192030674); + points += QPointF(198.93409106041895, 172.04876297154925); + points += QPointF(260.32251114299453, 75.38027418944861); + points += QPointF(324.54110236213444, 101.48031496062993); + points += QPointF(29.858267716535437, 300.85039370078744); + points += QPointF(99.86433649395013, 10.166060970128015); + + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector TST_VAbstractDetail::OutputPointsIssue548Case2() const +{ + QVector points; + + points += QPointF(284.78726172969823, 44.52579327927505); + points += QPointF(404.3486874792147, 93.11854543221973); + points += QPointF(29.598648843228922, 346.6587450186291); + points += QPointF(-12.946885351826726, 317.1657644661815); + points += QPointF(73.40376616581447, -41.38574336196901); + points += QPointF(284.78726172969823, 44.52579327927505); + + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector TST_VAbstractDetail::InputPointsIssue548Case3() const +{ + QVector points; + + points += QPointF(236.97989607468364, 65.89325192030674); + points += QPointF(198.93409106041895, 172.04876297154925); + points += QPointF(260.32251114299453, 75.38027418944861); + points += QPointF(324.54110236213444, 101.48031496062993); + points += QPointF(29.858267716535437, 300.85039370078744); + points += QPointF(99.86433649395013, 10.166060970128015); + + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector TST_VAbstractDetail::OutputPointsIssue548Case3() const +{ + QVector points; + + points += QPointF(332.5946273847129, 23.158334638243502); + points += QPointF(484.15627259629446, 84.75677590380938); + points += QPointF(29.339029969922702, 392.46709633647066); + points += QPointF(-55.75203842018885, 333.48113523157537); + points += QPointF(46.94319583767885, -92.9375476940661); + points += QPointF(332.5946273847129, 23.158334638243502); + + return points; +} + //--------------------------------------------------------------------------------------------------------------------- QVector TST_VAbstractDetail::InputPointsCase3() const { diff --git a/src/test/ValentinaTest/tst_vabstractdetail.h b/src/test/ValentinaTest/tst_vabstractdetail.h index 687443f42..cd7c59c43 100644 --- a/src/test/ValentinaTest/tst_vabstractdetail.h +++ b/src/test/ValentinaTest/tst_vabstractdetail.h @@ -54,11 +54,20 @@ private: void Case4() const; void Case5() const; - QVector InputPointsCase1() const; - QVector OutputPointsCase1() const; + QVector InputPointsIssue298Case1() const; + QVector OutputPointsIssue298Case1() const; - QVector InputPointsCase2() const; - QVector OutputPointsCase2() const; + QVector InputPointsIssue298Case2() const; + QVector OutputPointsIssue298Case2() const; + + QVector InputPointsIssue548Case1() const; + QVector OutputPointsIssue548Case1() const; + + QVector InputPointsIssue548Case2() const; + QVector OutputPointsIssue548Case2() const; + + QVector InputPointsIssue548Case3() const; + QVector OutputPointsIssue548Case3() const; QVector InputPointsCase3() const; QVector InputPointsCase4() const;