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. - New tools: Arc start point, Arc end point.
- Optimize U-notch shape. - Optimize U-notch shape.
- New feature. Boundary together with notches. - New feature. Boundary together with notches.
- Puzzle app. Horizontal piece flipping.
# Valentina 0.7.52 September 12, 2022 # Valentina 0.7.52 September 12, 2022
- Fix crash when default locale is ru. - Fix crash when default locale is ru.

View File

@ -144,7 +144,7 @@ VPPiece::VPPiece(const VLayoutPiece &layoutPiece)
if (IsForceFlipping()) if (IsForceFlipping())
{ {
Flip(); FlipVertically();
} }
} }
@ -200,7 +200,8 @@ void VPPiece::ClearTransformations()
const QPointF offset = MappedDetailBoundingRect().topLeft(); const QPointF offset = MappedDetailBoundingRect().topLeft();
Translate(-offset.x(), -offset.y()); 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(); QTransform pieceMatrix = GetMatrix();
QPointF center = pieceMatrix.map(DetailBoundingRect().center()); QPointF center = pieceMatrix.map(DetailBoundingRect().center());
@ -299,7 +300,23 @@ void VPPiece::Flip()
pieceMatrix *= m; pieceMatrix *= m;
SetMatrix(pieceMatrix); 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); 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; auto OutOfBound() const -> bool;
void SetOutOfBound(bool newOutOfBound); 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, 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()) if (piece.isNull())
{ {
@ -82,11 +82,21 @@ inline auto LineMatrix(const VPPiecePtr &piece, const QPointF &topLeft, qreal an
QTransform labelMatrix; QTransform labelMatrix;
labelMatrix.translate(topLeft.x(), topLeft.y()); labelMatrix.translate(topLeft.x(), topLeft.y());
if (piece->IsMirror()) if (piece->IsVerticallyFlipped() || piece->IsHorizontallyFlipped())
{ {
labelMatrix.scale(-1, 1); if (piece->IsVerticallyFlipped())
labelMatrix.rotate(-angle); {
labelMatrix.translate(-maxLineWidth, 0); 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 else
{ {
@ -169,6 +179,72 @@ inline auto SelectionBrush() -> QBrush
{ {
return {QColor(255, 160, 160, 60)}; 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 } // namespace
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -441,6 +517,8 @@ void VPGraphicsPiece::InitPieceLabelSVGFont(const QVector<QPointF> &labelShape,
const QVector<TextLine> labelLines = tm.GetLabelSourceLines(qFloor(dW), svgFont, penWidth); 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) for (const auto &tl : labelLines)
{ {
const VSvgFont fnt = LineFont(tl, svgFont); const VSvgFont fnt = LineFont(tl, svgFont);
@ -454,7 +532,8 @@ void VPGraphicsPiece::InitPieceLabelSVGFont(const QVector<QPointF> &labelShape,
const QString qsText = tl.m_qsText; const QString qsText = tl.m_qsText;
const qreal dX = LineAlign(tl, qsText, engine, dW, penWidth); const qreal dX = LineAlign(tl, qsText, engine, dW, penWidth);
// set up the rotation around top-left corner matrix // 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); auto *item = new QGraphicsPathItem(this);
item->setPath(engine.DrawPath(QPointF(), qsText)); 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 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) for (const auto &tl : labelLines)
{ {
const QFont fnt = LineFont(tl, tm.GetFont()); 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 QString qsText = tl.m_qsText;
const qreal dX = LineAlign(tl, qsText, fm, dW); const qreal dX = LineAlign(tl, qsText, fm, dW);
// set up the rotation around top-left corner matrix // 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) 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) [this](bool checked)
{ {
QList<VPPiecePtr> selectedPieces = SelectedPieces(); QList<VPPiecePtr> selectedPieces = SelectedPieces();
@ -791,9 +791,28 @@ void VPMainWindow::InitPropertyTabCurrentPiece()
const VPPiecePtr &selectedPiece = selectedPieces.constFirst(); const VPPiecePtr &selectedPiece = selectedPieces.constFirst();
if (not selectedPiece.isNull()) 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); LayoutWasSaved(false);
emit m_layout->PieceTransformationChanged(selectedPiece); emit m_layout->PieceTransformationChanged(selectedPiece);
} }
@ -1287,10 +1306,11 @@ void VPMainWindow::SetPropertyTabCurrentPieceData()
SetLineEditValue(ui->lineEditCurrentPieceGradationId, selectedPiece->GetGradationId()); SetLineEditValue(ui->lineEditCurrentPieceGradationId, selectedPiece->GetGradationId());
SetCheckBoxValue(ui->checkBoxCurrentPieceShowSeamline, not selectedPiece->IsHideMainPath()); 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(); const bool disableFlipping = selectedPiece->IsForbidFlipping() || selectedPiece->IsForceFlipping();
ui->checkBoxCurrentPieceMirrorPiece->setDisabled(disableFlipping); ui->checkBoxCurrentPieceVerticallyFlipped->setDisabled(disableFlipping);
if (not ui->checkBoxRelativeTranslation->isChecked()) if (not ui->checkBoxRelativeTranslation->isChecked())
{ {

View File

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

View File

@ -511,7 +511,8 @@ void VPLayoutFileReader::ReadPiece(const VPPiecePtr &piece)
piece->SetXScale(ReadAttributeDouble(attribs, ML::AttrXScale, QChar('1'))); piece->SetXScale(ReadAttributeDouble(attribs, ML::AttrXScale, QChar('1')));
piece->SetYScale(ReadAttributeDouble(attribs, ML::AttrYScale, QChar('1'))); piece->SetYScale(ReadAttributeDouble(attribs, ML::AttrYScale, QChar('1')));
piece->SetZValue(ReadAttributeDouble(attribs, ML::AttrZValue, 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->SetForbidFlipping(ReadAttributeBool(attribs, ML::AttrForbidFlipping, falseStr));
piece->SetForceFlipping(ReadAttributeBool(attribs, ML::AttrForceFlipping, falseStr)); piece->SetForceFlipping(ReadAttributeBool(attribs, ML::AttrForceFlipping, falseStr));
piece->SetFollowGrainline(ReadAttributeBool(attribs, ML::AttrFollowGrainline, falseStr)); piece->SetFollowGrainline(ReadAttributeBool(attribs, ML::AttrFollowGrainline, falseStr));

View File

@ -260,8 +260,10 @@ void VPLayoutFileWriter::WritePiece(const VPPiecePtr &piece)
writeStartElement(ML::TagPiece); writeStartElement(ML::TagPiece);
SetAttribute(ML::AttrUID, piece->GetUUID().toString()); SetAttribute(ML::AttrUID, piece->GetUUID().toString());
SetAttribute(ML::AttrName, piece->GetName()); SetAttribute(ML::AttrName, piece->GetName());
SetAttributeOrRemoveIf<bool>(ML::AttrMirrored, piece->IsMirror(), SetAttributeOrRemoveIf<bool>(ML::AttrVerticallyFlipped, piece->IsVerticallyFlipped(),
[](bool mirrored) noexcept { return not mirrored; }); [](bool flipped) noexcept { return not flipped; });
SetAttributeOrRemoveIf<bool>(ML::AttrHorizontallyFlipped, piece->IsHorizontallyFlipped(),
[](bool flipped) noexcept { return not flipped; });
SetAttributeOrRemoveIf<bool>(ML::AttrForbidFlipping, piece->IsForbidFlipping(), SetAttributeOrRemoveIf<bool>(ML::AttrForbidFlipping, piece->IsForbidFlipping(),
[](bool forbid) noexcept { return not forbid; }); [](bool forbid) noexcept { return not forbid; });
SetAttributeOrRemoveIf<bool>(ML::AttrForceFlipping, piece->IsForceFlipping(), 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 AttrFollowGrainline = QStringLiteral("followGrainline"); // NOLINT(cert-err58-cpp)
const QString AttrBoundaryTogetherWithNotches = QStringLiteral("boundaryTogetherWithNotches"); // NOLINT(cert-err58-cpp) const QString AttrBoundaryTogetherWithNotches = QStringLiteral("boundaryTogetherWithNotches"); // NOLINT(cert-err58-cpp)
const QString AttrUID = QStringLiteral("uid"); // 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 AttrForbidFlipping = QStringLiteral("forbidFlipping"); // NOLINT(cert-err58-cpp)
const QString AttrForceFlipping = QStringLiteral("forceFlipping"); // NOLINT(cert-err58-cpp) const QString AttrForceFlipping = QStringLiteral("forceFlipping"); // NOLINT(cert-err58-cpp)
const QString AttrSewLineOnDrawing = QStringLiteral("sewLineOnDrawing"); // 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 AttrFollowGrainline;
extern const QString AttrBoundaryTogetherWithNotches; extern const QString AttrBoundaryTogetherWithNotches;
extern const QString AttrUID; extern const QString AttrUID;
extern const QString AttrMirrored; extern const QString AttrVerticallyFlipped;
extern const QString AttrHorizontallyFlipped;
extern const QString AttrForbidFlipping; extern const QString AttrForbidFlipping;
extern const QString AttrForceFlipping; extern const QString AttrForceFlipping;
extern const QString AttrSewLineOnDrawing; extern const QString AttrSewLineOnDrawing;

View File

@ -221,7 +221,8 @@
</xs:sequence> </xs:sequence>
<xs:attribute name="uid" type="uuid" use="required"/> <xs:attribute name="uid" type="uuid" use="required"/>
<xs:attribute type="xs:string" name="name"/> <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="forbidFlipping"/>
<xs:attribute type="xs:boolean" name="forceFlipping"/> <xs:attribute type="xs:boolean" name="forceFlipping"/>
<xs:attribute type="xs:boolean" name="followGrainline"/> <xs:attribute type="xs:boolean" name="followGrainline"/>
@ -419,7 +420,8 @@
</xs:sequence> </xs:sequence>
<xs:attribute name="uid" type="uuid" use="required"/> <xs:attribute name="uid" type="uuid" use="required"/>
<xs:attribute type="xs:string" name="name"/> <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="forbidFlipping"/>
<xs:attribute type="xs:boolean" name="forceFlipping"/> <xs:attribute type="xs:boolean" name="forceFlipping"/>
<xs:attribute type="xs:boolean" name="followGrainline"/> <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 // The list of all string we use for conversion
// Better to use global variables because repeating QStringLiteral blows up code size // 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, strSeamLineTag, ("seamLine"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strSeamAllowanceTag, ("seamAllowance"_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, strInternalPathTag, ("internalPath"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strMarkerTag, ("marker"_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, strPointTag, ("point"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strPieceTag, ("piece"_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, strGrainlineTag, ("grainline"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrX, ("x"_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, strAttrY, ("y"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrTurnPoint, ("turnPoint"_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, strAttrCurvePoint, ("curvePoint"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrId, ("id"_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, strAttrUId, ("uid"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, strAttrAngle, ("angle"_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, 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 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() void VLayoutConverter::ToV0_1_3()
{ {
@ -407,6 +427,7 @@ void VLayoutConverter::ToV0_1_7()
// TODO. Delete if minimal supported version is 0.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."); Q_STATIC_ASSERT_X(VLayoutConverter::LayoutMinVer < FormatVersion(0, 1, 7), "Time to refactor the code.");
ConvertPiecesToV0_1_7();
SetVersion(QStringLiteral("0.1.7")); SetVersion(QStringLiteral("0.1.7"));
Save(); Save();
} }

View File

@ -72,6 +72,8 @@ protected:
void ConvertPiecesToV0_1_5(); void ConvertPiecesToV0_1_5();
void ConvertPiecesToV0_1_7();
void ToV0_1_3(); void ToV0_1_3();
void ToV0_1_5(); void ToV0_1_5();
void ToV0_1_7(); 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, auto LineMatrix(const VLayoutPiece &piece, const QPointF &topLeft, qreal angle, const QPointF &linePos,
int maxLineWidth) -> QTransform int maxLineWidth, qreal maxLabelHeight) -> QTransform
{ {
QTransform labelMatrix; QTransform labelMatrix;
labelMatrix.translate(topLeft.x(), topLeft.y()); labelMatrix.translate(topLeft.x(), topLeft.y());
if (piece.IsMirror()) if (piece.IsVerticallyFlipped() || piece.IsHorizontallyFlipped())
{ {
labelMatrix.scale(-1, 1); if (piece.IsVerticallyFlipped())
labelMatrix.rotate(-angle); {
labelMatrix.translate(-maxLineWidth, 0); 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 else
{ {
@ -220,6 +230,72 @@ auto NextPattern(int patternIndex, const QVector<int> &pattern) -> int
{ {
return (patternIndex + 2) % static_cast<int>(pattern.size()); 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 } // namespace
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -475,7 +551,8 @@ void VHPGLEngine::PlotInternalPaths(QTextStream &out, const VLayoutPiece &detail
QVector<VLayoutPiecePath> internalPaths = detail.GetInternalPaths(); QVector<VLayoutPiecePath> internalPaths = detail.GetInternalPaths();
for (const auto &path : internalPaths) 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()); 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 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) for (const auto &tl : labelLines)
{ {
const VSvgFont fnt = LineFont(tl, svgFont); 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 QString qsText = tl.m_qsText;
const qreal dX = LineAlign(tl, qsText, engine, dW, m_penWidthPx); const qreal dX = LineAlign(tl, qsText, engine, dW, m_penWidthPx);
// set up the rotation around top-left corner matrix // 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)); QPainterPath path = lineMatrix.map(engine.DrawPath(QPointF(), qsText));
PlotPainterPath(out, path, Qt::SolidLine); 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 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) for (const auto &tl : labelLines)
{ {
const QFont fnt = LineFont(tl, tm.GetFont()); 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 QString qsText = tl.m_qsText;
const qreal dX = LineAlign(tl, qsText, fm, dW); const qreal dX = LineAlign(tl, qsText, fm, dW);
// set up the rotation around top-left corner matrix // 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; QPainterPath path;

View File

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

View File

@ -667,7 +667,7 @@ template <> auto VLayoutPiece::Map<VLayoutPoint>(QVector<VLayoutPoint> points) c
point.ry() = p.y(); point.ry() = p.y();
return point; return point;
}); });
if (d->m_mirror) if (d->m_verticallyFlipped || d->m_horizontallyFlipped)
{ {
std::reverse(points.begin(), points.end()); std::reverse(points.begin(), points.end());
} }
@ -1087,7 +1087,7 @@ void VLayoutPiece::Mirror(const QLineF &edge)
m.translate(-p2.x(), -p2.y()); m.translate(-p2.x(), -p2.y());
d->m_matrix *= m; 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; QTransform m;
m.scale(-1, 1); m.scale(-1, 1);
d->m_matrix *= m; 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 // set up the rotation around top-left corner matrix
QTransform labelMatrix; QTransform labelMatrix;
labelMatrix.translate(labelShape.at(0).x(), labelShape.at(0).y()); labelMatrix.translate(labelShape.at(0).x(), labelShape.at(0).y());
if (d->m_mirror) if (d->m_verticallyFlipped)
{ {
labelMatrix.scale(-1, 1); labelMatrix.scale(-1, 1);
labelMatrix.rotate(-angle); labelMatrix.rotate(-angle);
@ -1704,7 +1704,7 @@ void VLayoutPiece::LabelStringsOutlineFont(QGraphicsItem *parent, const QVector<
// set up the rotation around top-left corner matrix // set up the rotation around top-left corner matrix
QTransform labelMatrix; QTransform labelMatrix;
labelMatrix.translate(labelShape.at(0).x(), labelShape.at(0).y()); labelMatrix.translate(labelShape.at(0).x(), labelShape.at(0).y());
if (d->m_mirror) if (d->m_verticallyFlipped)
{ {
labelMatrix.scale(-1, 1); labelMatrix.scale(-1, 1);
labelMatrix.rotate(-angle); 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; i2 = 0;
} }
if (d->m_mirror) if (d->m_verticallyFlipped || d->m_horizontallyFlipped)
{ {
QVector<QPointF> newPath = Map(path); QVector<QPointF> newPath = Map(path);
return {newPath.at(i1), newPath.at(i2)}; 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> 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; auto GetId() const -> vidtype;
void SetId(vidtype id); void SetId(vidtype id);
auto IsMirror() const -> bool; auto IsVerticallyFlipped() const -> bool;
void SetMirror(bool value); void SetVerticallyFlipped(bool value);
auto IsHorizontallyFlipped() const -> bool;
void SetHorizontallyFlipped(bool value);
void SetGradationId(const QString &id); void SetGradationId(const QString &id);
auto GetGradationId() const -> QString; auto GetGradationId() const -> QString;

View File

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

View File

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