From 3b51ccb31dd29342396eafebf43031e260757857 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Wed, 8 May 2019 15:19:03 +0300 Subject: [PATCH] Refactoring. Move drawing passmarks to separate class. --HG-- branch : develop --- src/libs/vgeometry/vplacelabelitem.cpp | 71 +- src/libs/vgeometry/vplacelabelitem.h | 4 + src/libs/vlayout/vabstractpiece.cpp | 15 - src/libs/vlayout/vabstractpiece.h | 1 - src/libs/vlayout/vlayoutpiece.cpp | 2 +- src/libs/vpatterndb/vpassmark.cpp | 870 ++++++++++++++++++ src/libs/vpatterndb/vpassmark.h | 96 ++ src/libs/vpatterndb/vpatterndb.pri | 6 +- src/libs/vpatterndb/vpiece.cpp | 412 +-------- src/libs/vpatterndb/vpiece.h | 54 +- src/libs/vwidgets/vgraphicssimpletextitem.cpp | 15 +- src/libs/vwidgets/vgraphicssimpletextitem.h | 3 + src/test/ValentinaTest/tst_vpiece.cpp | 5 +- 13 files changed, 1094 insertions(+), 460 deletions(-) create mode 100644 src/libs/vpatterndb/vpassmark.cpp create mode 100644 src/libs/vpatterndb/vpassmark.h diff --git a/src/libs/vgeometry/vplacelabelitem.cpp b/src/libs/vgeometry/vplacelabelitem.cpp index da5a320fb..3ff9c25d1 100644 --- a/src/libs/vgeometry/vplacelabelitem.cpp +++ b/src/libs/vgeometry/vplacelabelitem.cpp @@ -357,30 +357,51 @@ PlaceLabelImg VPlaceLabelItem::LabelShape() const QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wswitch-default") - switch(d->type) - { - case PlaceLabelType::Segment: - return SegmentShape(); - case PlaceLabelType::Rectangle: - return RectangleShape(); - case PlaceLabelType::Cross: - return CrossShape(); - case PlaceLabelType::Tshaped: - return TshapedShape(); - case PlaceLabelType::Doubletree: - return DoubletreeShape(); - case PlaceLabelType::Corner: - return CornerShape(); - case PlaceLabelType::Triangle: - return TriangleShape(); - case PlaceLabelType::Hshaped: - return HshapedShape(); - case PlaceLabelType::Button: - return ButtonShape(); - case PlaceLabelType::Circle: - return CircleShape(); - } - QT_WARNING_POP + switch(d->type) + { + case PlaceLabelType::Segment: + return SegmentShape(); + case PlaceLabelType::Rectangle: + return RectangleShape(); + case PlaceLabelType::Cross: + return CrossShape(); + case PlaceLabelType::Tshaped: + return TshapedShape(); + case PlaceLabelType::Doubletree: + return DoubletreeShape(); + case PlaceLabelType::Corner: + return CornerShape(); + case PlaceLabelType::Triangle: + return TriangleShape(); + case PlaceLabelType::Hshaped: + return HshapedShape(); + case PlaceLabelType::Button: + return ButtonShape(); + case PlaceLabelType::Circle: + return CircleShape(); + } +QT_WARNING_POP - return PlaceLabelImg(); + return PlaceLabelImg(); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPlaceLabelItem::LabelShapePath() const +{ + return LabelShapePath(LabelShape()); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPlaceLabelItem::LabelShapePath(const PlaceLabelImg &shape) +{ + QPainterPath path; + for (auto &p : shape) + { + if (not p.isEmpty()) + { + path.moveTo(p.first()); + path.addPolygon(p); + } + } + return path; } diff --git a/src/libs/vgeometry/vplacelabelitem.h b/src/libs/vgeometry/vplacelabelitem.h index 55f46004b..2a6a50adb 100644 --- a/src/libs/vgeometry/vplacelabelitem.h +++ b/src/libs/vgeometry/vplacelabelitem.h @@ -37,6 +37,7 @@ class VPlaceLabelItemData; class VContainer; +class QPainterPath; class VPlaceLabelItem : public VPointF { @@ -83,6 +84,9 @@ public: void SetLabelType(PlaceLabelType type); PlaceLabelImg LabelShape() const; + QPainterPath LabelShapePath() const; + + static QPainterPath LabelShapePath(const PlaceLabelImg &shape); private: QSharedDataPointer d; diff --git a/src/libs/vlayout/vabstractpiece.cpp b/src/libs/vlayout/vabstractpiece.cpp index d5199a352..7b466563e 100644 --- a/src/libs/vlayout/vabstractpiece.cpp +++ b/src/libs/vlayout/vabstractpiece.cpp @@ -1491,21 +1491,6 @@ bool VAbstractPiece::IsEkvPointOnLine(const VSAPoint &iPoint, const VSAPoint &pr && qAbs(prevPoint.GetSAAfter(tmpWidth) - nextPoint.GetSABefore(tmpWidth)) < accuracyPointOnLine); } -//--------------------------------------------------------------------------------------------------------------------- -QPainterPath VAbstractPiece::PlaceLabelImgPath(const PlaceLabelImg &img) -{ - QPainterPath path; - for (auto &p : img) - { - if (not p.isEmpty()) - { - path.moveTo(p.first()); - path.addPolygon(p); - } - } - return path; -} - //--------------------------------------------------------------------------------------------------------------------- qreal VAbstractPiece::GetMx() const { diff --git a/src/libs/vlayout/vabstractpiece.h b/src/libs/vlayout/vabstractpiece.h index bcf154c55..af104b03f 100644 --- a/src/libs/vlayout/vabstractpiece.h +++ b/src/libs/vlayout/vabstractpiece.h @@ -237,7 +237,6 @@ protected: static bool IsEkvPointOnLine(const QPointF &iPoint, const QPointF &prevPoint, const QPointF &nextPoint); static bool IsEkvPointOnLine(const VSAPoint &iPoint, const VSAPoint &prevPoint, const VSAPoint &nextPoint); - static QPainterPath PlaceLabelImgPath(const PlaceLabelImg &img); static bool IsItemContained(const QRectF &parentBoundingRect, const QVector &shape, qreal &dX, qreal &dY); static QVector CorrectPosition(const QRectF &parentBoundingRect, QVector points); diff --git a/src/libs/vlayout/vlayoutpiece.cpp b/src/libs/vlayout/vlayoutpiece.cpp index d5cf2e70a..b577673ee 100644 --- a/src/libs/vlayout/vlayoutpiece.cpp +++ b/src/libs/vlayout/vlayoutpiece.cpp @@ -904,7 +904,7 @@ QGraphicsItem *VLayoutPiece::GetItem(bool textAsPaths) const for (auto &label : d->m_placeLabels) { QGraphicsPathItem* pathItem = new QGraphicsPathItem(item); - pathItem->setPath(d->matrix.map(PlaceLabelImgPath(label.shape))); + pathItem->setPath(d->matrix.map(VPlaceLabelItem::LabelShapePath(label.shape))); } CreateLabelStrings(item, d->detailLabel, d->m_tmDetail, textAsPaths); diff --git a/src/libs/vpatterndb/vpassmark.cpp b/src/libs/vpatterndb/vpassmark.cpp new file mode 100644 index 000000000..4942a1ff4 --- /dev/null +++ b/src/libs/vpatterndb/vpassmark.cpp @@ -0,0 +1,870 @@ +/************************************************************************ + ** + ** @file vpassmark.cpp + ** @author Roman Telezhynskyi + ** @date 1 5, 2019 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2019 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 "vpassmark.h" +#include "../vmisc/vabstractapplication.h" +#include "../ifc/exception/vexceptioninvalidnotch.h" +#include "../vgeometry/vabstractcurve.h" +#include "../vgeometry/varc.h" + +namespace +{ +//--------------------------------------------------------------------------------------------------------------------- +PassmarkStatus GetSeamPassmarkSAPoint(VPiecePassmarkData passmarkData, const QVector &seamAllowance, + QPointF &point) +{ + // Correct distorsion + if (VGObject::IsPointOnLineSegment(passmarkData.passmarkSAPoint, passmarkData.previousSAPoint, + passmarkData.nextSAPoint)) + { + const QPointF p = VGObject::CorrectDistortion(passmarkData.passmarkSAPoint, passmarkData.previousSAPoint, + passmarkData.nextSAPoint); + passmarkData.passmarkSAPoint.setX(p.x()); + passmarkData.passmarkSAPoint.setY(p.y()); + } + + bool needRollback = false; // no need for rollback + QVector ekvPoints; + ekvPoints = VAbstractPiece::EkvPoint(ekvPoints, passmarkData.previousSAPoint, passmarkData.passmarkSAPoint, + passmarkData.nextSAPoint, passmarkData.passmarkSAPoint, passmarkData.saWidth, + &needRollback); + + if (needRollback && not seamAllowance.isEmpty()) + { + ekvPoints.clear(); + ekvPoints += seamAllowance.at(seamAllowance.size()-2); + } + + if (ekvPoints.isEmpty()) + { // Just in case + return PassmarkStatus::Error; // Something wrong + } + + if (ekvPoints.size() == 1 || ekvPoints.size() > 2) + { + point = ekvPoints.first(); + } + else if (ekvPoints.size() == 2) + { + if(passmarkData.passmarkSAPoint.GetAngleType() == PieceNodeAngle::ByFirstEdgeSymmetry || + passmarkData.passmarkSAPoint.GetAngleType() == PieceNodeAngle::ByFirstEdgeRightAngle) + { + point = ekvPoints.first(); + } + else + { + QLineF line = QLineF(ekvPoints.at(0), ekvPoints.at(1)); + line.setLength(line.length()/2.); + point = line.p2(); + } + } + return needRollback ? PassmarkStatus::Rollback : PassmarkStatus::Common; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool FixNotchPoint(const QVector &seamAllowance, const QPointF ¬chBase, QPointF *notch) +{ + bool fixed = true; + if (not VAbstractCurve::IsPointOnCurve(seamAllowance, *notch)) + { + fixed = false; + QLineF axis = QLineF(notchBase, *notch); + axis.setLength(ToPixel(50, Unit::Cm)); + const QVector points = VAbstractCurve::CurveIntersectLine(seamAllowance, axis); + + if (points.size() > 0) + { + if (points.size() == 1) + { + *notch = points.at(0); + fixed = true; + } + else + { + QMap forward; + + for ( qint32 i = 0; i < points.size(); ++i ) + { + if (points.at(i) == notchBase) + { // Always seek unique intersection + continue; + } + + const QLineF length(notchBase, points.at(i)); + if (qAbs(length.angle() - axis.angle()) < 0.1) + { + forward.insert(length.length(), i); + } + } + + + // Closest point is not always want we need. First return point in forward direction if exists. + if (not forward.isEmpty()) + { + *notch = points.at(forward.first()); + fixed = true; + } + } + } + } + else + { // Fixing distortion + QLineF axis = QLineF(notchBase, *notch); + axis.setLength(axis.length() + accuracyPointOnLine * 10); + const QVector points = VAbstractCurve::CurveIntersectLine(seamAllowance, axis); + if (points.size() == 1) + { + *notch = points.first(); + } + } + + return fixed; +} +const qreal passmarkGap = (1.5/*mm*/ / 25.4) * PrintDPI; + +//--------------------------------------------------------------------------------------------------------------------- +QLineF FindIntersection(const QLineF &line, const QVector &seamAllowance) +{ + QLineF testLine = line; + testLine.setLength(testLine.length()*10); + QVector intersections = VAbstractCurve::CurveIntersectLine(seamAllowance, testLine); + if (not intersections.isEmpty()) + { + return QLineF(line.p1(), intersections.last()); + } + + return line; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector CreateTwoPassmarkLines(const QLineF &line, const QVector &seamAllowance) +{ + QPointF l1p1; + { + QLineF line1 = line; + line1.setAngle(line1.angle() + 90); + line1.setLength(passmarkGap/2.); + l1p1 = line1.p2(); + } + + QPointF l2p1; + { + QLineF line2 = line; + line2.setAngle(line2.angle() - 90); + line2.setLength(passmarkGap/2.); + l2p1 = line2.p2(); + } + + QPointF l1p2; + { + QLineF line1 = QLineF(line.p2(), line.p1()); + line1.setAngle(line1.angle() - 90); + line1.setLength(passmarkGap/2.); + l1p2 = line1.p2(); + } + + QPointF l2p2; + { + QLineF line2 = QLineF(line.p2(), line.p1()); + line2.setAngle(line2.angle() + 90); + line2.setLength(passmarkGap/2.); + l2p2 = line2.p2(); + } + + QVector lines; + QLineF seg = FindIntersection(QLineF(l1p2, l1p1), seamAllowance); + lines.append(QLineF(seg.p2(), seg.p1())); + + seg = FindIntersection(QLineF(l2p2, l2p1), seamAllowance); + lines.append(QLineF(seg.p2(), seg.p1())); + return lines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector CreateThreePassmarkLines(const QLineF &line, const QVector &seamAllowance) +{ + QPointF l1p1; + { + QLineF line1 = line; + line1.setAngle(line1.angle() + 90); + line1.setLength(passmarkGap); + l1p1 = line1.p2(); + } + + QPointF l2p1; + { + QLineF line2 = line; + line2.setAngle(line2.angle() - 90); + line2.setLength(passmarkGap); + l2p1 = line2.p2(); + } + + QPointF l1p2; + { + QLineF line1 = QLineF(line.p2(), line.p1()); + line1.setAngle(line1.angle() - 90); + line1.setLength(passmarkGap); + l1p2 = line1.p2(); + } + + QPointF l2p2; + { + QLineF line2 = QLineF(line.p2(), line.p1()); + line2.setAngle(line2.angle() + 90); + line2.setLength(passmarkGap); + l2p2 = line2.p2(); + } + + QVector lines; + QLineF seg = FindIntersection(QLineF(l1p2, l1p1), seamAllowance); + lines.append(QLineF(seg.p2(), seg.p1())); + + lines.append(line); + + seg = FindIntersection(QLineF(l2p2, l2p1), seamAllowance); + lines.append(QLineF(seg.p2(), seg.p1())); + return lines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector CreateTMarkPassmark(const QLineF &line) +{ + QPointF p1; + { + QLineF tmpLine = QLineF(line.p2(), line.p1()); + tmpLine.setAngle(tmpLine.angle() - 90); + tmpLine.setLength(line.length() * 0.75 / 2); + p1 = tmpLine.p2(); + } + + QPointF p2; + { + QLineF tmpLine = QLineF(line.p2(), line.p1()); + tmpLine.setAngle(tmpLine.angle() + 90); + tmpLine.setLength(line.length() * 0.75 / 2); + p2 = tmpLine.p2(); + } + + QVector lines; + lines.append(line); + lines.append(QLineF(p1, p2)); + return lines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector CreateVMarkPassmark(const QLineF &line) +{ + QLineF l1 = line; + l1.setAngle(l1.angle() - 35); + + QLineF l2 = line; + l2.setAngle(l2.angle() + 35); + + QVector lines; + lines.append(l1); + lines.append(l2); + return lines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector CreateVMark2Passmark(const QLineF &line, const QVector &seamAllowance) +{ + QLineF l1 = QLineF(line.p2(), line.p1()); + l1.setAngle(l1.angle() + 35); + + QLineF l2 = QLineF(line.p2(), line.p1()); + l2.setAngle(l2.angle() - 35); + + QVector lines; + lines.append(FindIntersection(l1, seamAllowance)); + lines.append(FindIntersection(l2, seamAllowance)); + return lines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector PointsToSegments(const QVector &points) +{ + QVector lines; + if (points.size() >= 2) + { + for (int i=0; i < points.size()-1; ++i) + { + QLineF segment = QLineF(points.at(i), points.at(i+1)); + if (segment.length() > 0) + { + lines.append(segment); + } + } + } + return lines; +} + +const qreal passmarkRadiusFactor = 0.45; + +//--------------------------------------------------------------------------------------------------------------------- +QVector CreateUMarkPassmark(const QLineF &line, const QVector &seamAllowance) +{ + const qreal radius = line.length() * passmarkRadiusFactor; + + QPointF l1p1; + { + QLineF line1 = line; + line1.setAngle(line1.angle() + 90); + line1.setLength(radius); + l1p1 = line1.p2(); + } + + QPointF l2p1; + { + QLineF line2 = line; + line2.setAngle(line2.angle() - 90); + line2.setLength(radius); + l2p1 = line2.p2(); + } + + QPointF l1p2; + { + QLineF line1 = QLineF(line.p2(), line.p1()); + line1.setAngle(line1.angle() - 90); + line1.setLength(radius); + l1p2 = line1.p2(); + } + + QPointF l2p2; + { + QLineF line2 = QLineF(line.p2(), line.p1()); + line2.setAngle(line2.angle() + 90); + line2.setLength(radius); + l2p2 = line2.p2(); + } + + QLineF axis = QLineF(line.p2(), line.p1()); + axis.setLength(radius); + + QVector points; + + QLineF seg = FindIntersection(QLineF(l2p2, l2p1), seamAllowance); + seg = QLineF(seg.p2(), seg.p1()); + seg.setLength(seg.length() - radius); + points.append(seg.p1()); + points.append(seg.p2()); + + VArc arc(VPointF(axis.p2()), radius, QLineF(l1p2, l2p2).angle(), QLineF(l1p2, l2p2).angle()+180); + arc.SetApproximationScale(10); + points += arc.GetPoints(); + + seg = FindIntersection(QLineF(l1p2, l1p1), seamAllowance); + seg = QLineF(seg.p2(), seg.p1()); + seg.setLength(seg.length() - radius); + points.append(seg.p2()); + points.append(seg.p1()); + + return PointsToSegments(points); +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector CreateBoxMarkPassmark(const QLineF &line, const QVector &seamAllowance) +{ + const qreal radius = line.length() * passmarkRadiusFactor; + + QPointF l1p1; + { + QLineF line1 = line; + line1.setAngle(line1.angle() + 90); + line1.setLength(radius); + l1p1 = line1.p2(); + } + + QPointF l2p1; + { + QLineF line2 = line; + line2.setAngle(line2.angle() - 90); + line2.setLength(radius); + l2p1 = line2.p2(); + } + + QPointF l1p2; + { + QLineF line1 = QLineF(line.p2(), line.p1()); + line1.setAngle(line1.angle() - 90); + line1.setLength(radius); + l1p2 = line1.p2(); + } + + QPointF l2p2; + { + QLineF line2 = QLineF(line.p2(), line.p1()); + line2.setAngle(line2.angle() + 90); + line2.setLength(radius); + l2p2 = line2.p2(); + } + + QVector points; + + QLineF seg = FindIntersection(QLineF(l1p2, l1p1), seamAllowance); + points.append(seg.p2()); + points.append(seg.p1()); + + seg = FindIntersection(QLineF(l2p2, l2p1), seamAllowance); + points.append(seg.p1()); + points.append(seg.p2()); + + return PointsToSegments(points); +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector CreatePassmarkLines(PassmarkLineType lineType, PassmarkAngleType angleType, const QLineF &line, + const QVector &seamAllowance) +{ + QVector passmarksLines; + + if (angleType == PassmarkAngleType::Straightforward + || angleType == PassmarkAngleType::Intersection + || angleType == PassmarkAngleType::IntersectionOnlyLeft + || angleType == PassmarkAngleType::IntersectionOnlyRight + || angleType == PassmarkAngleType::Intersection2 + || angleType == PassmarkAngleType::Intersection2OnlyLeft + || angleType == PassmarkAngleType::Intersection2OnlyRight) + { + switch (lineType) + { + case PassmarkLineType::TwoLines: + passmarksLines += CreateTwoPassmarkLines(line, seamAllowance); + break; + case PassmarkLineType::ThreeLines: + passmarksLines += CreateThreePassmarkLines(line, seamAllowance); + break; + case PassmarkLineType::TMark: + passmarksLines += CreateTMarkPassmark(line); + break; + case PassmarkLineType::VMark: + passmarksLines += CreateVMarkPassmark(line); + break; + case PassmarkLineType::VMark2: + passmarksLines += CreateVMark2Passmark(line, seamAllowance); + break; + case PassmarkLineType::UMark: + passmarksLines += CreateUMarkPassmark(line, seamAllowance); + break; + case PassmarkLineType::BoxMark: + passmarksLines += CreateBoxMarkPassmark(line, seamAllowance); + break; + case PassmarkLineType::OneLine: + default: + passmarksLines.append(line); + break; + } + } + else + { + switch (lineType) + { + case PassmarkLineType::TMark: + passmarksLines += CreateTMarkPassmark(line); + break; + case PassmarkLineType::OneLine: + case PassmarkLineType::TwoLines: + case PassmarkLineType::ThreeLines: + case PassmarkLineType::VMark: + case PassmarkLineType::VMark2: + case PassmarkLineType::UMark: + case PassmarkLineType::BoxMark: + default: + passmarksLines.append(line); + break; + } + } + + return passmarksLines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector PassmarkBisector(PassmarkStatus seamPassmarkType, const VPiecePassmarkData &passmarkData, + const QPointF &seamPassmarkSAPoint, const QVector &seamAllowance) +{ + QLineF edge1; + QLineF edge2; + + if (seamPassmarkType == PassmarkStatus::Common) + { + if (passmarkData.passmarkSAPoint.GetAngleType() == PieceNodeAngle::ByFirstEdgeSymmetry) + { + edge1 = QLineF(seamPassmarkSAPoint, seamAllowance.at(seamAllowance.size() - 2)); + edge2 = QLineF(seamPassmarkSAPoint, seamAllowance.at(1)); + } + else + { + const QLineF bigLine1 = VAbstractPiece::ParallelLine(passmarkData.previousSAPoint, + passmarkData.passmarkSAPoint, passmarkData.saWidth ); + const QLineF bigLine2 = VAbstractPiece::ParallelLine(passmarkData.passmarkSAPoint, passmarkData.nextSAPoint, + passmarkData.saWidth ); + + edge1 = QLineF(seamPassmarkSAPoint, bigLine1.p1()); + edge2 = QLineF(seamPassmarkSAPoint, bigLine2.p2()); + } + } + else if(seamPassmarkType == PassmarkStatus::Rollback) + { + edge1 = QLineF(seamPassmarkSAPoint, seamAllowance.at(seamAllowance.size() - 3)); + edge2 = QLineF(seamPassmarkSAPoint, seamAllowance.at(0)); + } + else + { // Should never happen + return QVector(); + } + + const qreal length = passmarkData.passmarkSAPoint.PassmarkLength(passmarkData.saWidth); + if (not passmarkData.passmarkSAPoint.IsManualPasskmarkLength() && length <= accuracyPointOnLine) + { + const QString errorMsg = QObject::tr("Found null notch for point '%1' in piece '%2'. Length is less " + "than minimal allowed.") + .arg(passmarkData.nodeName, passmarkData.pieceName); + qApp->IsPedantic() ? throw VException(errorMsg) : qWarning() << errorMsg; + return QVector(); + } + + edge1.setAngle(edge1.angle() + edge1.angleTo(edge2)/2.); + edge1.setLength(length); + + return CreatePassmarkLines(passmarkData.passmarkLineType, passmarkData.passmarkAngleType, edge1, seamAllowance); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath PassmarkToPath(const QVector &passmark) +{ + QPainterPath path; + if (not passmark.isEmpty()) + { + for (qint32 i = 0; i < passmark.count(); ++i) + { + path.moveTo(passmark.at(i).p1()); + path.lineTo(passmark.at(i).p2()); + } + + path.setFillRule(Qt::WindingFill); + } + return path; +} +} + +//--------------------------------------------------------------------------------------------------------------------- +VPassmark::VPassmark() + : m_data() +{} + +//--------------------------------------------------------------------------------------------------------------------- +VPassmark::VPassmark(const VPiecePassmarkData &data) + : m_data(data), + m_null(false) +{} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPassmark::FullPassmark(const VPiece &piece, const VContainer *data) const +{ + if (m_null) + { + return QVector(); + } + + if (not piece.IsSeamAllowanceBuiltIn()) + { + QVector lines; + lines += SAPassmark(piece, data, PassmarkSide::All); + if (qApp->Settings()->IsDoublePassmark() + && not piece.IsHideMainPath() + && m_data.isMainPathNode + && m_data.passmarkAngleType != PassmarkAngleType::Intersection + && m_data.passmarkAngleType != PassmarkAngleType::IntersectionOnlyLeft + && m_data.passmarkAngleType != PassmarkAngleType::IntersectionOnlyRight + && m_data.passmarkAngleType != PassmarkAngleType::Intersection2 + && m_data.passmarkAngleType != PassmarkAngleType::Intersection2OnlyLeft + && m_data.passmarkAngleType != PassmarkAngleType::Intersection2OnlyRight + && m_data.isShowSecondPassmark) + { + lines += BuiltInSAPassmark(piece, data); + } + return lines; + } + + return BuiltInSAPassmark(piece, data); +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPassmark::SAPassmark(const VPiece &piece, const VContainer *data, PassmarkSide side) const +{ + if (m_null) + { + return QVector(); + } + + if (not piece.IsSeamAllowanceBuiltIn()) + { + // Because rollback cannot be calulated if passmark is not first point in main path we rotate it. + return SAPassmark(piece.SeamAllowancePointsWithRotation(data, m_data.passmarkIndex), side); + } + + return QVector(); +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPassmark::SAPassmark(const QVector &seamAllowance, PassmarkSide side) const +{ + if (m_null) + { + return QVector(); + } + + // Because rollback cannot be calulated if passmark is not first point in main path we rotate it. + return MakeSAPassmark(seamAllowance, side); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VPassmark::IsNull() const +{ + return m_null; +} + +//--------------------------------------------------------------------------------------------------------------------- +VPiecePassmarkData VPassmark::Data() const +{ + return m_data; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPassmark::MakeSAPassmark(const QVector &seamAllowance, PassmarkSide side) const +{ + if (seamAllowance.size() < 2) + { + const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Seam allowance is " + "empty.").arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; + return QVector(); // Something wrong + } + + QPointF seamPassmarkSAPoint; + const PassmarkStatus seamPassmarkType = GetSeamPassmarkSAPoint(m_data, seamAllowance, seamPassmarkSAPoint); + if (seamPassmarkType == PassmarkStatus::Error) + { + const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Cannot find " + "position for a notch.") + .arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; + return QVector(); // Something wrong + } + + if (not FixNotchPoint(seamAllowance, m_data.passmarkSAPoint, &seamPassmarkSAPoint)) + { + const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Unable to fix a " + "notch position.") + .arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; + } + + QVector passmarksLines; + + auto PassmarkIntersection = [&passmarksLines, this, seamAllowance] + (QLineF line, qreal width) + { + line.setLength(line.length()*100); // Hope 100 is enough + + const QVector intersections = VAbstractCurve::CurveIntersectLine(seamAllowance, line); + if (not intersections.isEmpty()) + { + if (intersections.last() != m_data.passmarkSAPoint) + { + line = QLineF(intersections.last(), m_data.passmarkSAPoint); + if (not m_data.passmarkSAPoint.IsManualPasskmarkLength()) + { + const qreal length = qMin(width * VSAPoint::passmarkFactor, VSAPoint::maxPassmarkLength); + if (length <= accuracyPointOnLine) + { + const QString errorMsg = QObject::tr("Found null notch for point '%1' in piece '%2'. Length is " + "less than minimal allowed.") + .arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VException(errorMsg) : qWarning() << errorMsg; + return; + } + line.setLength(length); + } + else + { + line.setLength(m_data.passmarkSAPoint.GetPasskmarkLength()); + } + passmarksLines += CreatePassmarkLines(m_data.passmarkLineType, m_data.passmarkAngleType, + line, seamAllowance); + } + else + { + const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Notch " + "collapse.") + .arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; + } + } + else + { + const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Cannot find " + "intersection.") + .arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; + } + }; + + if (m_data.passmarkAngleType == PassmarkAngleType::Straightforward) + { + const qreal length = m_data.passmarkSAPoint.PassmarkLength(m_data.saWidth); + if (not m_data.passmarkSAPoint.IsManualPasskmarkLength() && length <= accuracyPointOnLine) + { + const QString errorMsg = QObject::tr("Found null notch for point '%1' in piece '%2'. Length is less " + "than minimal allowed.") + .arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; + } + else + { + QLineF line = QLineF(seamPassmarkSAPoint, m_data.passmarkSAPoint); + line.setLength(length); + passmarksLines += CreatePassmarkLines(m_data.passmarkLineType, m_data.passmarkAngleType, line, + seamAllowance); + } + } + else if (m_data.passmarkAngleType == PassmarkAngleType::Bisector) + { + passmarksLines += PassmarkBisector(seamPassmarkType, m_data, seamPassmarkSAPoint, seamAllowance); + } + else if (m_data.passmarkAngleType == PassmarkAngleType::Intersection + || m_data.passmarkAngleType == PassmarkAngleType::IntersectionOnlyLeft + || m_data.passmarkAngleType == PassmarkAngleType::IntersectionOnlyRight) + { + if ((m_data.passmarkAngleType == PassmarkAngleType::Intersection + || m_data.passmarkAngleType == PassmarkAngleType::IntersectionOnlyRight) + && (side == PassmarkSide::All || side == PassmarkSide::Right)) + { + // first passmark + PassmarkIntersection(QLineF(m_data.previousSAPoint, m_data.passmarkSAPoint), + m_data.passmarkSAPoint.GetSAAfter(m_data.saWidth)); + } + + if ((m_data.passmarkAngleType == PassmarkAngleType::Intersection + || m_data.passmarkAngleType == PassmarkAngleType::IntersectionOnlyLeft) + && (side == PassmarkSide::All || side == PassmarkSide::Left)) + { + // second passmark + PassmarkIntersection(QLineF(m_data.nextSAPoint, m_data.passmarkSAPoint), + m_data.passmarkSAPoint.GetSABefore(m_data.saWidth)); + } + } + else if (m_data.passmarkAngleType == PassmarkAngleType::Intersection2 + || m_data.passmarkAngleType == PassmarkAngleType::Intersection2OnlyLeft + || m_data.passmarkAngleType == PassmarkAngleType::Intersection2OnlyRight) + { + if ((m_data.passmarkAngleType == PassmarkAngleType::Intersection2 + || m_data.passmarkAngleType == PassmarkAngleType::Intersection2OnlyRight) + && (side == PassmarkSide::All || side == PassmarkSide::Right)) + { + // first passmark + QLineF line(m_data.passmarkSAPoint, m_data.nextSAPoint); + line.setAngle(line.angle()+90); + PassmarkIntersection(line, m_data.passmarkSAPoint.GetSAAfter(m_data.saWidth)); + } + + if ((m_data.passmarkAngleType == PassmarkAngleType::Intersection2 + || m_data.passmarkAngleType == PassmarkAngleType::Intersection2OnlyLeft) + && (side == PassmarkSide::All || side == PassmarkSide::Left)) + { + // second passmark + QLineF line(m_data.passmarkSAPoint, m_data.previousSAPoint); + line.setAngle(line.angle()-90); + PassmarkIntersection(line, m_data.passmarkSAPoint.GetSABefore(m_data.saWidth)); + } + } + + return passmarksLines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPassmark::BuiltInSAPassmark(const VPiece &piece, const VContainer *data) const +{ + if (m_null) + { + return QVector(); + } + + const QVector mainPath = piece.MainPathPoints(data); + qreal length = 0; + if (not piece.IsSeamAllowanceBuiltIn()) + { + length = m_data.passmarkSAPoint.PassmarkLength(m_data.saWidth); + if (not m_data.passmarkSAPoint.IsManualPasskmarkLength() && length <= accuracyPointOnLine) + { + const QString errorMsg = QObject::tr("Found null notch for point '%1' in piece '%2'. Length is less " + "than minimal allowed.") + .arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; + return QVector(); + } + } + else + { + if (m_data.passmarkSAPoint.IsManualPasskmarkLength()) + { + length = m_data.passmarkSAPoint.GetPasskmarkLength(); + } + else + { + const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2' with built in " + "seam allowance. User must manually provide length.") + .arg(m_data.nodeName, m_data.pieceName); + qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; + return QVector(); + } + } + QVector passmarksLines; + + QLineF edge1 = QLineF(m_data.passmarkSAPoint, m_data.previousSAPoint); + QLineF edge2 = QLineF(m_data.passmarkSAPoint, m_data.nextSAPoint); + + edge1.setAngle(edge1.angle() + edge1.angleTo(edge2)/2.); + edge1.setLength(length); + + passmarksLines += CreatePassmarkLines(m_data.passmarkLineType, m_data.passmarkAngleType, edge1, mainPath); + + return passmarksLines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPassmark::SAPassmarkPath(const VPiece &piece, const VContainer *data, PassmarkSide side) const +{ + return PassmarkToPath(SAPassmark(piece, data, side)); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPassmark::BuiltInSAPassmarkPath(const VPiece &piece, const VContainer *data) const +{ + return PassmarkToPath(BuiltInSAPassmark(piece, data)); +} diff --git a/src/libs/vpatterndb/vpassmark.h b/src/libs/vpatterndb/vpassmark.h new file mode 100644 index 000000000..d7044d93c --- /dev/null +++ b/src/libs/vpatterndb/vpassmark.h @@ -0,0 +1,96 @@ +/************************************************************************ + ** + ** @file vpassmark.h + ** @author Roman Telezhynskyi + ** @date 1 5, 2019 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2019 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 VPASSMARK_H +#define VPASSMARK_H + +#include +#include + +#include "vpiece.h" +#include "../vgeometry/vgeometrydef.h" +#include "../vmisc/typedef.h" + +enum class PassmarkStatus: qint8 +{ + Error = 0, + Common = 1, + Rollback = -1 +}; + +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Weffc++") + +struct VPiecePassmarkData +{ + VSAPoint previousSAPoint{}; + VSAPoint passmarkSAPoint{}; + VSAPoint nextSAPoint{}; + qreal saWidth{0}; + QString nodeName{}; + QString pieceName{}; + PassmarkLineType passmarkLineType{PassmarkLineType::OneLine}; + PassmarkAngleType passmarkAngleType{PassmarkAngleType::Straightforward}; + bool isMainPathNode{true}; + bool isShowSecondPassmark{true}; + int passmarkIndex{-1}; + vidtype id{NULL_ID}; +}; + +Q_DECLARE_METATYPE(VPiecePassmarkData) +Q_DECLARE_TYPEINFO(VPiecePassmarkData, Q_MOVABLE_TYPE); + +QT_WARNING_POP + +enum class PassmarkSide : char { All=0, Left=1, Right=2 }; + +class VPassmark +{ +public: + VPassmark(); + VPassmark(const VPiecePassmarkData &data); + + QVector FullPassmark(const VPiece& piece, const VContainer *data) const; + QVector SAPassmark(const VPiece& piece, const VContainer *data, PassmarkSide side) const; + QVector SAPassmark(const QVector &seamAllowance, PassmarkSide side) const; + QVector BuiltInSAPassmark(const VPiece &piece, const VContainer *data) const; + + QPainterPath SAPassmarkPath(const VPiece& piece, const VContainer *data, PassmarkSide side) const; + QPainterPath BuiltInSAPassmarkPath(const VPiece &piece, const VContainer *data) const; + + bool IsNull() const; + + VPiecePassmarkData Data() const; +private: + VPiecePassmarkData m_data; + bool m_null{true}; + + QVector MakeSAPassmark(const QVector &seamAllowance, PassmarkSide side) const; + +}; + +#endif // VPASSMARK_H diff --git a/src/libs/vpatterndb/vpatterndb.pri b/src/libs/vpatterndb/vpatterndb.pri index ea3bc4cf0..b58357fd3 100644 --- a/src/libs/vpatterndb/vpatterndb.pri +++ b/src/libs/vpatterndb/vpatterndb.pri @@ -26,7 +26,8 @@ SOURCES += \ $$PWD/floatItemData/vgrainlinedata.cpp \ $$PWD/floatItemData/vabstractfloatitemdata.cpp \ $$PWD/measurements.cpp \ - $$PWD/pmsystems.cpp + $$PWD/pmsystems.cpp \ + $$PWD/vpassmark.cpp *msvc*:SOURCES += $$PWD/stable.cpp @@ -75,4 +76,5 @@ HEADERS += \ $$PWD/floatItemData/vpiecelabeldata_p.h \ $$PWD/measurements.h \ $$PWD/pmsystems.h \ - $$PWD/vformula_p.h + $$PWD/vformula_p.h \ + $$PWD/vpassmark.h diff --git a/src/libs/vpatterndb/vpiece.cpp b/src/libs/vpatterndb/vpiece.cpp index 1e9e0efaa..093b095de 100644 --- a/src/libs/vpatterndb/vpiece.cpp +++ b/src/libs/vpatterndb/vpiece.cpp @@ -28,6 +28,7 @@ #include "vpiece.h" #include "vpiece_p.h" +#include "vpassmark.h" #include "../vgeometry/vpointf.h" #include "../vgeometry/vabstractcurve.h" #include "../vgeometry/vplacelabelitem.h" @@ -607,14 +608,30 @@ QVector VPiece::CuttingPathPoints(const VContainer *data) const //--------------------------------------------------------------------------------------------------------------------- QVector VPiece::PassmarksLines(const VContainer *data) const +{ + QVector passmarks = Passmarks(data); + QVector lines; + for(auto &passmark : passmarks) + { + if (not passmark.IsNull()) + { + lines += passmark.FullPassmark(*this, data); + } + } + + return lines; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPiece::Passmarks(const VContainer *data) const { const QVector unitedPath = GetUnitedPath(data); if (not IsSeamAllowance() || not IsPassmarksPossible(unitedPath)) { - return QVector(); + return QVector(); } - QVector passmarks; + QVector passmarks; for (int i = 0; i< unitedPath.size(); ++i) { @@ -633,28 +650,6 @@ QVector VPiece::PassmarksLines(const VContainer *data) const return passmarks; } -//--------------------------------------------------------------------------------------------------------------------- -QVector VPiece::PlaceLabelPoints(const VContainer *data) const -{ - QVector points; - for(auto placeLabel : d->m_placeLabels) - { - try - { - const auto label = data->GeometricObject(placeLabel); - if (label->IsVisible()) - { - points.append(label->LabelShape()); - } - } - catch (const VExceptionBadId &e) - { - qWarning() << e.ErrorMessage(); - } - } - return points; -} - //--------------------------------------------------------------------------------------------------------------------- QVector VPiece::CurvesPainterPath(const VContainer *data) const { @@ -742,19 +737,23 @@ QPainterPath VPiece::PassmarksPath(const VContainer *data) const //--------------------------------------------------------------------------------------------------------------------- QPainterPath VPiece::PlaceLabelPath(const VContainer *data) const { - const QVector points = PlaceLabelPoints(data); QPainterPath path; - - if (not points.isEmpty()) + for(auto placeLabel : d->m_placeLabels) { - for (qint32 i = 0; i < points.count(); ++i) + try { - path.addPath(PlaceLabelImgPath(points.at(i))); + const auto label = data->GeometricObject(placeLabel); + if (label->IsVisible()) + { + path.addPath(label->LabelShapePath()); + } + } + catch (const VExceptionBadId &e) + { + qWarning() << e.ErrorMessage(); } - - path.setFillRule(Qt::WindingFill); } - + path.setFillRule(Qt::WindingFill); return path; } @@ -1376,57 +1375,6 @@ bool VPiece::GetPassmarkNextSAPoints(const QVector &path, int index, return true; } -//--------------------------------------------------------------------------------------------------------------------- -PassmarkStatus VPiece::GetSeamPassmarkSAPoint(VPiecePassmarkData passmarkData, const QVector &seamAllowance, - QPointF &point) -{ - // Correct distorsion - if (VGObject::IsPointOnLineSegment(passmarkData.passmarkSAPoint, passmarkData.previousSAPoint, - passmarkData.nextSAPoint)) - { - const QPointF p = VGObject::CorrectDistortion(passmarkData.passmarkSAPoint, passmarkData.previousSAPoint, - passmarkData.nextSAPoint); - passmarkData.passmarkSAPoint.setX(p.x()); - passmarkData.passmarkSAPoint.setY(p.y()); - } - - bool needRollback = false; // no need for rollback - QVector ekvPoints; - ekvPoints = EkvPoint(ekvPoints, passmarkData.previousSAPoint, passmarkData.passmarkSAPoint, - passmarkData.nextSAPoint, passmarkData.passmarkSAPoint, passmarkData.saWidth, &needRollback); - - if (needRollback && not seamAllowance.isEmpty()) - { - ekvPoints.clear(); - ekvPoints += seamAllowance.at(seamAllowance.size()-2); - } - - if (ekvPoints.isEmpty()) - { // Just in case - return PassmarkStatus::Error; // Something wrong - } - - if (ekvPoints.size() == 1 || ekvPoints.size() > 2) - { - point = ekvPoints.first(); - } - else if (ekvPoints.size() == 2) - { - if(passmarkData.passmarkSAPoint.GetAngleType() == PieceNodeAngle::ByFirstEdgeSymmetry || - passmarkData.passmarkSAPoint.GetAngleType() == PieceNodeAngle::ByFirstEdgeRightAngle) - { - point = ekvPoints.first(); - } - else - { - QLineF line = QLineF(ekvPoints.at(0), ekvPoints.at(1)); - line.setLength(line.length()/2.); - point = line.p2(); - } - } - return needRollback ? PassmarkStatus::Rollback : PassmarkStatus::Common; -} - //--------------------------------------------------------------------------------------------------------------------- bool VPiece::IsPassmarkVisible(const QVector &path, int passmarkIndex) const { @@ -1468,14 +1416,14 @@ bool VPiece::IsPassmarkVisible(const QVector &path, int passmarkInde } //--------------------------------------------------------------------------------------------------------------------- -QVector VPiece::CreatePassmark(const QVector &path, int previousIndex, int passmarkIndex, - int nextIndex, const VContainer *data) const +VPassmark VPiece::CreatePassmark(const QVector &path, int previousIndex, int passmarkIndex, int nextIndex, + const VContainer *data) const { SCASSERT(data != nullptr); if (not IsPassmarkVisible(path, passmarkIndex)) { - return QVector(); + return VPassmark(); } VSAPoint passmarkSAPoint; @@ -1484,21 +1432,26 @@ QVector VPiece::CreatePassmark(const QVector &path, int prev const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'.") .arg(VPiecePath::NodeName(path, passmarkIndex, data), GetName()); qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; - return QVector(); + return VPassmark(); } VSAPoint previousSAPoint; if (not GetPassmarkPreviousSAPoints(path, previousIndex, passmarkSAPoint, data, previousSAPoint, passmarkIndex)) { // No check here because it will cover valid cases - return QVector(); // Something wrong + return VPassmark(); // Something wrong } VSAPoint nextSAPoint; if (not GetPassmarkNextSAPoints(path, nextIndex, passmarkSAPoint, data, nextSAPoint, passmarkIndex)) { // No check here because it will cover valid cases - return QVector(); // Something wrong + return VPassmark(); // Something wrong + } + + if (passmarkSAPoint.IsManualPasskmarkLength() && passmarkSAPoint.GetPasskmarkLength() <= 0) + { + return VPassmark(); } VPiecePassmarkData passmarkData; @@ -1510,232 +1463,12 @@ QVector VPiece::CreatePassmark(const QVector &path, int prev passmarkData.pieceName = GetName(); passmarkData.passmarkLineType = path.at(passmarkIndex).GetPassmarkLineType(); passmarkData.passmarkAngleType = path.at(passmarkIndex).GetPassmarkAngleType(); + passmarkData.isMainPathNode = path.at(passmarkIndex).IsMainPathNode(); + passmarkData.isShowSecondPassmark = path.at(passmarkIndex).IsShowSecondPassmark(); + passmarkData.passmarkIndex = passmarkIndex; + passmarkData.id = path.at(passmarkIndex).GetId(); - const QVector mainPath = MainPathPoints(data); - - if (passmarkSAPoint.IsManualPasskmarkLength() && passmarkSAPoint.GetPasskmarkLength() <= 0) - { - return QVector(); - } - - if (not IsSeamAllowanceBuiltIn()) - { - // Because rollback cannot be calulated if passmark is not first point in main path we rotate it. - const QVector seamAllowance = SeamAllowancePointsWithRotation(data, passmarkIndex); - - QVector lines; - lines += SAPassmark(passmarkData, seamAllowance); - if (qApp->Settings()->IsDoublePassmark() - && not IsHideMainPath() - && path.at(passmarkIndex).IsMainPathNode() - && path.at(passmarkIndex).GetPassmarkAngleType() != PassmarkAngleType::Intersection - && path.at(passmarkIndex).GetPassmarkAngleType() != PassmarkAngleType::IntersectionOnlyLeft - && path.at(passmarkIndex).GetPassmarkAngleType() != PassmarkAngleType::IntersectionOnlyRight - && path.at(passmarkIndex).GetPassmarkAngleType() != PassmarkAngleType::Intersection2 - && path.at(passmarkIndex).GetPassmarkAngleType() != PassmarkAngleType::Intersection2OnlyLeft - && path.at(passmarkIndex).GetPassmarkAngleType() != PassmarkAngleType::Intersection2OnlyRight - && path.at(passmarkIndex).IsShowSecondPassmark()) - { - lines += BuiltInSAPassmark(passmarkData, mainPath); - } - return lines; - } - - return BuiltInSAPassmark(passmarkData, mainPath); -} - -//--------------------------------------------------------------------------------------------------------------------- -QVector VPiece::SAPassmark(const VPiecePassmarkData &passmarkData, const QVector &seamAllowance) -{ - if (seamAllowance.size() < 2) - { - const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Seam allowance is " - "empty.").arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; - return QVector(); // Something wrong - } - - QPointF seamPassmarkSAPoint; - const PassmarkStatus seamPassmarkType = GetSeamPassmarkSAPoint(passmarkData, seamAllowance, seamPassmarkSAPoint); - if (seamPassmarkType == PassmarkStatus::Error) - { - const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Cannot find " - "position for a notch.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; - return QVector(); // Something wrong - } - - if (not FixNotchPoint(seamAllowance, passmarkData.passmarkSAPoint, &seamPassmarkSAPoint)) - { - const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Unable to fix a " - "notch position.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; - } - - QVector passmarksLines; - - auto PassmarkIntersection = [&passmarksLines, passmarkData, seamAllowance] - (QLineF line, qreal width) - { - line.setLength(line.length()*100); // Hope 100 is enough - - const QVector intersections = VAbstractCurve::CurveIntersectLine(seamAllowance, line); - if (not intersections.isEmpty()) - { - if (intersections.last() != passmarkData.passmarkSAPoint) - { - line = QLineF(intersections.last(), passmarkData.passmarkSAPoint); - if (not passmarkData.passmarkSAPoint.IsManualPasskmarkLength()) - { - const qreal length = qMin(width * VSAPoint::passmarkFactor, VSAPoint::maxPassmarkLength); - if (length <= accuracyPointOnLine) - { - const QString errorMsg = QObject::tr("Found null notch for point '%1' in piece '%2'. Length is " - "less than minimal allowed.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VException(errorMsg) : qWarning() << errorMsg; - return; - } - line.setLength(length); - } - else - { - line.setLength(passmarkData.passmarkSAPoint.GetPasskmarkLength()); - } - passmarksLines += CreatePassmarkLines(passmarkData.passmarkLineType, passmarkData.passmarkAngleType, - line, seamAllowance); - } - else - { - const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Notch " - "collapse.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; - } - } - else - { - const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2'. Cannot find " - "intersection.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VExceptionInvalidNotch(errorMsg) : qWarning() << errorMsg; - } - }; - - if (passmarkData.passmarkAngleType == PassmarkAngleType::Straightforward) - { - const qreal length = passmarkData.passmarkSAPoint.PassmarkLength(passmarkData.saWidth); - if (not passmarkData.passmarkSAPoint.IsManualPasskmarkLength() && length <= accuracyPointOnLine) - { - const QString errorMsg = QObject::tr("Found null notch for point '%1' in piece '%2'. Length is less " - "than minimal allowed.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VException(errorMsg) : qWarning() << errorMsg; - } - else - { - QLineF line = QLineF(seamPassmarkSAPoint, passmarkData.passmarkSAPoint); - line.setLength(length); - passmarksLines += CreatePassmarkLines(passmarkData.passmarkLineType, passmarkData.passmarkAngleType, line, - seamAllowance); - } - } - else if (passmarkData.passmarkAngleType == PassmarkAngleType::Bisector) - { - passmarksLines += PassmarkBisector(seamPassmarkType, passmarkData, seamPassmarkSAPoint, seamAllowance); - } - else if (passmarkData.passmarkAngleType == PassmarkAngleType::Intersection - || passmarkData.passmarkAngleType == PassmarkAngleType::IntersectionOnlyLeft - || passmarkData.passmarkAngleType == PassmarkAngleType::IntersectionOnlyRight) - { - if (passmarkData.passmarkAngleType == PassmarkAngleType::Intersection - || passmarkData.passmarkAngleType == PassmarkAngleType::IntersectionOnlyRight) - { - // first passmark - PassmarkIntersection(QLineF(passmarkData.previousSAPoint, passmarkData.passmarkSAPoint), - passmarkData.passmarkSAPoint.GetSAAfter(passmarkData.saWidth)); - } - - if (passmarkData.passmarkAngleType == PassmarkAngleType::Intersection - || passmarkData.passmarkAngleType == PassmarkAngleType::IntersectionOnlyLeft) - { - // second passmark - PassmarkIntersection(QLineF(passmarkData.nextSAPoint, passmarkData.passmarkSAPoint), - passmarkData.passmarkSAPoint.GetSABefore(passmarkData.saWidth)); - } - } - else if (passmarkData.passmarkAngleType == PassmarkAngleType::Intersection2 - || passmarkData.passmarkAngleType == PassmarkAngleType::Intersection2OnlyLeft - || passmarkData.passmarkAngleType == PassmarkAngleType::Intersection2OnlyRight) - { - if (passmarkData.passmarkAngleType == PassmarkAngleType::Intersection2 - || passmarkData.passmarkAngleType == PassmarkAngleType::Intersection2OnlyRight) - { - // first passmark - QLineF line(passmarkData.passmarkSAPoint, passmarkData.nextSAPoint); - line.setAngle(line.angle()+90); - PassmarkIntersection(line, passmarkData.passmarkSAPoint.GetSAAfter(passmarkData.saWidth)); - } - - if (passmarkData.passmarkAngleType == PassmarkAngleType::Intersection2 - || passmarkData.passmarkAngleType == PassmarkAngleType::Intersection2OnlyLeft) - { - // second passmark - QLineF line(passmarkData.passmarkSAPoint, passmarkData.previousSAPoint); - line.setAngle(line.angle()-90); - PassmarkIntersection(line, passmarkData.passmarkSAPoint.GetSABefore(passmarkData.saWidth)); - } - } - - return passmarksLines; -} - -//--------------------------------------------------------------------------------------------------------------------- -QVector VPiece::BuiltInSAPassmark(const VPiecePassmarkData &passmarkData, - const QVector &mainPath) const -{ - qreal length = 0; - if (not IsSeamAllowanceBuiltIn()) - { - length = passmarkData.passmarkSAPoint.PassmarkLength(passmarkData.saWidth); - if (not passmarkData.passmarkSAPoint.IsManualPasskmarkLength() && length <= accuracyPointOnLine) - { - const QString errorMsg = QObject::tr("Found null notch for point '%1' in piece '%2'. Length is less " - "than minimal allowed.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VException(errorMsg) : qWarning() << errorMsg; - return QVector(); - } - } - else - { - if (passmarkData.passmarkSAPoint.IsManualPasskmarkLength()) - { - length = passmarkData.passmarkSAPoint.GetPasskmarkLength(); - } - else - { - const QString errorMsg = QObject::tr("Cannot calculate a notch for point '%1' in piece '%2' with built in " - "seam allowance. User must manually provide length.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VException(errorMsg) : qWarning() << errorMsg; - return QVector(); - } - } - QVector passmarksLines; - - QLineF edge1 = QLineF(passmarkData.passmarkSAPoint, passmarkData.previousSAPoint); - QLineF edge2 = QLineF(passmarkData.passmarkSAPoint, passmarkData.nextSAPoint); - - edge1.setAngle(edge1.angle() + edge1.angleTo(edge2)/2.); - edge1.setLength(length); - - passmarksLines += CreatePassmarkLines(passmarkData.passmarkLineType, passmarkData.passmarkAngleType, edge1, - mainPath); - - return passmarksLines; + return VPassmark(passmarkData); } //--------------------------------------------------------------------------------------------------------------------- @@ -1751,54 +1484,3 @@ int VPiece::IsCSAStart(const QVector &records, quint32 id) return -1; } - -//--------------------------------------------------------------------------------------------------------------------- -QVector VPiece::PassmarkBisector(PassmarkStatus seamPassmarkType, const VPiecePassmarkData &passmarkData, - const QPointF &seamPassmarkSAPoint, const QVector &seamAllowance) -{ - QLineF edge1; - QLineF edge2; - - if (seamPassmarkType == PassmarkStatus::Common) - { - if (passmarkData.passmarkSAPoint.GetAngleType() == PieceNodeAngle::ByFirstEdgeSymmetry) - { - edge1 = QLineF(seamPassmarkSAPoint, seamAllowance.at(seamAllowance.size() - 2)); - edge2 = QLineF(seamPassmarkSAPoint, seamAllowance.at(1)); - } - else - { - const QLineF bigLine1 = ParallelLine(passmarkData.previousSAPoint, passmarkData.passmarkSAPoint, - passmarkData.saWidth ); - const QLineF bigLine2 = ParallelLine(passmarkData.passmarkSAPoint, passmarkData.nextSAPoint, - passmarkData.saWidth ); - - edge1 = QLineF(seamPassmarkSAPoint, bigLine1.p1()); - edge2 = QLineF(seamPassmarkSAPoint, bigLine2.p2()); - } - } - else if(seamPassmarkType == PassmarkStatus::Rollback) - { - edge1 = QLineF(seamPassmarkSAPoint, seamAllowance.at(seamAllowance.size() - 3)); - edge2 = QLineF(seamPassmarkSAPoint, seamAllowance.at(0)); - } - else - { // Should never happen - return QVector(); - } - - const qreal length = passmarkData.passmarkSAPoint.PassmarkLength(passmarkData.saWidth); - if (not passmarkData.passmarkSAPoint.IsManualPasskmarkLength() && length <= accuracyPointOnLine) - { - const QString errorMsg = QObject::tr("Found null notch for point '%1' in piece '%2'. Length is less " - "than minimal allowed.") - .arg(passmarkData.nodeName, passmarkData.pieceName); - qApp->IsPedantic() ? throw VException(errorMsg) : qWarning() << errorMsg; - return QVector(); - } - - edge1.setAngle(edge1.angle() + edge1.angleTo(edge2)/2.); - edge1.setLength(length); - - return CreatePassmarkLines(passmarkData.passmarkLineType, passmarkData.passmarkAngleType, edge1, seamAllowance); -} diff --git a/src/libs/vpatterndb/vpiece.h b/src/libs/vpatterndb/vpiece.h index c0bffdb94..625d06f0c 100644 --- a/src/libs/vpatterndb/vpiece.h +++ b/src/libs/vpatterndb/vpiece.h @@ -46,33 +46,7 @@ class VGrainlineData; class VContainer; class QPainterPath; class VPointF; - -QT_WARNING_PUSH -QT_WARNING_DISABLE_GCC("-Weffc++") - -enum class PassmarkStatus: qint8 -{ - Error = 0, - Common = 1, - Rollback = -1 -}; - -struct VPiecePassmarkData -{ - VSAPoint previousSAPoint; - VSAPoint passmarkSAPoint; - VSAPoint nextSAPoint; - qreal saWidth; - QString nodeName; - QString pieceName; - PassmarkLineType passmarkLineType; - PassmarkAngleType passmarkAngleType; -}; - -Q_DECLARE_METATYPE(VPiecePassmarkData) -Q_DECLARE_TYPEINFO(VPiecePassmarkData, Q_MOVABLE_TYPE); - -QT_WARNING_POP +class VPassmark; class VPiece : public VAbstractPiece { @@ -100,7 +74,8 @@ public: QVector SeamAllowancePoints(const VContainer *data) const; QVector CuttingPathPoints(const VContainer *data) const; QVector PassmarksLines(const VContainer *data) const; - QVector PlaceLabelPoints(const VContainer *data) const; + + QVector Passmarks(const VContainer *data) const; QVector CurvesPainterPath(const VContainer *data) const; @@ -160,8 +135,6 @@ public: QVector GetUnitedPath(const VContainer *data) const; - static QVector SAPassmark(const VPiecePassmarkData &passmarkData, const QVector &seamAllowance); -protected: QVector SeamAllowancePointsWithRotation(const VContainer *data, int makeFirst) const; private: QSharedDataPointer d; @@ -176,30 +149,13 @@ private: const VContainer *data, VSAPoint &point, int passmarkIndex) const; bool GetPassmarkNextSAPoints(const QVector &path, int index, const VSAPoint &passmarkSAPoint, const VContainer *data, VSAPoint &point, int passmarkIndex) const; - static PassmarkStatus GetSeamPassmarkSAPoint(VPiecePassmarkData passmarkData, - const QVector &seamAllowance, QPointF &point); bool IsPassmarkVisible(const QVector &path, int passmarkIndex) const; - QVector CreatePassmark(const QVector &path, int previousIndex, int passmarkIndex, int nextIndex, - const VContainer *data) const; - - QVector BuiltInSAPassmark(const VPiecePassmarkData &passmarkData, const QVector &mainPath) const; - static QVector PassmarkBisector(PassmarkStatus seamPassmarkType, const VPiecePassmarkData &passmarkData, - const QPointF &seamPassmarkSAPoint, const QVector& seamAllowance); + VPassmark CreatePassmark(const QVector &path, int previousIndex, int passmarkIndex, int nextIndex, + const VContainer *data) const; static int IsCSAStart(const QVector &records, quint32 id); - - PlaceLabelImg LabelShape(const VContainer *data) const; - PlaceLabelImg SegmentShape(const VContainer *data) const; - PlaceLabelImg RectangleShape(const VContainer *data) const; - PlaceLabelImg CrossShape(const VContainer *data) const; - PlaceLabelImg TshapedShape(const VContainer *data) const; - PlaceLabelImg DoubletreeShape(const VContainer *data) const; - PlaceLabelImg CornerShape(const VContainer *data) const; - PlaceLabelImg TriangleShape(const VContainer *data) const; - PlaceLabelImg HshapedShape(const VContainer *data) const; - PlaceLabelImg ButtonShape(const VContainer *data) const; }; Q_DECLARE_TYPEINFO(VPiece, Q_MOVABLE_TYPE); diff --git a/src/libs/vwidgets/vgraphicssimpletextitem.cpp b/src/libs/vwidgets/vgraphicssimpletextitem.cpp index 2e6a609f3..571b7eafd 100644 --- a/src/libs/vwidgets/vgraphicssimpletextitem.cpp +++ b/src/libs/vwidgets/vgraphicssimpletextitem.cpp @@ -278,7 +278,7 @@ void VGraphicsSimpleTextItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) */ void VGraphicsSimpleTextItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { - this->setBrush(Qt::black); + this->setBrush(m_baseColor); QGraphicsSimpleTextItem::hoverLeaveEvent(event); } @@ -359,6 +359,19 @@ void VGraphicsSimpleTextItem::keyReleaseEvent(QKeyEvent *event) QGraphicsSimpleTextItem::keyReleaseEvent ( event ); } +//--------------------------------------------------------------------------------------------------------------------- +QColor VGraphicsSimpleTextItem::BaseColor() const +{ + return m_baseColor; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VGraphicsSimpleTextItem::SetBaseColor(const QColor &baseColor) +{ + m_baseColor = baseColor; + setBrush(m_baseColor); +} + //--------------------------------------------------------------------------------------------------------------------- void VGraphicsSimpleTextItem::Init() { diff --git a/src/libs/vwidgets/vgraphicssimpletextitem.h b/src/libs/vwidgets/vgraphicssimpletextitem.h index c70b53957..351f03018 100644 --- a/src/libs/vwidgets/vgraphicssimpletextitem.h +++ b/src/libs/vwidgets/vgraphicssimpletextitem.h @@ -66,6 +66,8 @@ public: void SetRealPos(QPointF pos); + QColor BaseColor() const; + void SetBaseColor(const QColor &BaseColor); signals: /** @@ -96,6 +98,7 @@ private: qreal m_oldScale; bool m_showParentTooltip; QPointF m_realPos{}; + QColor m_baseColor{Qt::black}; void Init(); diff --git a/src/test/ValentinaTest/tst_vpiece.cpp b/src/test/ValentinaTest/tst_vpiece.cpp index a024f8b16..2adf10b2b 100644 --- a/src/test/ValentinaTest/tst_vpiece.cpp +++ b/src/test/ValentinaTest/tst_vpiece.cpp @@ -29,6 +29,7 @@ #include "tst_vpiece.h" #include "../vpatterndb/vcontainer.h" #include "../vpatterndb/vpiece.h" +#include "../vpatterndb/vpassmark.h" #include "../vpatterndb/vpiecenode.h" #include "../vpatterndb/vpiecepath.h" #include "../vgeometry/vsplinepath.h" @@ -980,5 +981,7 @@ void TST_VPiece::TestSAPassmark() QFETCH(QVector, seamAllowance); QFETCH(QVector, expectedResult); - Comparison(VPiece::SAPassmark(passmarkData, seamAllowance), expectedResult); + VPassmark passmark(passmarkData); + + Comparison(passmark.SAPassmark(seamAllowance, PassmarkSide::All), expectedResult); }