/************************************************************************ ** ** @file ** @author Roman Telezhynskyi ** @date 1 10, 2016 ** ** @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) 2016 Valentina project ** 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 . ** *************************************************************************/ #include "vtoolmove.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../../dialogs/tools/dialogtool.h" #include "../../../dialogs/tools/dialogmove.h" #include "../../../visualization/line/operation/vistoolmove.h" #include "../../../visualization/visualization.h" #include "../vgeometry/vabstractcurve.h" #include "../vgeometry/varc.h" #include "../vgeometry/vellipticalarc.h" #include "../vgeometry/vcubicbezier.h" #include "../vgeometry/vcubicbezierpath.h" #include "../vgeometry/vgobject.h" #include "../vgeometry/vpointf.h" #include "../vgeometry/vspline.h" #include "../vgeometry/vsplinepath.h" #include "../vpatterndb/vtranslatevars.h" #include "../vmisc/vabstractapplication.h" #include "../vmisc/vcommonsettings.h" #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) #include "../vmisc/diagnostic.h" #endif // QT_VERSION < QT_VERSION_CHECK(5, 5, 0) #include "../vmisc/compatibility.h" #include "../vpatterndb/vcontainer.h" #include "../vpatterndb/vformula.h" #include "../ifc/ifcdef.h" #include "../ifc/exception/vexception.h" #include "../vwidgets/vabstractsimple.h" #include "../vwidgets/vmaingraphicsscene.h" #include "../../vabstracttool.h" #include "../../vdatatool.h" #include "../vdrawtool.h" template class QSharedPointer; const QString VToolMove::ToolType = QStringLiteral("moving"); namespace { QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wswitch-default") QPointF GetOriginPoint(const QVector &objects, const VContainer *data, qreal calcLength, qreal calcAngle) { QPolygonF originObjects; for (auto object : objects) { const QSharedPointer obj = data->GetGObject(object.id); // This check helps to find missed objects in the switch Q_STATIC_ASSERT_X(static_cast(GOType::Unknown) == 8, "Not all objects were handled."); switch(static_cast(obj->getType())) { case GOType::Point: originObjects.append(data->GeometricObject(object.id)->toQPointF()); break; case GOType::Arc: case GOType::EllipticalArc: case GOType::Spline: case GOType::SplinePath: case GOType::CubicBezier: case GOType::CubicBezierPath: AppendTo(originObjects, data->GeometricObject(object.id)->GetPoints()); break; case GOType::Unknown: case GOType::PlaceLabel: Q_UNREACHABLE(); break; } } QPointF rotationOrigin = originObjects.boundingRect().center(); QLineF move(rotationOrigin, QPointF(rotationOrigin.x()+calcLength, rotationOrigin.y())); move.setAngle(calcAngle); return move.p2(); } QT_WARNING_POP } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::setDialog() { SCASSERT(not m_dialog.isNull()) const QPointer dialogTool = qobject_cast(m_dialog); SCASSERT(not dialogTool.isNull()) dialogTool->SetAngle(formulaAngle); dialogTool->SetRotationAngle(formulaRotationAngle); dialogTool->SetLength(formulaLength); dialogTool->SetSuffix(suffix); dialogTool->SetRotationOrigPointId(origPointId); dialogTool->SetNotes(m_notes); dialogTool->SetSourceObjects(source); SetDialogVisibilityGroupData(dialogTool); } //--------------------------------------------------------------------------------------------------------------------- VToolMove *VToolMove::Create(const QPointer &dialog, VMainGraphicsScene *scene, VAbstractPattern *doc, VContainer *data) { SCASSERT(not dialog.isNull()) const QPointer dialogTool = qobject_cast(dialog); SCASSERT(not dialogTool.isNull()) VToolMoveInitData initData; initData.formulaAngle = dialogTool->GetAngle(); initData.formulaRotationAngle = dialogTool->GetRotationAngle(); initData.formulaLength = dialogTool->GetLength(); initData.rotationOrigin = dialogTool->GetRotationOrigPointId(); initData.suffix = dialogTool->GetSuffix(); initData.source = dialogTool->GetSourceObjects(); initData.hasLinkedVisibilityGroup = dialogTool->HasLinkedVisibilityGroup(); initData.visibilityGroupName = dialogTool->GetVisibilityGroupName(); initData.visibilityGroupTags = dialogTool->GetVisibilityGroupTags(); initData.scene = scene; initData.doc = doc; initData.data = data; initData.parse = Document::FullParse; initData.typeCreation = Source::FromGui; initData.notes = dialogTool->GetNotes(); VToolMove* operation = Create(initData); if (operation != nullptr) { operation->m_dialog = dialog; } return operation; } //--------------------------------------------------------------------------------------------------------------------- VToolMove *VToolMove::Create(VToolMoveInitData &initData) { qreal calcAngle = 0; qreal calcRotationAngle = 0; qreal calcLength = 0; calcAngle = CheckFormula(initData.id, initData.formulaAngle, initData.data); calcRotationAngle = CheckFormula(initData.id, initData.formulaRotationAngle, initData.data); calcLength = VAbstractValApplication::VApp()->toPixel(CheckFormula(initData.id, initData.formulaLength, initData.data)); QPointF rotationOrigin; QSharedPointer originPoint; if (initData.rotationOrigin == NULL_ID) { rotationOrigin = GetOriginPoint(initData.source, initData.data, calcLength, calcAngle); } else { originPoint = initData.data->GeometricObject(initData.rotationOrigin); rotationOrigin = static_cast(*originPoint); } if (initData.typeCreation == Source::FromGui) { initData.destination.clear();// Try to avoid mistake, value must be empty initData.id = initData.data->getNextId();//Just reserve id for tool for (auto object : qAsConst(initData.source)) { const QSharedPointer obj = initData.data->GetGObject(object.id); // This check helps to find missed objects in the switch Q_STATIC_ASSERT_X(static_cast(GOType::Unknown) == 8, "Not all objects were handled."); QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wswitch-default") switch(static_cast(obj->getType())) { case GOType::Point: initData.destination.append(CreatePoint(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data)); break; case GOType::Arc: initData.destination.append(CreateArc(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data)); break; case GOType::EllipticalArc: initData.destination.append(CreateArc(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data)); break; case GOType::Spline: initData.destination.append(CreateCurve(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data)); break; case GOType::SplinePath: initData.destination.append(CreateCurveWithSegments(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data)); break; case GOType::CubicBezier: initData.destination.append(CreateCurve(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data)); break; case GOType::CubicBezierPath: initData.destination.append(CreateCurveWithSegments(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data)); break; case GOType::Unknown: case GOType::PlaceLabel: Q_UNREACHABLE(); break; } QT_WARNING_POP } } else { for (int i = 0; i < initData.source.size(); ++i) { const SourceItem object = initData.source.at(i); const QSharedPointer obj = initData.data->GetGObject(object.id); // This check helps to find missed objects in the switch Q_STATIC_ASSERT_X(static_cast(GOType::Unknown) == 8, "Not all objects were handled."); QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wswitch-default") switch(static_cast(obj->getType())) { case GOType::Point: UpdatePoint(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data, initData.destination.at(i)); break; case GOType::Arc: UpdateArc(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data, initData.destination.at(i).id); break; case GOType::EllipticalArc: UpdateArc(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data, initData.destination.at(i).id); break; case GOType::Spline: UpdateCurve(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data, initData.destination.at(i).id); break; case GOType::SplinePath: UpdateCurveWithSegments(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin,initData.suffix, initData.data, initData.destination.at(i).id); break; case GOType::CubicBezier: UpdateCurve(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin,initData.suffix, initData.data, initData.destination.at(i).id); break; case GOType::CubicBezierPath: UpdateCurveWithSegments(initData.id, object, calcAngle, calcLength, calcRotationAngle, rotationOrigin, initData.suffix, initData.data, initData.destination.at(i).id); break; case GOType::Unknown: case GOType::PlaceLabel: Q_UNREACHABLE(); break; } QT_WARNING_POP } if (initData.parse != Document::FullParse) { initData.doc->UpdateToolData(initData.id, initData.data); } } if (initData.parse == Document::FullParse) { if (initData.typeCreation == Source::FromGui && initData.hasLinkedVisibilityGroup) { VAbstractApplication::VApp()->getUndoStack()->beginMacro(tr("move")); } VAbstractTool::AddRecord(initData.id, Tool::Move, initData.doc); VToolMove *tool = new VToolMove(initData); initData.scene->addItem(tool); InitOperationToolConnections(initData.scene, tool); VAbstractPattern::AddTool(initData.id, tool); if (not originPoint.isNull()) { initData.doc->IncrementReferens(originPoint->getIdTool()); } for (auto object : qAsConst(initData.source)) { initData.doc->IncrementReferens(initData.data->GetGObject(object.id)->getIdTool()); } if (initData.typeCreation == Source::FromGui && initData.hasLinkedVisibilityGroup) { VAbstractOperation::CreateVisibilityGroup(initData); VAbstractApplication::VApp()->getUndoStack()->endMacro(); } return tool; } return nullptr; } //--------------------------------------------------------------------------------------------------------------------- VFormula VToolMove::GetFormulaAngle() const { VFormula fAngle(formulaAngle, getData()); fAngle.setCheckZero(false); fAngle.setToolId(m_id); fAngle.setPostfix(degreeSymbol); fAngle.Eval(); return fAngle; } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::SetFormulaAngle(const VFormula &value) { if (value.error() == false) { formulaAngle = value.GetFormula(FormulaType::FromUser); QSharedPointer obj = VContainer::GetFakeGObject(m_id); SaveOption(obj); } } //--------------------------------------------------------------------------------------------------------------------- VFormula VToolMove::GetFormulaRotationAngle() const { VFormula fAngle(formulaRotationAngle, getData()); fAngle.setCheckZero(false); fAngle.setToolId(m_id); fAngle.setPostfix(degreeSymbol); fAngle.Eval(); return fAngle; } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::SetFormulaRotationAngle(const VFormula &value) { if (value.error() == false) { formulaRotationAngle = value.GetFormula(FormulaType::FromUser); QSharedPointer obj = VContainer::GetFakeGObject(m_id); SaveOption(obj); } } //--------------------------------------------------------------------------------------------------------------------- VFormula VToolMove::GetFormulaLength() const { VFormula fLength(formulaLength, getData()); fLength.setCheckZero(true); fLength.setToolId(m_id); fLength.setPostfix(UnitsToStr(VAbstractValApplication::VApp()->patternUnits())); fLength.Eval(); return fLength; } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::SetFormulaLength(const VFormula &value) { if (value.error() == false) { formulaLength = value.GetFormula(FormulaType::FromUser); QSharedPointer obj = VContainer::GetFakeGObject(m_id); SaveOption(obj); } } //--------------------------------------------------------------------------------------------------------------------- QString VToolMove::OriginPointName() const { try { return VAbstractTool::data.GetGObject(origPointId)->name(); } catch (const VExceptionBadId &) { return tr("Center point"); } } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::ShowVisualization(bool show) { ShowToolVisualization(show); } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::ShowContextMenu(QGraphicsSceneContextMenuEvent *event, quint32 id) { try { ContextMenu(event, id); } catch(const VExceptionToolWasDeleted &e) { Q_UNUSED(e) return;//Leave this method immediately!!! } } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::SetVisualization() { if (not vis.isNull()) { auto *visual = qobject_cast(vis); SCASSERT(visual != nullptr) const bool osSeparator = VAbstractApplication::VApp()->Settings()->GetOsSeparator(); const VTranslateVars *trVars = VAbstractApplication::VApp()->TrVars(); visual->SetObjects(SourceToObjects(source)); visual->SetAngle(trVars->FormulaToUser(formulaAngle, osSeparator)); visual->SetRotationAngle(trVars->FormulaToUser(formulaRotationAngle, osSeparator)); visual->SetLength(trVars->FormulaToUser(formulaLength, osSeparator)); visual->SetRotationOriginPointId(origPointId); visual->RefreshGeometry(); } } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::SaveDialog(QDomElement &domElement, QList &oldDependencies, QList &newDependencies) { SCASSERT(not m_dialog.isNull()) const QPointer dialogTool = qobject_cast(m_dialog); SCASSERT(not dialogTool.isNull()) AddDependence(oldDependencies, origPointId); AddDependence(newDependencies, dialogTool->GetRotationOrigPointId()); doc->SetAttribute(domElement, AttrAngle, dialogTool->GetAngle()); doc->SetAttribute(domElement, AttrLength, dialogTool->GetLength()); doc->SetAttribute(domElement, AttrSuffix, dialogTool->GetSuffix()); doc->SetAttribute(domElement, AttrCenter, QString().setNum(dialogTool->GetRotationOrigPointId())); doc->SetAttribute(domElement, AttrRotationAngle, dialogTool->GetRotationAngle()); doc->SetAttributeOrRemoveIf(domElement, AttrNotes, dialogTool->GetNotes(), [](const QString ¬es) noexcept {return notes.isEmpty();}); source = dialogTool->GetSourceObjects(); SaveSourceDestination(domElement); // Save visibility data for later use SaveVisibilityGroupData(dialogTool); } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::ReadToolAttributes(const QDomElement &domElement) { VAbstractOperation::ReadToolAttributes(domElement); origPointId = doc->GetParametrUInt(domElement, AttrCenter, NULL_ID_STR); formulaAngle = doc->GetParametrString(domElement, AttrAngle, QChar('0')); formulaRotationAngle = doc->GetParametrString(domElement, AttrRotationAngle, QChar('0')); formulaLength = doc->GetParametrString(domElement, AttrLength, QChar('0')); } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::SaveOptions(QDomElement &tag, QSharedPointer &obj) { VAbstractOperation::SaveOptions(tag, obj); doc->SetAttribute(tag, AttrType, ToolType); doc->SetAttribute(tag, AttrAngle, formulaAngle); doc->SetAttribute(tag, AttrRotationAngle, formulaRotationAngle); doc->SetAttribute(tag, AttrLength, formulaLength); doc->SetAttribute(tag, AttrCenter, QString().setNum(origPointId)); } //--------------------------------------------------------------------------------------------------------------------- QString VToolMove::MakeToolTip() const { return QStringLiteral(" %1: %2° " " %3: %4 %5 " " %6: %7° " " %8: %9 " "%10") .arg(tr("Angle")) // 1 .arg(GetFormulaAngle().getDoubleValue()) // 2 .arg(tr("Length")) // 3 .arg(GetFormulaLength().getDoubleValue()) // 4 .arg(UnitsToStr(VAbstractValApplication::VApp()->patternUnits(), true), // 5 tr("Rotation angle")) // 6 .arg(GetFormulaRotationAngle().getDoubleValue()) // 7 .arg(tr("Rotation origin point"), // 8 OriginPointName()) // 9 .arg(VisibilityGroupToolTip()); // 10 } //--------------------------------------------------------------------------------------------------------------------- VToolMove::VToolMove(const VToolMoveInitData &initData, QGraphicsItem *parent) : VAbstractOperation(initData, parent), formulaAngle(initData.formulaAngle), formulaRotationAngle(initData.formulaRotationAngle), formulaLength(initData.formulaLength), origPointId(initData.rotationOrigin) { InitOperatedObjects(); ToolCreation(initData.typeCreation); } //--------------------------------------------------------------------------------------------------------------------- DestinationItem VToolMove::CreatePoint(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data) { const QSharedPointer point = data->GeometricObject(sItem.id); VPointF moved = point->Move(length, angle, suffix).Rotate(rotationOrigin, rotationAngle); moved.setIdObject(idTool); if (not sItem.alias.isEmpty()) { moved.setName(sItem.alias); } DestinationItem item; item.mx = moved.mx(); item.my = moved.my(); item.showLabel = moved.IsShowLabel(); item.id = data->AddGObject(new VPointF(moved)); return item; } //--------------------------------------------------------------------------------------------------------------------- template DestinationItem VToolMove::CreateArc(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data) { const DestinationItem item = CreateItem(idTool, sItem, angle, length, rotationAngle, rotationOrigin, suffix, data); data->AddArc(data->GeometricObject(item.id), item.id); return item; } //--------------------------------------------------------------------------------------------------------------------- void VToolMove::UpdatePoint(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data, const DestinationItem &item) { const QSharedPointer point = data->GeometricObject(sItem.id); VPointF moved = point->Move(length, angle, suffix).Rotate(rotationOrigin, rotationAngle); moved.setIdObject(idTool); moved.setMx(item.mx); moved.setMy(item.my); moved.SetShowLabel(item.showLabel); if (not sItem.alias.isEmpty()) { moved.setName(sItem.alias); } data->UpdateGObject(item.id, new VPointF(moved)); } //--------------------------------------------------------------------------------------------------------------------- template void VToolMove::UpdateArc(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data, quint32 id) { UpdateItem(idTool, sItem, angle, length, rotationAngle, rotationOrigin, suffix, data, id); data->AddArc(data->GeometricObject(id), id); } //--------------------------------------------------------------------------------------------------------------------- template DestinationItem VToolMove::CreateItem(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data) { const QSharedPointer i = data->GeometricObject(sItem.id); Item moved = i->Move(length, angle, suffix).Rotate(rotationOrigin, rotationAngle); moved.setIdObject(idTool); if (not sItem.alias.isEmpty()) { moved.SetAliasSuffix(sItem.alias); } if (sItem.penStyle != TypeLineDefault) { moved.SetPenStyle(sItem.penStyle); } if (sItem.color != ColorDefault) { moved.SetColor(sItem.color); } DestinationItem item; item.id = data->AddGObject(new Item(moved)); return item; } //--------------------------------------------------------------------------------------------------------------------- template DestinationItem VToolMove::CreateCurve(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data) { const DestinationItem item = CreateItem(idTool, sItem, angle, length, rotationAngle, rotationOrigin, suffix, data); data->AddSpline(data->GeometricObject(item.id), item.id); return item; } //--------------------------------------------------------------------------------------------------------------------- template DestinationItem VToolMove::CreateCurveWithSegments(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data) { const DestinationItem item = CreateItem(idTool, sItem, angle, length, rotationAngle, rotationOrigin, suffix, data); data->AddCurveWithSegments(data->GeometricObject(item.id), item.id); return item; } //--------------------------------------------------------------------------------------------------------------------- template void VToolMove::UpdateItem(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data, quint32 id) { const QSharedPointer i = data->GeometricObject(sItem.id); Item moved = i->Move(length, angle, suffix).Rotate(rotationOrigin, rotationAngle); moved.setIdObject(idTool); if (not sItem.alias.isEmpty()) { moved.SetAliasSuffix(sItem.alias); } if (sItem.penStyle != TypeLineDefault) { moved.SetPenStyle(sItem.penStyle); } if (sItem.color != ColorDefault) { moved.SetColor(sItem.color); } data->UpdateGObject(id, new Item(moved)); } //--------------------------------------------------------------------------------------------------------------------- template void VToolMove::UpdateCurve(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data, quint32 id) { UpdateItem(idTool, sItem, angle, length, rotationAngle, rotationOrigin, suffix, data, id); data->AddSpline(data->GeometricObject(id), id); } //--------------------------------------------------------------------------------------------------------------------- template void VToolMove::UpdateCurveWithSegments(quint32 idTool, const SourceItem &sItem, qreal angle, qreal length, qreal rotationAngle, const QPointF &rotationOrigin, const QString &suffix, VContainer *data, quint32 id) { UpdateItem(idTool, sItem, angle, length, rotationAngle, rotationOrigin, suffix, data, id); data->AddCurveWithSegments(data->GeometricObject(id), id); }