Horizontal piece flipping.

This commit is contained in:
Roman Telezhynskyi 2023-11-29 16:40:36 +02:00
parent a7073dbeae
commit e9565b3e75
19 changed files with 339 additions and 74 deletions

View file

@ -59,6 +59,7 @@
- New tools: Arc start point, Arc end point.
- Optimize U-notch shape.
- New feature. Boundary together with notches.
- Puzzle app. Horizontal piece flipping.
# Valentina 0.7.52 September 12, 2022
- Fix crash when default locale is ru.

View file

@ -144,7 +144,7 @@ VPPiece::VPPiece(const VLayoutPiece &layoutPiece)
if (IsForceFlipping())
{
Flip();
FlipVertically();
}
}
@ -200,7 +200,8 @@ void VPPiece::ClearTransformations()
const QPointF offset = MappedDetailBoundingRect().topLeft();
Translate(-offset.x(), -offset.y());
SetMirror(false);
SetVerticallyFlipped(false);
SetHorizontallyFlipped(false);
}
//---------------------------------------------------------------------------------------------------------------------
@ -287,7 +288,7 @@ void VPPiece::SetGrainline(const VPieceGrainline &grainline)
}
//---------------------------------------------------------------------------------------------------------------------
void VPPiece::Flip()
void VPPiece::FlipVertically()
{
QTransform pieceMatrix = GetMatrix();
QPointF center = pieceMatrix.map(DetailBoundingRect().center());
@ -299,7 +300,23 @@ void VPPiece::Flip()
pieceMatrix *= m;
SetMatrix(pieceMatrix);
SetMirror(!IsMirror());
SetVerticallyFlipped(!IsVerticallyFlipped());
}
//---------------------------------------------------------------------------------------------------------------------
void VPPiece::FlipHorizontally()
{
QTransform pieceMatrix = GetMatrix();
QPointF center = pieceMatrix.map(DetailBoundingRect().center());
QTransform m;
m.translate(0, center.y());
m.scale(1, -1);
m.translate(0, -center.y());
pieceMatrix *= m;
SetMatrix(pieceMatrix);
SetHorizontallyFlipped(!IsHorizontallyFlipped());
}
//---------------------------------------------------------------------------------------------------------------------

View file

@ -97,9 +97,10 @@ public:
void SetGrainline(const VPieceGrainline &grainline);
/**
* @brief Flip horizontally mirror around center of bounding rect
* @brief Flip verticvally mirror around center of bounding rect
*/
void Flip();
void FlipVertically();
void FlipHorizontally();
auto OutOfBound() const -> bool;
void SetOutOfBound(bool newOutOfBound);

View file

