54 #include "../vmisc/vabstractapplication.h"
55 #include "../vgeometry/vpointf.h"
60 #include <QPainterPath>
64 #ifdef Q_COMPILER_RVALUE_REFS
66 { Swap(piece);
return *
this; }
70 { std::swap(d, piece.d); }
137 return d->m_pieceLock;
143 d->m_pieceLock = value;
149 return d->m_forbidFlipping;
155 d->m_forbidFlipping = value;
161 return d->m_seamAllowance;
167 d->m_seamAllowance = value;
173 return d->m_seamAllowanceBuiltIn;
179 d->m_seamAllowanceBuiltIn = value;
185 return d->m_hideMainPath;
191 d->m_hideMainPath = value;
203 value >= 0 ?
d->m_width = value :
d->m_width = 0;
211 qDebug()<<
"Width < 0.";
218 qDebug()<<
"Not enough points for building the equidistant.";
222 if (p.last().toPoint() != p.first().toPoint())
228 for (qint32 i = 0; i < p.size(); ++i )
232 ekvPoints <<
EkvPoint(p.at(p.size()-2), p.at(p.size()-1),
233 p.at(1), p.at(0), width);
239 if (not ekvPoints.isEmpty())
241 ekvPoints.append(ekvPoints.at(0));
246 ekvPoints <<
EkvPoint(p.at(i-1), p.at(i),
247 p.at(i+1), p.at(i), width);
250 const bool removeFirstAndLast =
false;
260 const int n = points.size();
264 for (
int i = 0; i < n; ++i)
269 s = points.at(i).x()*(points.at(n-1).y() - points.at(i+1).y());
277 s = points.at(i).x()*(points.at(i-1).y() - points.at(0).y());
282 s = points.at(i).x()*(points.at(i-1).y() - points.at(i+1).y());
299 if(points.count() < 3)
317 int count = points.size();
324 const bool pathClosed = (points.first() == points.last());
328 qint32 i, j, jNext = 0;
329 for (i = 0; i < count; ++i)
335 ekvPoints.append(points.at(i));
339 enum LoopIntersectType { NoIntersection, BoundedIntersection, ParallelIntersection };
342 LoopIntersectType status = NoIntersection;
343 const QLineF line1(points.at(i), points.at(i+1));
346 for (j = count-1; j >= i+2; --j)
348 j == count-1 ? jNext = 0 : jNext = j+1;
349 QLineF line2(points.at(j), points.at(jNext));
351 if(qFuzzyIsNull(line2.length()))
358 auto AddUniqueIndex = [&uniqueVertices](qint32 i)
360 if (not uniqueVertices.contains(i))
362 uniqueVertices.append(i);
371 pathClosed && jNext == count-1 ? AddUniqueIndex(0) : AddUniqueIndex(jNext);
373 const QLineF::IntersectType intersect = line1.intersects(line2, &crosPoint);
374 if (intersect == QLineF::NoIntersection)
380 && uniqueVertices.size() == 4)
383 QLineF tmpLine1 = line1;
384 QLineF tmpLine2 = line2;
386 tmpLine1.setAngle(tmpLine1.angle()+90);
388 QPointF tmpCrosPoint;
389 const QLineF::IntersectType tmpIntrs1 = tmpLine1.intersects(tmpLine2, &tmpCrosPoint);
392 tmpLine2.setAngle(tmpLine2.angle()+90);
394 const QLineF::IntersectType tmpIntrs2 = tmpLine1.intersects(tmpLine2, &tmpCrosPoint);
396 if (tmpIntrs1 == QLineF::BoundedIntersection || tmpIntrs2 == QLineF::BoundedIntersection)
402 status = ParallelIntersection;
408 else if (intersect == QLineF::BoundedIntersection)
410 if (uniqueVertices.size() == 4)
412 if ((line1.p1() != crosPoint
413 && line1.p2() != crosPoint
414 && line2.p1() != crosPoint
415 && line2.p2() != crosPoint) ||
CheckIntersection(points, i, i+1, j, jNext, crosPoint))
417 status = BoundedIntersection;
422 status = NoIntersection;
427 case ParallelIntersection:
429 ekvPoints.append(points.at(i));
430 ekvPoints.append(points.at(jNext));
431 jNext > j ? i = jNext : i = j;
433 case BoundedIntersection:
434 ekvPoints.append(points.at(i));
435 ekvPoints.append(crosPoint);
440 ekvPoints.append(points.at(i));
452 return (line.p2().x() - line.p1().x()) * (p.y() - line.p1().y()) -
453 (line.p2().y() - line.p1().y()) * (p.x() - line.p1().x());
490 if (p2Line1 != p2Line2)
492 qDebug()<<
"Last points of two lines must be equal.";
499 const QLineF::IntersectType type = bigLine1.intersects( bigLine2, &CrosPoint );
502 case (QLineF::BoundedIntersection):
504 points.append(CrosPoint);
506 case (QLineF::UnboundedIntersection):
508 const qreal localWidth =
MaxLocalSA(p2Line1, width);
509 QLineF line( p2Line1, CrosPoint );
512 const QLineF b1 =
BisectorLine(p1Line1, p2Line1, p1Line2);
513 const QLineF b2 =
BisectorLine(bigLine1.p1(), CrosPoint, bigLine2.p2());
522 QT_WARNING_DISABLE_GCC(
"-Wswitch-default")
526 return AngleByLength(p2Line1, bigLine1.p1(), CrosPoint, bigLine2.p2(), localWidth);
528 return AngleByIntersection(p1Line1, p2Line1, p1Line2, bigLine1.p1(), CrosPoint, bigLine2.p2(),
547 QLineF bisector(p2Line1, p1Line1);
548 bisector.setAngle(b1.angle());
550 const qreal result1 =
PointPosition(bisector.p2(), QLineF(p1Line1, p2Line1));
551 const qreal result2 =
PointPosition(bisector.p2(), QLineF(p2Line2, p1Line2));
553 if ((result1 < 0 || qFuzzyIsNull(result1)) && (result2 < 0 || qFuzzyIsNull(result2)))
559 const QLineF::IntersectType type = bigEdge.intersects(line, &px);
560 if (type != QLineF::BoundedIntersection)
562 if (line.length() < QLineF(p2Line1, px).length())
564 points.append(CrosPoint);
571 const qreal result1 =
PointPosition(CrosPoint, QLineF(p1Line1, p2Line1));
572 const qreal result2 =
PointPosition(CrosPoint, QLineF(p2Line2, p1Line2));
574 if ((result1 < 0 || qFuzzyIsNull(result1)) && (result2 < 0 || qFuzzyIsNull(result2)))
576 if (line.length() >= localWidth)
578 points.append(CrosPoint);
583 line.setLength(localWidth);
584 points.append(line.p2());
591 points.append(bigEdge.p1());
592 points.append(bigEdge.p2());
599 case (QLineF::NoIntersection):
601 points.append(bigLine1.p2());
611 const QPointF &sp3, qreal width)
615 QLineF line(p2, sp2);
616 const qreal length = line.length();
617 if (length > width*
maxL)
619 line.setLength(width);
620 QLineF cutLine(line.p2(), sp2);
621 cutLine.setLength(length);
625 cutLine.setAngle(cutLine.angle()+90);
626 QLineF::IntersectType type = QLineF(sp1, sp2).intersects(cutLine, &px);
627 if (type == QLineF::NoIntersection)
629 qDebug()<<
"Couldn't find intersection with cut line.";
633 cutLine.setAngle(cutLine.angle()-180);
634 type = QLineF(sp2, sp3).intersects(cutLine, &px);
635 if (type == QLineF::NoIntersection)
637 qDebug()<<
"Couldn't find intersection with cut line.";
650 const QPointF &sp1,
const QPointF &sp2,
const QPointF &sp3,
655 QLineF edge2(p2, p3);
656 QLineF sEdge1(sp1, sp2);
659 QLineF::IntersectType type = edge2.intersects(sEdge1, &px);
660 if (type == QLineF::NoIntersection)
665 if (QLineF(p2, px).length() > width*
maxL)
671 QLineF edge1(p1, p2);
672 QLineF sEdge2(sp2, sp3);
674 type = edge1.intersects(sEdge2, &px);
675 if (type == QLineF::NoIntersection)
680 if (QLineF(p2, px).length() > width*
maxL)
691 const QPointF &sp1,
const QPointF &sp2,
const QPointF &sp3,
696 QLineF sEdge2(sp2, sp3);
699 QLineF fEdge(fp1, fp2);
702 QLineF sEdge1(sp1, sp2);
703 QLineF::IntersectType type = fEdge.intersects(sEdge1, &px);
704 if (type == QLineF::NoIntersection)
709 if (QLineF(p2, px).length() > width*
maxL)
715 type = fEdge.intersects(sEdge2, &px);
716 if (type == QLineF::NoIntersection)
721 if (QLineF(p2, px).length() > width*
maxL)
732 const QPointF &sp1,
const QPointF &sp2,
const QPointF &sp3,
737 QLineF sEdge1(sp1, sp2);
740 QLineF fEdge(fp2, fp3);
743 QLineF::IntersectType type = fEdge.intersects(sEdge1, &px);
744 if (type == QLineF::NoIntersection)
749 if (QLineF(p2, px).length() > width*
maxL)
755 QLineF sEdge2(sp2, sp3);
756 type = fEdge.intersects(sEdge2, &px);
757 if (type == QLineF::NoIntersection)
762 if (QLineF(p2, px).length() > width*
maxL)
773 const QPointF &sp1,
const QPointF &sp2,
const QPointF &sp3,
778 QLineF edge1(p2, p1);
779 edge1.setAngle(edge1.angle()-90);
782 QLineF::IntersectType type = edge1.intersects(QLineF(sp1, sp2), &px);
783 if (type == QLineF::NoIntersection)
788 if (QLineF(p2, px).length() > width*
maxL)
794 type = edge1.intersects(QLineF(sp2, sp3), &px);
795 if (type == QLineF::NoIntersection)
800 if (QLineF(p2, px).length() > width*
maxL)
811 const QPointF &sp1,
const QPointF &sp2,
const QPointF &sp3,
816 QLineF edge2(p2, p3);
817 edge2.setAngle(edge2.angle()+90);
820 QLineF::IntersectType type = edge2.intersects(QLineF(sp1, sp2), &px);
821 if (type == QLineF::NoIntersection)
826 if (QLineF(p2, px).length() > width*
maxL)
832 type = edge2.intersects(QLineF(sp2, sp3), &px);
833 if (type == QLineF::NoIntersection)
838 if (QLineF(p2, px).length() > width*
maxL)
878 QLineF pLine(p1, p2);
879 pLine.setAngle( pLine.angle() + angle );
880 pLine.setLength( width );
887 QLineF line1(p2, p1);
888 QLineF line2(p2, p3);
891 const qreal angle1 = line1.angleTo(line2);
892 const qreal angle2 = line2.angleTo(line1);
894 if (angle1 <= angle2)
897 bLine.setAngle(bLine.angle() + angle1/2.0);
902 bLine.setAngle(bLine.angle() + angle2/2.0);
911 const QLineF newB2 = b2.translated(-(b2.p1().x() - b1.p1().x()), -(b2.p1().y() - b1.p1().y()));
913 qreal angle1 = newB2.angleTo(b1);
919 qreal angle2 = b1.angleTo(newB2);
925 if (angle1 <= angle2)
937 const QPointF &crossPoint)
940 sub1.append(crossPoint);
945 sub2.append(crossPoint);
949 if (sub1Sum < 0 && sub2Sum < 0)
969 const bool l1p1el2p1 = (line1.p1() == line2.p1());
970 const bool l1p2el2p2 = (line1.p2() == line2.p2());
971 const bool l1p1el2p2 = (line1.p1() == line2.p2());
972 const bool l1p2el2p1 = (line1.p2() == line2.p1());
974 if (l1p2el2p2 || l1p2el2p1)
979 else if (l1p1el2p1 || l1p1el2p2)
994 if (sub1.isEmpty() || sub2.isEmpty())
999 const QRectF sub1Rect = QPolygonF(sub1).boundingRect();
1000 const QRectF sub2Rect = QPolygonF(sub2).boundingRect();
1001 if (not sub1Rect.intersects(sub2Rect))
1006 QPainterPath sub1Path;
1007 sub1Path.setFillRule(Qt::WindingFill);
1008 sub1Path.moveTo(sub1.at(0));
1009 for (qint32 i = 1; i < sub1.count(); ++i)
1011 sub1Path.lineTo(sub1.at(i));
1013 sub1Path.lineTo(sub1.at(0));
1015 QPainterPath sub2Path;
1016 sub2Path.setFillRule(Qt::WindingFill);
1017 sub2Path.moveTo(sub2.at(0));
1018 for (qint32 i = 1; i < sub2.count(); ++i)
1020 sub2Path.lineTo(sub2.at(i));
1022 sub2Path.lineTo(sub2.at(0));
1024 if (not sub1Path.intersects(sub2Path))
1038 || startIndex < 0 || startIndex >= path.size()
1039 || endIndex < 0 || endIndex >= path.size()
1040 || startIndex == endIndex)
1046 int i = startIndex - 1;
1050 if (i >= path.size())
1054 subPath.append(path.at(i));
1055 }
while (i != endIndex);
1070 const qreal tmpWidth = 10;
static QVector< QPointF > AngleByFirstRightAngle(const QPointF &p1, const QPointF &p2, const QPointF &sp1, const QPointF &sp2, const QPointF &sp3, qreal width)
bool IsSeamAllowanceBuiltIn() const
bool IsSeamAllowance() const
bool isHideSeamLine() const
static bool isClockwise(const QVector< QPointF > &points)
void setFill(const QString &value)
static bool IsEkvPointOnLine(const QPointF &iPoint, const QPointF &prevPoint, const QPointF &nextPoint)
static QVector< QPointF > Equidistant(const QVector< VSAPoint > &points, qreal width)
static bool ParallelCrossPoint(const QLineF &line1, const QLineF &line2, QPointF &point)
static QVector< QPointF > AngleBySecondRightAngle(const QPointF &p2, const QPointF &p3, const QPointF &sp1, const QPointF &sp2, const QPointF &sp3, qreal width)
static QLineF createParallelLine(const VSAPoint &p1, const VSAPoint &p2, qreal width)
static bool Crossing(const QVector< QPointF > &sub1, const QVector< QPointF > &sub2)
static Q_DECL_CONSTEXPR qreal PointPosition(const QPointF &p, const QLineF &line)
static qreal sumTrapezoids(const QVector< QPointF > &points)
static QVector< QPointF > AngleByLength(const QPointF &p2, const QPointF &sp1, const QPointF &sp2, const QPointF &sp3, qreal width)
QSharedDataPointer< VAbstractPieceData > d
void SetSAWidth(qreal value)
static QVector< QPointF > EkvPoint(const VSAPoint &p1Line1, const VSAPoint &p2Line1, const VSAPoint &p1Line2, const VSAPoint &p2Line2, qreal width)
EkvPoint return seam allowance points in place of intersection of two edges. Last points of two edges...
static QVector< QPointF > AngleBySecondSymmetry(const QPointF &p2, const QPointF &p3, const QPointF &sp1, const QPointF &sp2, const QPointF &sp3, qreal width)
void SetForbidFlipping(bool value)
static qreal AngleBetweenBisectors(const QLineF &b1, const QLineF &b2)
static QPointF SingleParallelPoint(const QPointF &p1, const QPointF &p2, qreal angle, qreal width)
void setColor(const QString &value)
static qreal MaxLocalSA(const VSAPoint &p, qreal width)
static QVector< QPointF > SubPath(const QVector< QPointF > &path, int startIndex, int endIndex)
void setHideSeamLine(bool value)
void SetName(const QString &value)
void SetSeamAllowanceBuiltIn(bool value)
void Swap(VAbstractPiece &piece) Q_DECL_NOTHROW
void SetSeamAllowance(bool value)
virtual ~VAbstractPiece()
static QVector< QPointF > CheckLoops(const QVector< QPointF > &points)
CheckLoops seek and delete loops in equidistant.
static QVector< QPointF > AngleByIntersection(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &sp1, const QPointF &sp2, const QPointF &sp3, qreal width)
static QVector< QPointF > AngleByFirstSymmetry(const QPointF &p1, const QPointF &p2, const QPointF &sp1, const QPointF &sp2, const QPointF &sp3, qreal width)
static QVector< T > CorrectEquidistantPoints(const QVector< T > &points, bool removeFirstAndLast=true)
CorrectEquidistantPoints clear equivalent points and remove point on line from equdistant.
bool IsForbidFlipping() const
static QLineF BisectorLine(const QPointF &p1, const QPointF &p2, const QPointF &p3)
static bool CheckIntersection(const QVector< QPointF > &points, int i, int iNext, int j, int jNext, const QPointF &crossPoint)
VAbstractPiece & operator=(const VAbstractPiece &piece)
static bool IsPointOnLineviaPDP(const QPointF &t, const QPointF &p1, const QPointF &p2)
IsPointOnLineviaPDP use the perp dot product (PDP) way.
static const double accuracyPointOnLine
static QPointF FlipPF(const QLineF &axis, const QPointF &point)
The VSAPoint class seam allowance point.
Q_DECL_CONSTEXPR PieceNodeAngle GetAngleType() const
Q_DECL_CONSTEXPR qreal GetSABefore() const
Q_DECL_CONSTEXPR qreal GetSAAfter() const
static Q_REQUIRED_RESULT bool VFuzzyComparePossibleNulls(double p1, double p2)