diff --git a/src/libs/vlayout/vabstractpiece.cpp b/src/libs/vlayout/vabstractpiece.cpp index 003235c5b..4577f191b 100644 --- a/src/libs/vlayout/vabstractpiece.cpp +++ b/src/libs/vlayout/vabstractpiece.cpp @@ -109,6 +109,54 @@ void VAbstractPiece::SetSAWidth(qreal value) value >= 0 ? d->m_width = value : d->m_width = 0; } +//--------------------------------------------------------------------------------------------------------------------- +QVector VAbstractPiece::Equidistant(const QVector &points, qreal width) +{ + QVector ekvPoints; + + if (width <= 0) + { + qDebug()<<"Width <= 0."; + return QVector(); + } + + QVector p = CorrectEquidistantPoints(points); + if ( p.size() < 3 ) + { + qDebug()<<"Not enough points for building the equidistant."; + return QVector(); + } + + if (p.last().toPoint() != p.first().toPoint()) + { + p.append(p.at(0));// Should be always closed + } + + for (qint32 i = 0; i < p.size(); ++i ) + { + if ( i == 0) + {//first point + ekvPoints << EkvPoint(QLineF(p.at(p.size()-2), p.at(p.size()-1)), QLineF(p.at(1), p.at(0)), width); + continue; + } + + if (i == p.size()-1) + {//last point + if (not ekvPoints.isEmpty()) + { + ekvPoints.append(ekvPoints.at(0)); + } + continue; + } + //points in the middle of polyline + ekvPoints << EkvPoint(QLineF(p.at(i-1), p.at(i)), QLineF(p.at(i+1), p.at(i)), width); + } + + const bool removeFirstAndLast = false; + ekvPoints = CheckLoops(CorrectEquidistantPoints(ekvPoints, removeFirstAndLast));//Result path can contain loops + return ekvPoints; +} + //--------------------------------------------------------------------------------------------------------------------- qreal VAbstractPiece::SumTrapezoids(const QVector &points) { @@ -349,3 +397,140 @@ QVector VAbstractPiece::RemoveDublicates(const QVector &points return p; } + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief EkvPoint return vector of points of equidistant two lines. Last point of two lines must be equal. + * @param line1 first line. + * @param line2 second line. + * @param width width of equidistant. + * @return vector of points. + */ +QVector VAbstractPiece::EkvPoint(const QLineF &line1, const QLineF &line2, qreal width) +{ + if (width <= 0) + { + return QVector(); + } + + QVector points; + if (line1.p2() != line2.p2()) + { + qDebug()<<"Last points of two lines must be equal."; + return QVector(); + } + + QPointF CrosPoint; + 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) + { + case (QLineF::BoundedIntersection): + points.append(CrosPoint); + return points; + break; + case (QLineF::UnboundedIntersection): + { + 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 + line.setLength(width); // Not sure about width value here + QLineF cutLine(line.p2(), CrosPoint); // Cut line is a perpendicular + cutLine.setLength(length); // Decided take this length + + // We do not check intersection type because intersection must alwayse exist + QPointF px; + cutLine.setAngle(cutLine.angle()+90); + QLineF::IntersectType type = bigLine1.intersect( cutLine, &px ); + if (type == QLineF::NoIntersection) + { + qDebug()<<"Couldn't find intersection with cut line."; + } + points.append(px); + + cutLine.setAngle(cutLine.angle()-180); + type = bigLine2.intersect( cutLine, &px ); + if (type == QLineF::NoIntersection) + { + qDebug()<<"Couldn't find intersection with cut line."; + } + points.append(px); + } + else + { + 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): + /*If we have correct lines this means lines lie on a line.*/ + points.append(bigLine1.p2()); + return points; + break; + default: + break; + } + return points; +} + +//--------------------------------------------------------------------------------------------------------------------- +QLineF VAbstractPiece::ParallelLine(const QLineF &line, qreal width) +{ + const QLineF paralel = QLineF(SingleParallelPoint(line, 90, width), + SingleParallelPoint(QLineF(line.p2(), line.p1()), -90, width)); + return paralel; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPointF VAbstractPiece::SingleParallelPoint(const QLineF &line, qreal angle, qreal width) +{ + QLineF pLine = line; + pLine.setAngle( pLine.angle() + angle ); + pLine.setLength( width ); + return pLine.p2(); +} + +//--------------------------------------------------------------------------------------------------------------------- +int VAbstractPiece::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()); +} diff --git a/src/libs/vlayout/vabstractpiece.h b/src/libs/vlayout/vabstractpiece.h index fdf6908c3..230db9539 100644 --- a/src/libs/vlayout/vabstractpiece.h +++ b/src/libs/vlayout/vabstractpiece.h @@ -35,6 +35,7 @@ template class QVector; class QPointF; class VAbstractPieceData; +class QLineF; class VAbstractPiece { @@ -56,6 +57,7 @@ public: qreal GetSAWidth() const; void SetSAWidth(qreal value); + static QVector Equidistant(const QVector &points, qreal width); static qreal SumTrapezoids(const QVector &points); static QVector CheckLoops(const QVector &points); static QVector CorrectEquidistantPoints(const QVector &points, bool removeFirstAndLast = true); @@ -65,6 +67,11 @@ protected: private: QSharedDataPointer d; + + static QVector EkvPoint(const QLineF &line1, const QLineF &line2, qreal width); + static QLineF ParallelLine(const QLineF &line, qreal width); + static QPointF SingleParallelPoint(const QLineF &line, qreal angle, qreal width); + static int BisectorAngle(const QPointF &p1, const QPointF &p2, const QPointF &p3); }; #endif // VABSTRACTPIECE_H diff --git a/src/libs/vpatterndb/vpiece.cpp b/src/libs/vpatterndb/vpiece.cpp index 5f25e37cb..da0183809 100644 --- a/src/libs/vpatterndb/vpiece.cpp +++ b/src/libs/vpatterndb/vpiece.cpp @@ -200,6 +200,50 @@ QVector VPiece::MainPathNodePoints(const VContainer *data) const return points; } +//--------------------------------------------------------------------------------------------------------------------- +QVector VPiece::SeamAllowancePoints(const VContainer *data) const +{ + SCASSERT(data != nullptr); + + QVector pointsEkv; + if (not IsSeamAllowance()) + { + return pointsEkv; + } + + for (int i = 0; i< CountNodes(); ++i) + { + switch (at(i).GetTypeTool()) + { + case (Tool::NodePoint): + { + const QSharedPointer point = data->GeometricObject(at(i).GetId()); + pointsEkv.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()); + + pointsEkv << curve->GetSegmentPoints(begin, end, at(i).GetReverse()); + } + break; + default: + qDebug()<<"Get wrong tool type. Ignore."<< static_cast(at(i).GetTypeTool()); + break; + } + } + + pointsEkv = CheckLoops(CorrectEquidistantPoints(pointsEkv));//A path can contains loops + pointsEkv = Equidistant(pointsEkv, ToPixel(GetSAWidth(), *data->GetPatternUnit())); + return pointsEkv; +} + //--------------------------------------------------------------------------------------------------------------------- QPainterPath VPiece::MainPathPath(const VContainer *data) const { @@ -220,6 +264,30 @@ QPainterPath VPiece::MainPathPath(const VContainer *data) const return path; } +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPiece::SeamAllowancePath(const VContainer *data) const +{ + const QVector pointsEkv = SeamAllowancePoints(data); + QPainterPath ekv; + + // seam allowence + if (IsSeamAllowance()) + { + if (not pointsEkv.isEmpty()) + { + ekv.moveTo(pointsEkv.at(0)); + for (qint32 i = 1; i < pointsEkv.count(); ++i) + { + ekv.lineTo(pointsEkv.at(i)); + } + + ekv.setFillRule(Qt::WindingFill); + } + } + + return ekv; +} + //--------------------------------------------------------------------------------------------------------------------- qreal VPiece::GetMx() const { diff --git a/src/libs/vpatterndb/vpiece.h b/src/libs/vpatterndb/vpiece.h index 31e82d401..ad5834580 100644 --- a/src/libs/vpatterndb/vpiece.h +++ b/src/libs/vpatterndb/vpiece.h @@ -62,8 +62,10 @@ public: QVector MainPathPoints(const VContainer *data) const; QVector MainPathNodePoints(const VContainer *data) const; + QVector SeamAllowancePoints(const VContainer *data) const; QPainterPath MainPathPath(const VContainer *data) const; + QPainterPath SeamAllowancePath(const VContainer *data) const; qreal GetMx() const; void SetMx(qreal value); diff --git a/src/libs/vtools/tools/vtoolseamallowance.cpp b/src/libs/vtools/tools/vtoolseamallowance.cpp index e92a573a8..af6b06943 100644 --- a/src/libs/vtools/tools/vtoolseamallowance.cpp +++ b/src/libs/vtools/tools/vtoolseamallowance.cpp @@ -607,7 +607,8 @@ VToolSeamAllowance::VToolSeamAllowance(VAbstractPattern *doc, VContainer *data, VNoBrushScalePathItem(parent), m_dialog(), m_sceneDetails(scene), - m_drawName(drawName) + m_drawName(drawName), + m_seamAllowance(new VNoBrushScalePathItem(this)) { VPiece detail = data->GetPiece(id); for (int i = 0; i< detail.CountNodes(); ++i) @@ -639,6 +640,7 @@ VToolSeamAllowance::VToolSeamAllowance(VAbstractPattern *doc, VContainer *data, RefreshGeometry(); this->setBrush(QBrush(Qt::Dense7Pattern)); + m_seamAllowance->setBrush(QBrush(Qt::FDiagPattern)); this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); this->setFlag(QGraphicsItem::ItemIsFocusable, true);// For keyboard input focus @@ -670,6 +672,17 @@ void VToolSeamAllowance::RefreshGeometry() this->setPath(mainPath); this->setPos(detail.GetMx(), detail.GetMy()); + if (detail.IsSeamAllowance()) + { + mainPath.addPath(detail.SeamAllowancePath(this->getData())); + mainPath.setFillRule(Qt::OddEvenFill); + m_seamAllowance->setPath(mainPath); + } + else + { + m_seamAllowance->setPath(QPainterPath()); + } + this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); } diff --git a/src/libs/vtools/tools/vtoolseamallowance.h b/src/libs/vtools/tools/vtoolseamallowance.h index cbb9eaec3..dd65595ee 100644 --- a/src/libs/vtools/tools/vtoolseamallowance.h +++ b/src/libs/vtools/tools/vtoolseamallowance.h @@ -115,6 +115,8 @@ private: VMainGraphicsScene *m_sceneDetails; QString m_drawName; + VNoBrushScalePathItem *m_seamAllowance; + void SetDialog(); template