@ -72,7 +72,7 @@ namespace
{
//---------------------------------------------------------------------------------------------------------------------
inline auto LineMatrix(const VPPiecePtr &piece, const QPointF &topLeft, qreal angle, const QPointF &linePos,
int maxLineWidth) -> QTransform
int maxLineWidth, qreal maxLabelHeight) -> QTransform
{
if (piece.isNull())
{
@ -82,11 +82,21 @@ inline auto LineMatrix(const VPPiecePtr &piece, const QPointF &topLeft, qreal an
QTransform labelMatrix;
labelMatrix.translate(topLeft.x(), topLeft.y());
if (piece->IsMirror())
if (piece->IsVerticallyFlipped() || piece->IsHorizontallyFlipped())
{
labelMatrix.scale(-1, 1);
labelMatrix.rotate(-angle);
labelMatrix.translate(-maxLineWidth, 0);
if (piece->IsVerticallyFlipped())
{
labelMatrix.scale(-1, 1);
labelMatrix.rotate(-angle);
labelMatrix.translate(-maxLineWidth, 0);
}
if (piece->IsHorizontallyFlipped())
{
labelMatrix.scale(1, -1);
labelMatrix.rotate(-angle);
labelMatrix.translate(0, -maxLabelHeight);
}
}
else
{
@ -169,6 +179,72 @@ inline auto SelectionBrush() -> QBrush
{
return {QColor(255, 160, 160, 60)};
}
//---------------------------------------------------------------------------------------------------------------------
auto LabelHeightSVGFont(const VPPiecePtr &piece, const QVector<TextLine> &labelLines, const VSvgFont &svgFont,
const VSvgFontDatabase *db, qreal penWidth, qreal dH, int spacing) -> qreal
{
qreal labelHeight = 0;
if (piece->IsHorizontallyFlipped())
{
for (int i = 0; i < labelLines.size(); ++i)
{
const VSvgFont fnt = LineFont(labelLines.at(i), svgFont);
VSvgFontEngine engine = db->FontEngine(fnt);
const qreal lineHeight = engine.FontHeight() + penWidth;
if (labelHeight + lineHeight > dH)
{
break;
}
if (i < labelLines.size() - 1)
{
labelHeight += lineHeight + spacing;
}
else
{
labelHeight += lineHeight;
}
}
}
return labelHeight;
}
//---------------------------------------------------------------------------------------------------------------------
auto LabelHeightOutlineFont(const VPPiecePtr &piece, const QVector<TextLine> &labelLines, const QFont &font,
bool textAsPaths, qreal penWidth, qreal dH, int spacing) -> qreal
{
qreal labelHeight = 0;
if (piece->IsHorizontallyFlipped())
{
for (int i = 0; i < labelLines.size(); ++i)
{
const QFont fnt = LineFont(labelLines.at(i), font);
QFontMetrics fm(fnt);
const qreal lineHeight = textAsPaths ? fm.height() + penWidth : fm.height();
if (labelHeight + lineHeight > dH)
{
break;
}
if (i < labelLines.size() - 1)
{
labelHeight += lineHeight + spacing;
}
else
{
labelHeight += lineHeight;
}
}
}
return labelHeight;
}
} // namespace
//---------------------------------------------------------------------------------------------------------------------
@ -441,6 +517,8 @@ void VPGraphicsPiece::InitPieceLabelSVGFont(const QVector<QPointF> &labelShape,
const QVector<TextLine> labelLines = tm.GetLabelSourceLines(qFloor(dW), svgFont, penWidth);
const qreal labelHeight = LabelHeightSVGFont(piece, labelLines, svgFont, db, penWidth, dH, tm.GetSpacing());
for (const auto &tl : labelLines)
{
const VSvgFont fnt = LineFont(tl, svgFont);
@ -454,7 +532,8 @@ void VPGraphicsPiece::InitPieceLabelSVGFont(const QVector<QPointF> &labelShape,
const QString qsText = tl.m_qsText;
const qreal dX = LineAlign(tl, qsText, engine, dW, penWidth);
// set up the rotation around top-left corner matrix
const QTransform lineMatrix = LineMatrix(piece, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth);
const QTransform lineMatrix =
LineMatrix(piece, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth, labelHeight);
auto *item = new QGraphicsPathItem(this);
item->setPath(engine.DrawPath(QPointF(), qsText));
@ -508,6 +587,9 @@ void VPGraphicsPiece::InitPieceLabelOutlineFont(const QVector<QPointF> &labelSha
const QVector<TextLine> labelLines = tm.GetLabelSourceLines(qFloor(dW), tm.GetFont());
const qreal labelHeight =
LabelHeightOutlineFont(piece, labelLines, tm.GetFont(), textAsPaths, penWidth, dH, tm.GetSpacing());
for (const auto &tl : labelLines)
{
const QFont fnt = LineFont(tl, tm.GetFont());
@ -528,7 +610,8 @@ void VPGraphicsPiece::InitPieceLabelOutlineFont(const QVector<QPointF> &labelSha
const QString qsText = tl.m_qsText;
const qreal dX = LineAlign(tl, qsText, fm, dW);
// set up the rotation around top-left corner matrix
const QTransform lineMatrix = LineMatrix(piece, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth);
const QTransform lineMatrix =
LineMatrix(piece, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth, labelHeight);
if (textAsPaths)
{

View file

@ -782,7 +782,7 @@ void VPMainWindow::InitPropertyTabCurrentPiece()
}
});
connect(ui->checkBoxCurrentPieceMirrorPiece, &QCheckBox::toggled, this,
connect(ui->checkBoxCurrentPieceVerticallyFlipped, &QCheckBox::toggled, this,
[this](bool checked)
{
QList<VPPiecePtr> selectedPieces = SelectedPieces();
@ -791,9 +791,28 @@ void VPMainWindow::InitPropertyTabCurrentPiece()
const VPPiecePtr &selectedPiece = selectedPieces.constFirst();
if (not selectedPiece.isNull())
{
if (selectedPiece->IsMirror() != checked)
if (selectedPiece->IsVerticallyFlipped() != checked)
{
selectedPiece->Flip();
selectedPiece->FlipVertically();
LayoutWasSaved(false);
emit m_layout->PieceTransformationChanged(selectedPiece);
}
}
}
});
connect(ui->checkBoxCurrentPieceHorizontallyFlipped, &QCheckBox::toggled, this,
[this](bool checked)
{
QList<VPPiecePtr> selectedPieces = SelectedPieces();
if (selectedPieces.size() == 1)
{
const VPPiecePtr &selectedPiece = selectedPieces.constFirst();
if (not selectedPiece.isNull())
{
if (selectedPiece->IsHorizontallyFlipped() != checked)
{
selectedPiece->FlipHorizontally();
LayoutWasSaved(false);
emit m_layout->PieceTransformationChanged(selectedPiece);
}
@ -1287,10 +1306,11 @@ void VPMainWindow::SetPropertyTabCurrentPieceData()
SetLineEditValue(ui->lineEditCurrentPieceGradationId, selectedPiece->GetGradationId());
SetCheckBoxValue(ui->checkBoxCurrentPieceShowSeamline, not selectedPiece->IsHideMainPath());
SetCheckBoxValue(ui->checkBoxCurrentPieceMirrorPiece, selectedPiece->IsMirror());
SetCheckBoxValue(ui->checkBoxCurrentPieceVerticallyFlipped, selectedPiece->IsVerticallyFlipped());
SetCheckBoxValue(ui->checkBoxCurrentPieceHorizontallyFlipped, selectedPiece->IsHorizontallyFlipped());
const bool disableFlipping = selectedPiece->IsForbidFlipping() || selectedPiece->IsForceFlipping();
ui->checkBoxCurrentPieceMirrorPiece->setDisabled(disableFlipping);
ui->checkBoxCurrentPieceVerticallyFlipped->setDisabled(disableFlipping);
if (not ui->checkBoxRelativeTranslation->isChecked())
{

View file

@ -279,8 +279,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>392</width>
<height>700</height>
<width>378</width>
<height>707</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_23">
@ -624,9 +624,16 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QCheckBox" name="checkBoxCurrentPieceMirrorPiece">
<widget class="QCheckBox" name="checkBoxCurrentPieceVerticallyFlipped">
<property name="text">
<string>Mirror piece</string>
<string>Vertically flipped</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCurrentPieceHorizontallyFlipped">
<property name="text">
<string>Horizontally flipped</string>
</property>
</widget>
</item>
@ -2416,7 +2423,7 @@
<tabstop>lineEditCurrentPieceName</tabstop>
<tabstop>plainTextEditCurrentPieceUUID</tabstop>
<tabstop>checkBoxCurrentPieceShowSeamline</tabstop>
<tabstop>checkBoxCurrentPieceMirrorPiece</tabstop>
<tabstop>checkBoxCurrentPieceVerticallyFlipped</tabstop>
<tabstop>doubleSpinBoxCurrentPieceAngle</tabstop>
<tabstop>doubleSpinBoxCurrentPieceBoxPositionX</tabstop>
<tabstop>doubleSpinBoxCurrentPieceBoxPositionY</tabstop>
@ -2434,8 +2441,8 @@
</resources>
<connections/>
<buttongroups>
<buttongroup name="buttonGroupTileOrientation"/>
<buttongroup name="buttonGroupSheetOrientation"/>
<buttongroup name="buttonGroupRotationDirection"/>
<buttongroup name="buttonGroupSheetOrientation"/>
<buttongroup name="buttonGroupTileOrientation"/>
</buttongroups>
</ui>

View file

@ -511,7 +511,8 @@ void VPLayoutFileReader::ReadPiece(const VPPiecePtr &piece)
piece->SetXScale(ReadAttributeDouble(attribs, ML::AttrXScale, QChar('1')));
piece->SetYScale(ReadAttributeDouble(attribs, ML::AttrYScale, QChar('1')));
piece->SetZValue(ReadAttributeDouble(attribs, ML::AttrZValue, QChar('1')));
piece->SetMirror(ReadAttributeBool(attribs, ML::AttrMirrored, falseStr));
piece->SetVerticallyFlipped(ReadAttributeBool(attribs, ML::AttrVerticallyFlipped, falseStr));
piece->SetHorizontallyFlipped(ReadAttributeBool(attribs, ML::AttrHorizontallyFlipped, falseStr));
piece->SetForbidFlipping(ReadAttributeBool(attribs, ML::AttrForbidFlipping, falseStr));
piece->SetForceFlipping(ReadAttributeBool(attribs, ML::AttrForceFlipping, falseStr));
piece->SetFollowGrainline(ReadAttributeBool(attribs, ML::AttrFollowGrainline, falseStr));

View file

@ -260,8 +260,10 @@ void VPLayoutFileWriter::WritePiece(const VPPiecePtr &piece)
writeStartElement(ML::TagPiece);
SetAttribute(ML::AttrUID, piece->GetUUID().toString());
SetAttribute(ML::AttrName, piece->GetName());
SetAttributeOrRemoveIf<bool>(ML::AttrMirrored, piece->IsMirror(),
[](bool mirrored) noexcept { return not mirrored; });
SetAttributeOrRemoveIf<bool>(ML::AttrVerticallyFlipped, piece->IsVerticallyFlipped(),
[](bool flipped) noexcept { return not flipped; });
SetAttributeOrRemoveIf<bool>(ML::AttrHorizontallyFlipped, piece->IsHorizontallyFlipped(),
[](bool flipped) noexcept { return not flipped; });
SetAttributeOrRemoveIf<bool>(ML::AttrForbidFlipping, piece->IsForbidFlipping(),
[](bool forbid) noexcept { return not forbid; });
SetAttributeOrRemoveIf<bool>(ML::AttrForceFlipping, piece->IsForceFlipping(),

View file

@ -84,7 +84,8 @@ const QString AttrLength = QStringLiteral("length");
const QString AttrFollowGrainline = QStringLiteral("followGrainline"); // NOLINT(cert-err58-cpp)
const QString AttrBoundaryTogetherWithNotches = QStringLiteral("boundaryTogetherWithNotches"); // NOLINT(cert-err58-cpp)
const QString AttrUID = QStringLiteral("uid"); // NOLINT(cert-err58-cpp)
const QString AttrMirrored = QStringLiteral("mirrored"); // NOLINT(cert-err58-cpp)
const QString AttrVerticallyFlipped = QStringLiteral("verticallyFlipped"); // NOLINT(cert-err58-cpp)
const QString AttrHorizontallyFlipped = QStringLiteral("horizontallyFlipped"); // NOLINT(cert-err58-cpp)
const QString AttrForbidFlipping = QStringLiteral("forbidFlipping"); // NOLINT(cert-err58-cpp)
const QString AttrForceFlipping = QStringLiteral("forceFlipping"); // NOLINT(cert-err58-cpp)
const QString AttrSewLineOnDrawing = QStringLiteral("sewLineOnDrawing"); // NOLINT(cert-err58-cpp)

View file

@ -83,7 +83,8 @@ extern const QString AttrLength;
extern const QString AttrFollowGrainline;
extern const QString AttrBoundaryTogetherWithNotches;
extern const QString AttrUID;
extern const QString AttrMirrored;
extern const QString AttrVerticallyFlipped;
extern const QString AttrHorizontallyFlipped;
extern const QString AttrForbidFlipping;
extern const QString AttrForceFlipping;
extern const QString AttrSewLineOnDrawing;

View file

@ -221,7 +221,8 @@
</xs:sequence>
<xs:attribute name="uid" type="uuid" use="required"/>
<xs:attribute type="xs:string" name="name"/>
<xs:attribute type="xs:boolean" name="mirrored"/>
<xs:attribute type="xs:boolean" name="verticallyFlipped"/>
<xs:attribute type="xs:boolean" name="horizontallyFlipped"/>
<xs:attribute type="xs:boolean" name="forbidFlipping"/>
<xs:attribute type="xs:boolean" name="forceFlipping"/>
<xs:attribute type="xs:boolean" name="followGrainline"/>
@ -419,7 +420,8 @@
</xs:sequence>
<xs:attribute name="uid" type="uuid" use="required"/>
<xs:attribute type="xs:string" name="name"/>
<xs:attribute type="xs:boolean" name="mirrored"/>
<xs:attribute type="xs:boolean" name="verticallyFlipped"/>
<xs:attribute type="xs:boolean" name="horizontallyFlipped"/>
<xs:attribute type="xs:boolean" name="forbidFlipping"/>
<xs:attribute type="xs:boolean" name="forceFlipping"/>
<xs:attribute type="xs:boolean" name="followGrainline"/>

View file

@ -58,21 +58,23 @@ QT_WARNING_DISABLE_CLANG("-Wunused-member-function")
// The list of all string we use for conversion
// Better to use global variables because repeating QStringLiteral blows up code size
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strSeamLineTag, ("seamLine"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strSeamAllowanceTag, ("seamAllowance"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strInternalPathTag, ("internalPath"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strMarkerTag, ("marker"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strPointTag, ("point"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strPieceTag, ("piece"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strGrainlineTag, ("grainline"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrX, ("x"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrY, ("y"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrTurnPoint, ("turnPoint"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrCurvePoint, ("curvePoint"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrId, ("id"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrUId, ("uid"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrAngle, ("angle"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrArrowDirection, ("arrowDirection"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strSeamLineTag, ("seamLine"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strSeamAllowanceTag, ("seamAllowance"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strInternalPathTag, ("internalPath"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strMarkerTag, ("marker"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strPointTag, ("point"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strPieceTag, ("piece"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strGrainlineTag, ("grainline"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrX, ("x"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrY, ("y"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrTurnPoint, ("turnPoint"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrCurvePoint, ("curvePoint"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrId, ("id"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrUId, ("uid"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrAngle, ("angle"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrArrowDirection, ("arrowDirection"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrMirrored, ("mirrored"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrVerticallyFlipped, ("verticallyFlipped"_L1)) // NOLINT
QT_WARNING_POP
@ -380,6 +382,24 @@ void VLayoutConverter::ConvertPiecesToV0_1_5()
}
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutConverter::ConvertPiecesToV0_1_7()
{
// TODO. Delete if minimal supported version is 0.1.7
Q_STATIC_ASSERT_X(VLayoutConverter::LayoutMinVer < FormatVersion(0, 1, 7), "Time to refactor the code.");
QDomNodeList pieceTags = elementsByTagName(*strPieceTag);
for (int i = 0; i < pieceTags.size(); ++i)
{
QDomElement node = pieceTags.at(i).toElement();
if (node.isElement() && node.hasAttribute(*strAttrMirrored))
{
node.setAttribute(*strAttrVerticallyFlipped, node.attribute(*strAttrMirrored));
node.removeAttribute(*strAttrMirrored);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutConverter::ToV0_1_3()
{
@ -407,6 +427,7 @@ void VLayoutConverter::ToV0_1_7()
// TODO. Delete if minimal supported version is 0.1.7
Q_STATIC_ASSERT_X(VLayoutConverter::LayoutMinVer < FormatVersion(0, 1, 7), "Time to refactor the code.");
ConvertPiecesToV0_1_7();
SetVersion(QStringLiteral("0.1.7"));
Save();
}

View file

@ -72,6 +72,8 @@ protected:
void ConvertPiecesToV0_1_5();
void ConvertPiecesToV0_1_7();
void ToV0_1_3();
void ToV0_1_5();
void ToV0_1_7();

View file

@ -162,16 +162,26 @@ inline auto LineAlign(const TextLine &tl, const QString &text, const QFontMetric
//---------------------------------------------------------------------------------------------------------------------
auto LineMatrix(const VLayoutPiece &piece, const QPointF &topLeft, qreal angle, const QPointF &linePos,
int maxLineWidth) -> QTransform
int maxLineWidth, qreal maxLabelHeight) -> QTransform
{
QTransform labelMatrix;
labelMatrix.translate(topLeft.x(), topLeft.y());
if (piece.IsMirror())
if (piece.IsVerticallyFlipped() || piece.IsHorizontallyFlipped())
{
labelMatrix.scale(-1, 1);
labelMatrix.rotate(-angle);
labelMatrix.translate(-maxLineWidth, 0);
if (piece.IsVerticallyFlipped())
{
labelMatrix.scale(-1, 1);
labelMatrix.rotate(-angle);
labelMatrix.translate(-maxLineWidth, 0);
}
if (piece.IsHorizontallyFlipped())
{
labelMatrix.scale(1, -1);
labelMatrix.rotate(-angle);
labelMatrix.translate(0, -maxLabelHeight);
}
}
else
{
@ -220,6 +230,72 @@ auto NextPattern(int patternIndex, const QVector<int> &pattern) -> int
{
return (patternIndex + 2) % static_cast<int>(pattern.size());
}
//---------------------------------------------------------------------------------------------------------------------
auto LabelHeightSVGFont(const VLayoutPiece &detail, const QVector<TextLine> &labelLines, const VSvgFont &svgFont,
const VSvgFontDatabase *db, qreal penWidth, qreal dH, int spacing) -> qreal
{
qreal labelHeight = 0;
if (detail.IsHorizontallyFlipped())
{
for (int i = 0; i < labelLines.size(); ++i)
{
const VSvgFont fnt = LineFont(labelLines.at(i), svgFont);
VSvgFontEngine engine = db->FontEngine(fnt);
const qreal lineHeight = engine.FontHeight() + penWidth;
if (labelHeight + lineHeight > dH)
{
break;
}
if (i < labelLines.size() - 1)
{
labelHeight += lineHeight + spacing;
}
else
{
labelHeight += lineHeight;
}
}
}
return labelHeight;
}
//---------------------------------------------------------------------------------------------------------------------
auto LabelHeightOutlineFont(const VLayoutPiece &detail, const QVector<TextLine> &labelLines, const QFont &font,
qreal penWidth, qreal dH, int spacing) -> qreal
{
qreal labelHeight = 0;
if (detail.IsHorizontallyFlipped())
{
for (int i = 0; i < labelLines.size(); ++i)
{
const QFont fnt = LineFont(labelLines.at(i), font);
QFontMetrics fm(fnt);
const qreal lineHeight = fm.height() + penWidth;
if (labelHeight + lineHeight > dH)
{
break;
}
if (i < labelLines.size() - 1)
{
labelHeight += lineHeight + spacing;
}
else
{
labelHeight += lineHeight;
}
}
}
return labelHeight;
}
} // namespace
//---------------------------------------------------------------------------------------------------------------------
@ -475,7 +551,8 @@ void VHPGLEngine::PlotInternalPaths(QTextStream &out, const VLayoutPiece &detail
QVector<VLayoutPiecePath> internalPaths = detail.GetInternalPaths();
for (const auto &path : internalPaths)
{
QVector<VLayoutPoint> points = VLayoutPiece::MapVector(path.Points(), detail.GetMatrix(), detail.IsMirror());
QVector<VLayoutPoint> points = VLayoutPiece::MapVector(
path.Points(), detail.GetMatrix(), detail.IsVerticallyFlipped() || detail.IsHorizontallyFlipped());
PlotPath(out, CastToPoint(ConvertPath(points)), path.PenStyle());
}
}
@ -579,6 +656,8 @@ void VHPGLEngine::PlotLabelSVGFont(QTextStream &out, const VLayoutPiece &detail,
const QVector<TextLine> labelLines = tm.GetLabelSourceLines(qFloor(dW), svgFont, m_penWidthPx);
const qreal labelHeight = LabelHeightSVGFont(detail, labelLines, svgFont, db, m_penWidthPx, dH, tm.GetSpacing());
for (const auto &tl : labelLines)
{
const VSvgFont fnt = LineFont(tl, svgFont);
@ -592,7 +671,8 @@ void VHPGLEngine::PlotLabelSVGFont(QTextStream &out, const VLayoutPiece &detail,
const QString qsText = tl.m_qsText;
const qreal dX = LineAlign(tl, qsText, engine, dW, m_penWidthPx);
// set up the rotation around top-left corner matrix
const QTransform lineMatrix = LineMatrix(detail, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth);
const QTransform lineMatrix =
LineMatrix(detail, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth, labelHeight);
QPainterPath path = lineMatrix.map(engine.DrawPath(QPointF(), qsText));
PlotPainterPath(out, path, Qt::SolidLine);
@ -626,6 +706,9 @@ void VHPGLEngine::PlotLabelOutlineFont(QTextStream &out, const VLayoutPiece &det
const QVector<TextLine> labelLines = tm.GetLabelSourceLines(qFloor(dW), tm.GetFont());
const qreal labelHeight =
LabelHeightOutlineFont(detail, labelLines, tm.GetFont(), m_penWidthPx, dH, tm.GetSpacing());
for (const auto &tl : labelLines)
{
const QFont fnt = LineFont(tl, tm.GetFont());
@ -646,7 +729,8 @@ void VHPGLEngine::PlotLabelOutlineFont(QTextStream &out, const VLayoutPiece &det
const QString qsText = tl.m_qsText;
const qreal dX = LineAlign(tl, qsText, fm, dW);
// set up the rotation around top-left corner matrix
const QTransform lineMatrix = LineMatrix(detail, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth);
const QTransform lineMatrix =
LineMatrix(detail, labelShape.at(0), angle, QPointF(dX, dY), maxLineWidth, labelHeight);
QPainterPath path;

View file

@ -284,7 +284,7 @@ auto VLayoutPaper::SaveResult(const VBestSquare &bestResult, const VLayoutPiece
{
VLayoutPiece workDetail = detail;
workDetail.SetMatrix(bestResult.Matrix()); // Don't forget set matrix
workDetail.SetMirror(bestResult.Mirror());
workDetail.SetVerticallyFlipped(bestResult.Mirror());
if (d->saveLength)
{

View file

@ -667,7 +667,7 @@ template <> auto VLayoutPiece::Map<VLayoutPoint>(QVector<VLayoutPoint> points) c
point.ry() = p.y();
return point;
});
if (d->m_mirror)
if (d->m_verticallyFlipped || d->m_horizontallyFlipped)
{
std::reverse(points.begin(), points.end());
}
@ -1087,7 +1087,7 @@ void VLayoutPiece::Mirror(const QLineF &edge)
m.translate(-p2.x(), -p2.y());
d->m_matrix *= m;
d->m_mirror = !d->m_mirror;
d->m_verticallyFlipped = !d->m_verticallyFlipped;
}
//---------------------------------------------------------------------------------------------------------------------
@ -1096,7 +1096,7 @@ void VLayoutPiece::Mirror()
QTransform m;
m.scale(-1, 1);
d->m_matrix *= m;
d->m_mirror = !d->m_mirror;
d->m_verticallyFlipped = !d->m_verticallyFlipped;
}
//---------------------------------------------------------------------------------------------------------------------
@ -1607,7 +1607,7 @@ void VLayoutPiece::LabelStringsSVGFont(QGraphicsItem *parent, const QVector<QPoi
// set up the rotation around top-left corner matrix
QTransform labelMatrix;
labelMatrix.translate(labelShape.at(0).x(), labelShape.at(0).y());
if (d->m_mirror)
if (d->m_verticallyFlipped)
{
labelMatrix.scale(-1, 1);
labelMatrix.rotate(-angle);
@ -1704,7 +1704,7 @@ void VLayoutPiece::LabelStringsOutlineFont(QGraphicsItem *parent, const QVector<
// set up the rotation around top-left corner matrix
QTransform labelMatrix;
labelMatrix.translate(labelShape.at(0).x(), labelShape.at(0).y());
if (d->m_mirror)
if (d->m_verticallyFlipped)
{
labelMatrix.scale(-1, 1);
labelMatrix.rotate(-angle);
@ -1844,15 +1844,27 @@ auto VLayoutPiece::GetMainPathItem() const -> QGraphicsPathItem *
}
//---------------------------------------------------------------------------------------------------------------------
auto VLayoutPiece::IsMirror() const -> bool
auto VLayoutPiece::IsVerticallyFlipped() const -> bool
{
return d->m_mirror;
return d->m_verticallyFlipped;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutPiece::SetMirror(bool value)
void VLayoutPiece::SetVerticallyFlipped(bool value)
{
d->m_mirror = value;
d->m_verticallyFlipped = value;
}
//---------------------------------------------------------------------------------------------------------------------
auto VLayoutPiece::IsHorizontallyFlipped() const -> bool
{
return d->m_horizontallyFlipped;
}
//---------------------------------------------------------------------------------------------------------------------
void VLayoutPiece::SetHorizontallyFlipped(bool value)
{
d->m_horizontallyFlipped = value;
}
//---------------------------------------------------------------------------------------------------------------------
@ -1911,7 +1923,7 @@ auto VLayoutPiece::Edge(const QVector<QPointF> &path, int i) const -> QLineF
i2 = 0;
}
if (d->m_mirror)
if (d->m_verticallyFlipped || d->m_horizontallyFlipped)
{
QVector<QPointF> newPath = Map(path);
return {newPath.at(i1), newPath.at(i2)};
@ -1940,7 +1952,7 @@ auto VLayoutPiece::EdgeByPoint(const QVector<QPointF> &path, const QPointF &p1)
//---------------------------------------------------------------------------------------------------------------------
template <class T> auto VLayoutPiece::Map(QVector<T> points) const -> QVector<T>
{
return MapVector(points, d->m_matrix, d->m_mirror);
return MapVector(points, d->m_matrix, d->m_verticallyFlipped || d->m_horizontallyFlipped);
}
//---------------------------------------------------------------------------------------------------------------------

View file

@ -156,8 +156,11 @@ public:
auto GetId() const -> vidtype;
void SetId(vidtype id);
auto IsMirror() const -> bool;
void SetMirror(bool value);
auto IsVerticallyFlipped() const -> bool;
void SetVerticallyFlipped(bool value);
auto IsHorizontallyFlipped() const -> bool;
void SetHorizontallyFlipped(bool value);
void SetGradationId(const QString &id);
auto GetGradationId() const -> QString;

View file

@ -83,7 +83,8 @@ public:
/** @brief layoutWidth value layout allowance width in pixels. */
qreal m_layoutWidth{0}; // NOLINT(misc-non-private-member-variables-in-classes)
bool m_mirror{false}; // NOLINT(misc-non-private-member-variables-in-classes)
bool m_verticallyFlipped{false}; // NOLINT(misc-non-private-member-variables-in-classes)
bool m_horizontallyFlipped{false}; // NOLINT(misc-non-private-member-variables-in-classes)
/** @brief detailLabel detail label rectangle */
QVector<QPointF> m_detailLabel{}; // NOLINT(misc-non-private-member-variables-in-classes)
@ -118,7 +119,7 @@ private:
Q_DISABLE_ASSIGN_MOVE(VLayoutPieceData) // NOLINT
static constexpr quint32 streamHeader{0x80D7D009}; // CRC-32Q string "VLayoutPieceData"
static constexpr quint16 classVersion{5};
static constexpr quint16 classVersion{6};
};
QT_WARNING_POP
@ -142,7 +143,7 @@ inline auto operator<<(QDataStream &dataStream, const VLayoutPieceData &piece) -
dataStream << piece.m_internalPaths;
dataStream << piece.m_matrix;
dataStream << piece.m_layoutWidth;
dataStream << piece.m_mirror;
dataStream << piece.m_verticallyFlipped;
dataStream << piece.m_detailLabel;
dataStream << piece.m_patternInfo;
dataStream << piece.m_placeLabels;
@ -155,6 +156,7 @@ inline auto operator<<(QDataStream &dataStream, const VLayoutPieceData &piece) -
dataStream << piece.m_xScale;
dataStream << piece.m_yScale;
dataStream << piece.m_grainline;
dataStream << piece.m_horizontallyFlipped;
return dataStream;
}
@ -211,7 +213,7 @@ inline auto operator>>(QDataStream &dataStream, VLayoutPieceData &piece) -> QDat
dataStream >> piece.m_internalPaths;
dataStream >> piece.m_matrix;
dataStream >> piece.m_layoutWidth;
dataStream >> piece.m_mirror;
dataStream >> piece.m_verticallyFlipped;
dataStream >> piece.m_detailLabel;
dataStream >> piece.m_patternInfo;
@ -268,6 +270,11 @@ inline auto operator>>(QDataStream &dataStream, VLayoutPieceData &piece) -> QDat
}
}
if (actualClassVersion >= 6)
{
dataStream >> piece.m_horizontallyFlipped;
}
return dataStream;
}

View file

@ -281,7 +281,7 @@ void VPosition::SaveCandidate(VBestSquare &bestResult, const VLayoutPiece &detai
data.globalI = globalI; // Edge of global contour
data.detJ = detJ; // Edge of detail
data.resMatrix = detail.GetMatrix(); // Matrix for rotation and translation detail
data.resMirror = detail.IsMirror();
data.resMirror = detail.IsVerticallyFlipped();
data.type = type;
data.depthPosition = depthPosition;
data.sidePosition = sidePosition;