Refactoring. Move drawing passmarks to separate class.

--HG--
branch : develop
This commit is contained in:
Roman Telezhynskyi 2019-05-08 15:19:03 +03:00
parent 012eef24f6
commit 3b51ccb31d
13 changed files with 1094 additions and 460 deletions

View file

@ -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;
}

View file

@ -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<VPlaceLabelItemData> d;

View file

@ -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
{

View file

@ -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<QPointF> &shape, qreal &dX,
qreal &dY);
static QVector<QPointF> CorrectPosition(const QRectF &parentBoundingRect, QVector<QPointF> points);

View file

@ -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);

View file

@ -0,0 +1,870 @@
/************************************************************************
**
** @file vpassmark.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @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
** <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#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<QPointF> &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<QPointF> 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<QPointF> &seamAllowance, const QPointF &notchBase, 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<QPointF> points = VAbstractCurve::CurveIntersectLine(seamAllowance, axis);
if (points.size() > 0)
{
if (points.size() == 1)
{
*notch = points.at(0);
fixed = true;
}
else
{
QMap<qreal, int> 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<QPointF> 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<QPointF> &seamAllowance)
{
QLineF testLine = line;
testLine.setLength(testLine.length()*10);
QVector<QPointF> intersections = VAbstractCurve::CurveIntersectLine(seamAllowance, testLine);
if (not intersections.isEmpty())
{
return QLineF(line.p1(), intersections.last());
}
return line;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QLineF> CreateTwoPassmarkLines(const QLineF &line, const QVector<QPointF> &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<QLineF> 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<QLineF> CreateThreePassmarkLines(const QLineF &line, const QVector<QPointF> &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<QLineF> 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<QLineF> 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<QLineF> lines;
lines.append(line);
lines.append(QLineF(p1, p2));
return lines;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QLineF> CreateVMarkPassmark(const QLineF &line)
{
QLineF l1 = line;
l1.setAngle(l1.angle() - 35);
QLineF l2 = line;
l2.setAngle(l2.angle() + 35);
QVector<QLineF> lines;
lines.append(l1);
lines.append(l2);
return lines;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QLineF> CreateVMark2Passmark(const QLineF &line, const QVector<QPointF> &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<QLineF> lines;
lines.append(FindIntersection(l1, seamAllowance));
lines.append(FindIntersection(l2, seamAllowance));
return lines;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QLineF> PointsToSegments(const QVector<QPointF> &points)
{
QVector<QLineF> 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<QLineF> CreateUMarkPassmark(const QLineF &line, const QVector<QPointF> &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<QPointF> 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<QLineF> CreateBoxMarkPassmark(const QLineF &line, const QVector<QPointF> &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<QPointF> 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<QLineF> CreatePassmarkLines(PassmarkLineType lineType, PassmarkAngleType angleType, const QLineF &line,
const QVector<QPointF> &seamAllowance)
{
QVector<QLineF> 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<QLineF> PassmarkBisector(PassmarkStatus seamPassmarkType, const VPiecePassmarkData &passmarkData,
const QPointF &seamPassmarkSAPoint, const QVector<QPointF> &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<QLineF>();
}
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<QLineF>();
}
edge1.setAngle(edge1.angle() + edge1.angleTo(edge2)/2.);
edge1.setLength(length);
return CreatePassmarkLines(passmarkData.passmarkLineType, passmarkData.passmarkAngleType, edge1, seamAllowance);
}
//---------------------------------------------------------------------------------------------------------------------
QPainterPath PassmarkToPath(const QVector<QLineF> &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<QLineF> VPassmark::FullPassmark(const VPiece &piece, const VContainer *data) const
{
if (m_null)
{
return QVector<QLineF>();
}
if (not piece.IsSeamAllowanceBuiltIn())
{
QVector<QLineF> 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<QLineF> VPassmark::SAPassmark(const VPiece &piece, const VContainer *data, PassmarkSide side) const
{
if (m_null)
{
return QVector<QLineF>();
}
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<QLineF>();
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QLineF> VPassmark::SAPassmark(const QVector<QPointF> &seamAllowance, PassmarkSide side) const
{
if (m_null)
{
return QVector<QLineF>();
}
// 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<QLineF> VPassmark::MakeSAPassmark(const QVector<QPointF> &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<QLineF>(); // 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<QLineF>(); // 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<QLineF> passmarksLines;
auto PassmarkIntersection = [&passmarksLines, this, seamAllowance]
(QLineF line, qreal width)
{
line.setLength(line.length()*100); // Hope 100 is enough
const QVector<QPointF> 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<QLineF> VPassmark::BuiltInSAPassmark(const VPiece &piece, const VContainer *data) const
{
if (m_null)
{
return QVector<QLineF>();
}
const QVector<QPointF> 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<QLineF>();
}
}
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<QLineF>();
}
}
QVector<QLineF> 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));
}

View file

@ -0,0 +1,96 @@
/************************************************************************
**
** @file vpassmark.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @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
** <https://bitbucket.org/dismine/valentina> 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 <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VPASSMARK_H
#define VPASSMARK_H
#include <QtGlobal>
#include <QMetaType>
#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<QLineF> FullPassmark(const VPiece& piece, const VContainer *data) const;
QVector<QLineF> SAPassmark(const VPiece& piece, const VContainer *data, PassmarkSide side) const;
QVector<QLineF> SAPassmark(const QVector<QPointF> &seamAllowance, PassmarkSide side) const;
QVector<QLineF> 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<QLineF> MakeSAPassmark(const QVector<QPointF> &seamAllowance, PassmarkSide side) const;
};
#endif // VPASSMARK_H

View file

@ -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

View file

@ -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<QPointF> VPiece::CuttingPathPoints(const VContainer *data) const
//---------------------------------------------------------------------------------------------------------------------
QVector<QLineF> VPiece::PassmarksLines(const VContainer *data) const
{
QVector<VPassmark> passmarks = Passmarks(data);
QVector<QLineF> lines;
for(auto &passmark : passmarks)
{
if (not passmark.IsNull())
{
lines += passmark.FullPassmark(*this, data);
}
}
return lines;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<VPassmark> VPiece::Passmarks(const VContainer *data) const
{
const QVector<VPieceNode> unitedPath = GetUnitedPath(data);
if (not IsSeamAllowance() || not IsPassmarksPossible(unitedPath))
{
return QVector<QLineF>();
return QVector<VPassmark>();
}
QVector<QLineF> passmarks;
QVector<VPassmark> passmarks;
for (int i = 0; i< unitedPath.size(); ++i)
{
@ -633,28 +650,6 @@ QVector<QLineF> VPiece::PassmarksLines(const VContainer *data) const
return passmarks;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<PlaceLabelImg> VPiece::PlaceLabelPoints(const VContainer *data) const
{
QVector<PlaceLabelImg> points;
for(auto placeLabel : d->m_placeLabels)
{
try
{
const auto label = data->GeometricObject<VPlaceLabelItem>(placeLabel);
if (label->IsVisible())
{
points.append(label->LabelShape());
}
}
catch (const VExceptionBadId &e)
{
qWarning() << e.ErrorMessage();
}
}
return points;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QPainterPath> 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<PlaceLabelImg> 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<VPlaceLabelItem>(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<VPieceNode> &path, int index,
return true;
}
//---------------------------------------------------------------------------------------------------------------------
PassmarkStatus VPiece::GetSeamPassmarkSAPoint(VPiecePassmarkData passmarkData, const QVector<QPointF> &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<QPointF> 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<VPieceNode> &path, int passmarkIndex) const
{
@ -1468,14 +1416,14 @@ bool VPiece::IsPassmarkVisible(const QVector<VPieceNode> &path, int passmarkInde
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QLineF> VPiece::CreatePassmark(const QVector<VPieceNode> &path, int previousIndex, int passmarkIndex,
int nextIndex, const VContainer *data) const
VPassmark VPiece::CreatePassmark(const QVector<VPieceNode> &path, int previousIndex, int passmarkIndex, int nextIndex,
const VContainer *data) const
{
SCASSERT(data != nullptr);
if (not IsPassmarkVisible(path, passmarkIndex))
{
return QVector<QLineF>();
return VPassmark();
}
VSAPoint passmarkSAPoint;
@ -1484,21 +1432,26 @@ QVector<QLineF> VPiece::CreatePassmark(const QVector<VPieceNode> &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<QLineF>();
return VPassmark();
}
VSAPoint previousSAPoint;
if (not GetPassmarkPreviousSAPoints(path, previousIndex, passmarkSAPoint, data, previousSAPoint, passmarkIndex))
{
// No check here because it will cover valid cases
return QVector<QLineF>(); // 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<QLineF>(); // Something wrong
return VPassmark(); // Something wrong
}
if (passmarkSAPoint.IsManualPasskmarkLength() && passmarkSAPoint.GetPasskmarkLength() <= 0)
{
return VPassmark();
}
VPiecePassmarkData passmarkData;
@ -1510,232 +1463,12 @@ QVector<QLineF> VPiece::CreatePassmark(const QVector<VPieceNode> &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<QPointF> mainPath = MainPathPoints(data);
if (passmarkSAPoint.IsManualPasskmarkLength() && passmarkSAPoint.GetPasskmarkLength() <= 0)
{
return QVector<QLineF>();
}
if (not IsSeamAllowanceBuiltIn())
{
// Because rollback cannot be calulated if passmark is not first point in main path we rotate it.
const QVector<QPointF> seamAllowance = SeamAllowancePointsWithRotation(data, passmarkIndex);
QVector<QLineF> 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<QLineF> VPiece::SAPassmark(const VPiecePassmarkData &passmarkData, const QVector<QPointF> &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<QLineF>(); // 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<QLineF>(); // 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<QLineF> passmarksLines;
auto PassmarkIntersection = [&passmarksLines, passmarkData, seamAllowance]
(QLineF line, qreal width)
{
line.setLength(line.length()*100); // Hope 100 is enough
const QVector<QPointF> 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<QLineF> VPiece::BuiltInSAPassmark(const VPiecePassmarkData &passmarkData,
const QVector<QPointF> &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<QLineF>();
}
}
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<QLineF>();
}
}
QVector<QLineF> 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<CustomSARecord> &records, quint32 id)
return -1;
}
//---------------------------------------------------------------------------------------------------------------------
QVector<QLineF> VPiece::PassmarkBisector(PassmarkStatus seamPassmarkType, const VPiecePassmarkData &passmarkData,
const QPointF &seamPassmarkSAPoint, const QVector<QPointF> &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<QLineF>();
}
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<QLineF>();
}
edge1.setAngle(edge1.angle() + edge1.angleTo(edge2)/2.);
edge1.setLength(length);
return CreatePassmarkLines(passmarkData.passmarkLineType, passmarkData.passmarkAngleType, edge1, seamAllowance);
}

View file

@ -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<QPointF> SeamAllowancePoints(const VContainer *data) const;
QVector<QPointF> CuttingPathPoints(const VContainer *data) const;
QVector<QLineF> PassmarksLines(const VContainer *data) const;
QVector<PlaceLabelImg> PlaceLabelPoints(const VContainer *data) const;
QVector<VPassmark> Passmarks(const VContainer *data) const;
QVector<QPainterPath> CurvesPainterPath(const VContainer *data) const;
@ -160,8 +135,6 @@ public:
QVector<VPieceNode> GetUnitedPath(const VContainer *data) const;
static QVector<QLineF> SAPassmark(const VPiecePassmarkData &passmarkData, const QVector<QPointF> &seamAllowance);
protected:
QVector<QPointF> SeamAllowancePointsWithRotation(const VContainer *data, int makeFirst) const;
private:
QSharedDataPointer<VPieceData> d;
@ -176,30 +149,13 @@ private:
const VContainer *data, VSAPoint &point, int passmarkIndex) const;
bool GetPassmarkNextSAPoints(const QVector<VPieceNode> &path, int index, const VSAPoint &passmarkSAPoint,
const VContainer *data, VSAPoint &point, int passmarkIndex) const;
static PassmarkStatus GetSeamPassmarkSAPoint(VPiecePassmarkData passmarkData,
const QVector<QPointF> &seamAllowance, QPointF &point);
bool IsPassmarkVisible(const QVector<VPieceNode> &path, int passmarkIndex) const;
QVector<QLineF> CreatePassmark(const QVector<VPieceNode> &path, int previousIndex, int passmarkIndex, int nextIndex,
const VContainer *data) const;
QVector<QLineF> BuiltInSAPassmark(const VPiecePassmarkData &passmarkData, const QVector<QPointF> &mainPath) const;
static QVector<QLineF> PassmarkBisector(PassmarkStatus seamPassmarkType, const VPiecePassmarkData &passmarkData,
const QPointF &seamPassmarkSAPoint, const QVector<QPointF>& seamAllowance);
VPassmark CreatePassmark(const QVector<VPieceNode> &path, int previousIndex, int passmarkIndex, int nextIndex,
const VContainer *data) const;
static int IsCSAStart(const QVector<CustomSARecord> &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);

View file

@ -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()
{

View file

@ -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();

View file

@ -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<QPointF>, seamAllowance);
QFETCH(QVector<QLineF>, expectedResult);
Comparison(VPiece::SAPassmark(passmarkData, seamAllowance), expectedResult);
VPassmark passmark(passmarkData);
Comparison(passmark.SAPassmark(seamAllowance, PassmarkSide::All), expectedResult);
}