1 /************************************************************************
2  **
3  **  @file   vpatternrecipe.cpp
4  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
5  **  @date   8 7, 2019
6  **
7  **  @brief
8  **  @copyright
9  **  This source code is part of the Valentina project, a pattern making
10  **  program, whose allow create and modeling patterns of clothing.
11  **  Copyright (C) 2019 Valentina project
12  **  <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
13  **
14  **  Valentina is free software: you can redistribute it and/or modify
15  **  it under the terms of the GNU General Public License as published by
16  **  the Free Software Foundation, either version 3 of the License, or
17  **  (at your option) any later version.
18  **
19  **  Valentina is distributed in the hope that it will be useful,
20  **  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  **  GNU General Public License for more details.
23  **
24  **  You should have received a copy of the GNU General Public License
25  **  along with Valentina.  If not, see <http://www.gnu.org/licenses/>.
26  **
27  *************************************************************************/
28 
29 #include "vpatternrecipe.h"
30 #include "../vmisc/projectversion.h"
31 #include "../vmisc/vabstractapplication.h"
32 #include "../ifc/xml/vabstractpattern.h"
33 #include "../ifc/exception/vexceptioninvalidhistory.h"
34 #include "../vpatterndb/vcontainer.h"
35 #include "../vgeometry/vpointf.h"
36 #include "../vgeometry/vcubicbezier.h"
37 #include "../vgeometry/vsplinepath.h"
38 #include "../vgeometry/vcubicbezierpath.h"
39 #include "../vtools/tools/drawTools/drawtools.h"
40 #include "../vpatterndb/calculator.h"
41 
42 namespace
43 {
44 #define TagStep QStringLiteral("step")
45 
46 #define AttrLabel QStringLiteral("label")
47 #define AttrLengthValue QStringLiteral("lengthValue")
48 #define AttrAngleValue QStringLiteral("angleValue")
49 #define AttrAngle1Value QStringLiteral("angle1Value")
50 #define AttrAngle2Value QStringLiteral("angle2Value")
51 #define AttrLength1Value QStringLiteral("length1Value")
52 #define AttrLength2Value QStringLiteral("length2Value")
53 #define AttrRadiusValue QStringLiteral("radiusValue")
54 #define AttrC1RadiusValue QStringLiteral("c1RadiusValue")
55 #define AttrC2RadiusValue QStringLiteral("c2RadiusValue")
56 #define AttrCRadiusValue QStringLiteral("cRadiusValue")
57 #define AttrRadius1Value QStringLiteral("radius1Value")
58 #define AttrRadius2Value QStringLiteral("radius2Value")
59 #define AttrRotationAngleValue QStringLiteral("rotationAngleValue")
60 
61 //---------------------------------------------------------------------------------------------------------------------
FileComment()62 inline QString FileComment()
63 {
64     return QStringLiteral("Recipe created with Valentina v%1 (https://smart-pattern.com.ua/).")
65             .arg(APP_VERSION_STR);
66 }
67 
68 //---------------------------------------------------------------------------------------------------------------------
69 template <typename T>
GetPatternTool(quint32 id)70 T *GetPatternTool(quint32 id)
71 {
72     T* tool = qobject_cast<T*>(VAbstractPattern::getTool(id));
73     if (not tool)
74     {
75         throw VExceptionInvalidHistory(QObject::tr("Cannot cast tool with id '%1'.").arg(id));
76     }
77     return tool;
78 }
79 }  // namespace
80 
81 //---------------------------------------------------------------------------------------------------------------------
VPatternRecipe(VAbstractPattern * pattern,QObject * parent)82 VPatternRecipe::VPatternRecipe(VAbstractPattern *pattern, QObject *parent)
83     : VDomDocument(parent),
84       m_pattern(pattern)
85 {
86     SCASSERT(pattern != nullptr)
87 
88     QDomElement recipeElement = createElement(QStringLiteral("recipe"));
89     recipeElement.appendChild(createComment(FileComment()));
90     SetAttribute(recipeElement, QStringLiteral("version"), QStringLiteral("1.3.0"));
91 
92     recipeElement.appendChild(Prerequisite());
93     recipeElement.appendChild(Content());
94 
95     appendChild(recipeElement);
96     insertBefore(createProcessingInstruction(QStringLiteral("xml"),
97                                              QStringLiteral("version=\"1.0\" encoding=\"UTF-8\"")), firstChild());
98 }
99 
100 //---------------------------------------------------------------------------------------------------------------------
Prerequisite()101 QDomElement VPatternRecipe::Prerequisite()
102 {
103     /*
104      <prerequisite>
105         <measurements>
106             <m description="" full_name="Обхват талии" name="@От" value="65"/>
107         </measurements>
108         <increments>
109             <increment description="" formula="height/2-15" name="#L_C"/>
110         </increments>
111         <previewCalculations>
112             <increment description="" formula="height/2-15" name="#L_C"/>
113         </previewCalculations>
114     </prerequisite>
115      */
116     QDomElement prerequisiteElement = createElement(QStringLiteral("prerequisite"));
117 
118     prerequisiteElement.appendChild(CreateElementWithText(QStringLiteral("valentina"), APP_VERSION_STR));
119     prerequisiteElement.appendChild(CreateElementWithText(QStringLiteral("unit"),
120                                                           UnitsToStr(VAbstractValApplication::VApp()->patternUnits())));
121     prerequisiteElement.appendChild(CreateElementWithText(QStringLiteral("author"), m_pattern->GetCompanyName()));
122     prerequisiteElement.appendChild(CreateElementWithText(QStringLiteral("pattenName"), m_pattern->GetPatternName()));
123     prerequisiteElement.appendChild(CreateElementWithText(QStringLiteral("description"), m_pattern->GetDescription()));
124     prerequisiteElement.appendChild(CreateElementWithText(QStringLiteral("notes"), m_pattern->GetNotes()));
125     prerequisiteElement.appendChild(Measurements());
126     prerequisiteElement.appendChild(Increments());
127     prerequisiteElement.appendChild(PreviewCalculations());
128 
129     return prerequisiteElement;
130 }
131 
132 //---------------------------------------------------------------------------------------------------------------------
Measurements()133 QDomElement VPatternRecipe::Measurements()
134 {
135     QDomElement measurements = createElement(QStringLiteral("measurements"));
136 
137     VContainer data = m_pattern->GetCompleteData();
138     QList<QSharedPointer<VMeasurement>> patternMeasurements = data.DataMeasurements().values();
139 
140     // Resore order
141     std::sort(patternMeasurements.begin(), patternMeasurements.end(),
142               [](const QSharedPointer<VMeasurement> &a, const QSharedPointer<VMeasurement> &b)
143     {return a->Index() < b->Index();});
144 
145     for(auto &m : patternMeasurements)
146     {
147         measurements.appendChild(Measurement(m));
148     }
149 
150     return measurements;
151 }
152 
153 //---------------------------------------------------------------------------------------------------------------------
Measurement(const QSharedPointer<VMeasurement> & m)154 QDomElement VPatternRecipe::Measurement(const QSharedPointer<VMeasurement> &m)
155 {
156     /*
157      * <measurements>
158      *  <m description="" full_name="Обхват талии" name="@От" value="65"/>
159      * </measurements>
160      */
161     QDomElement measurement = createElement(QStringLiteral("measurement"));
162 
163     SetAttribute(measurement, QStringLiteral("description"), m->GetDescription());
164     SetAttribute(measurement, QStringLiteral("fullName"), m->GetGuiText());
165     SetAttribute(measurement, QStringLiteral("name"), m->GetName());
166     SetAttribute(measurement, QStringLiteral("formula"), m->GetFormula()); // TODO: localize
167     SetAttribute(measurement, QStringLiteral("value"), *m->GetValue());
168 
169     return measurement;
170 }
171 
172 //---------------------------------------------------------------------------------------------------------------------
Increments()173 QDomElement VPatternRecipe::Increments()
174 {
175     QDomElement increments = createElement(QStringLiteral("increments"));
176 
177     VContainer data = m_pattern->GetCompleteData();
178     QList<QSharedPointer<VIncrement>> patternIncrements = data.DataIncrementsWithSeparators().values();
179 
180     // Resore order
181     std::sort(patternIncrements.begin(), patternIncrements.end(),
182               [](const QSharedPointer<VIncrement> &a, const QSharedPointer<VIncrement> &b)
183     {return a->GetIndex() < b->GetIndex();});
184 
185     for(auto &incr : patternIncrements)
186     {
187         if (not incr->IsPreviewCalculation())
188         {
189             increments.appendChild(Increment(incr));
190         }
191     }
192 
193     return increments;
194 }
195 
196 //---------------------------------------------------------------------------------------------------------------------
PreviewCalculations()197 QDomElement VPatternRecipe::PreviewCalculations()
198 {
199     QDomElement previewCalculations = createElement(QStringLiteral("previewCalculations"));
200 
201     VContainer data = m_pattern->GetCompleteData();
202     QList<QSharedPointer<VIncrement>> patternIncrements = data.DataIncrementsWithSeparators().values();
203 
204     // Resore order
205     std::sort(patternIncrements.begin(), patternIncrements.end(),
206               [](const QSharedPointer<VIncrement> &a, const QSharedPointer<VIncrement> &b)
207     {return a->GetIndex() < b->GetIndex();});
208 
209     for(auto &incr : patternIncrements)
210     {
211         if (incr->IsPreviewCalculation())
212         {
213             previewCalculations.appendChild(Increment(incr));
214         }
215     }
216 
217     return previewCalculations;
218 }
219 
220 //---------------------------------------------------------------------------------------------------------------------
Increment(const QSharedPointer<VIncrement> & incr)221 QDomElement VPatternRecipe::Increment(const QSharedPointer<VIncrement> &incr)
222 {
223     QDomElement measurement = createElement(QStringLiteral("increment"));
224 
225     SetAttribute(measurement, QStringLiteral("description"), incr->GetDescription());
226     SetAttribute(measurement, QStringLiteral("name"), incr->GetName());
227 
228     if (incr->GetType() != VarType::IncrementSeparator)
229     {
230         SetAttribute(measurement, QStringLiteral("formula"), incr->GetFormula()); // TODO: localize
231         SetAttribute(measurement, QStringLiteral("value"), *incr->GetValue());
232     }
233     else
234     {
235         SetAttribute(measurement, QStringLiteral("separator"), true);
236     }
237 
238     return measurement;
239 }
240 
241 //---------------------------------------------------------------------------------------------------------------------
Content()242 QDomElement VPatternRecipe::Content()
243 {
244     QDomElement content = createElement(QStringLiteral("content"));
245 
246     const QDomNodeList draws = m_pattern->documentElement().elementsByTagName(VAbstractPattern::TagDraw);
247     for (int i=0; i < draws.size(); ++i)
248     {
249         QDomElement draw = draws.at(i).toElement();
250         if (draw.isNull())
251         {
252             throw VExceptionInvalidHistory(tr("Invalid tag %1").arg(VAbstractPattern::TagDraw));
253         }
254 
255         content.appendChild(Draft(draw));
256     }
257 
258     content.appendChild(FinalMeasurements());
259 
260     return content;
261 }
262 
263 //---------------------------------------------------------------------------------------------------------------------
Draft(const QDomElement & draft)264 QDomElement VPatternRecipe::Draft(const QDomElement &draft)
265 {
266     QDomElement recipeDraft = createElement(QStringLiteral("draft"));
267 
268     const QString draftName = draft.attribute(QStringLiteral("name"));
269     SetAttribute(recipeDraft, QStringLiteral("name"), draftName);
270 
271     VContainer data = m_pattern->GetCompletePPData(draftName);
272 
273     QVector<VToolRecord> *history = m_pattern->getHistory();
274     for (auto &record : *history)
275     {
276         if (record.getNameDraw() == draftName)
277         {
278             QDomElement step = Step(record, data);
279             if (not step.isNull())
280             {
281                 recipeDraft.appendChild(step);
282             }
283         }
284     }
285 
286     return recipeDraft;
287 }
288 
289 //---------------------------------------------------------------------------------------------------------------------
Step(const VToolRecord & tool,const VContainer & data)290 QDomElement VPatternRecipe::Step(const VToolRecord &tool, const VContainer &data)
291 {
292     // This check helps to find missed tools in the switch
293     Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in history.");
294 
295     const QDomElement domElem = m_pattern->elementById(tool.getId());
296     if (not domElem.isElement() && tool.IsMandatory())
297     {
298         throw VExceptionInvalidHistory(tr("Can't find element by id '%1'").arg(tool.getId()));
299     }
300     try
301     {
302 QT_WARNING_PUSH
303 QT_WARNING_DISABLE_GCC("-Wswitch-default")
304         switch (tool.getTypeTool())
305         {
306             case Tool::Arrow:
307             case Tool::SinglePoint:
308             case Tool::DoublePoint:
309             case Tool::LinePoint:
310             case Tool::AbstractSpline:
311             case Tool::Cut:
312             case Tool::Midpoint:// Same as Tool::AlongLine, but tool will never has such type
313             case Tool::ArcIntersectAxis:// Same as Tool::CurveIntersectAxis, but tool will never has such type
314             case Tool::LAST_ONE_DO_NOT_USE:
315                 Q_UNREACHABLE(); //-V501
316                 break;
317             case Tool::BasePoint:
318                 return BasePoint(tool);
319             case Tool::EndLine:
320                 return EndLine(tool);
321             case Tool::Line:
322                 return Line(tool);
323             case Tool::AlongLine:
324                 return AlongLine(tool);
325             case Tool::ShoulderPoint:
326                 return ShoulderPoint(tool);
327             case Tool::Normal:
328                 return Normal(tool);
329             case Tool::Bisector:
330                 return Bisector(tool);
331             case Tool::LineIntersect:
332                 return LineIntersect(tool);
333             case Tool::Spline:
334                 return Spline(tool);
335             case Tool::CubicBezier:
336                 return CubicBezier(tool);
337             case Tool::Arc:
338                 return Arc(tool);
339             case Tool::ArcWithLength:
340                 return ArcWithLength(tool);
341             case Tool::SplinePath:
342                 return SplinePath(tool);
343             case Tool::CubicBezierPath:
344                 return CubicBezierPath(tool);
345             case Tool::PointOfContact:
346                 return PointOfContact(tool);
347             case Tool::Height:
348                 return Height(tool);
349             case Tool::Triangle:
350                 return Triangle(tool);
351             case Tool::PointOfIntersection:
352                 return PointOfIntersection(tool);
353             case Tool::CutArc:
354                 return CutArc(tool);
355             case Tool::CutSpline:
356                 return CutSpline(tool);
357             case Tool::CutSplinePath:
358                 return CutSplinePath(tool);
359             case Tool::LineIntersectAxis:
360                 return LineIntersectAxis(tool);
361             case Tool::CurveIntersectAxis:
362                 return CurveIntersectAxis(tool);
363             case Tool::PointOfIntersectionArcs:
364                 return PointOfIntersectionArcs(tool);
365             case Tool::PointOfIntersectionCircles:
366                 return PointOfIntersectionCircles(tool);
367             case Tool::PointOfIntersectionCurves:
368                 return PointOfIntersectionCurves(tool);
369             case Tool::PointFromCircleAndTangent:
370                 return PointFromCircleAndTangent(tool);
371             case Tool::PointFromArcAndTangent:
372                 return PointFromArcAndTangent(tool);
373             case Tool::TrueDarts:
374                 return TrueDarts(tool);
375             case Tool::EllipticalArc:
376                 return EllipticalArc(tool);
377             case Tool::Rotation:
378                 return Rotation(tool, data);
379             case Tool::FlippingByLine:
380                 return FlippingByLine(tool, data);
381             case Tool::FlippingByAxis:
382                 return FlippingByAxis(tool, data);
383             case Tool::Move:
384                 return Move(tool, data);
385             //Because "history" not only show history of pattern, but help restore current data for each pattern's
386             //piece, we need add record about details and nodes, but don't show them.
387             case Tool::Piece:
388             case Tool::UnionDetails:
389             case Tool::NodeArc:
390             case Tool::NodeElArc:
391             case Tool::NodePoint:
392             case Tool::NodeSpline:
393             case Tool::NodeSplinePath:
394             case Tool::Group:
395             case Tool::PiecePath:
396             case Tool::Pin:
397             case Tool::PlaceLabel:
398             case Tool::InsertNode:
399             case Tool::DuplicateDetail:
400                 return QDomElement();
401         }
402 QT_WARNING_POP
403     }
404     catch (const VExceptionBadId &e)
405     {
406         throw VExceptionInvalidHistory(e.ErrorMessage());
407     }
408 
409     throw VExceptionInvalidHistory(tr("Can't create history record for the tool."));
410 }
411 
412 //---------------------------------------------------------------------------------------------------------------------
FinalMeasurements()413 QDomElement VPatternRecipe::FinalMeasurements()
414 {
415     QDomElement recipeFinalMeasurements = createElement(QStringLiteral("finalMeasurements"));
416 
417     const QVector<VFinalMeasurement> measurements = m_pattern->GetFinalMeasurements();
418     VContainer data = m_pattern->GetCompleteData();
419 
420     for (auto &m : measurements)
421     {
422         recipeFinalMeasurements.appendChild(FinalMeasurement(m, data));
423     }
424 
425     return recipeFinalMeasurements;
426 }
427 
428 //---------------------------------------------------------------------------------------------------------------------
FinalMeasurement(const VFinalMeasurement & fm,const VContainer & data)429 QDomElement VPatternRecipe::FinalMeasurement(const VFinalMeasurement &fm, const VContainer &data)
430 {
431     QDomElement recipeFinalMeasurement = createElement(QStringLiteral("finalMeasurement"));
432 
433     SetAttribute(recipeFinalMeasurement, QStringLiteral("description"), fm.description);
434     SetAttribute(recipeFinalMeasurement, QStringLiteral("name"), fm.name);
435     SetAttribute(recipeFinalMeasurement, QStringLiteral("formula"), fm.formula); // TODO: localize
436 
437     QScopedPointer<Calculator> cal(new Calculator());
438     try
439     {
440         const qreal result = cal->EvalFormula(data.DataVariables(), fm.formula);
441         if (qIsInf(result) || qIsNaN(result))
442         {
443             const QString errorMsg = QString("%1\n\n%1").arg(tr("Reading final measurements error."),
444                                                              tr("Value for final measurtement '%1' is infinite or NaN. "
445                                                                 "Please, check your calculations.").arg(fm.name));
446             VAbstractApplication::VApp()->IsPedantic() ? throw VException(errorMsg)
447                                                        : qWarning()
448                                                          << VAbstractValApplication::warningMessageSignature + errorMsg;
449         }
450 
451         SetAttribute(recipeFinalMeasurement, QStringLiteral("value"), result);
452     }
453     catch (const qmu::QmuParserError &e)
454     {
455         throw VExceptionInvalidHistory(tr("Unable to create record for final measurement '%1'. Error: %2")
456                                        .arg(fm.name).arg(e.GetMsg()));
457     }
458 
459     return recipeFinalMeasurement;
460 }
461 
462 //---------------------------------------------------------------------------------------------------------------------
BasePoint(const VToolRecord & record)463 QDomElement VPatternRecipe::BasePoint(const VToolRecord &record)
464 {
465     auto *tool = GetPatternTool<VToolBasePoint>(record.getId());
466 
467     QDomElement step = createElement(TagStep);
468     ToolAttributes(step, tool);
469     return step;
470 }
471 
472 //---------------------------------------------------------------------------------------------------------------------
EndLine(const VToolRecord & record)473 QDomElement VPatternRecipe::EndLine(const VToolRecord &record)
474 {
475     auto *tool = GetPatternTool<VToolEndLine>(record.getId());
476 
477     QDomElement step = createElement(TagStep);
478 
479     ToolAttributes(step, tool);
480     SetAttribute(step, AttrBasePoint, tool->BasePointName());
481     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
482     Formula(step, tool->GetFormulaAngle(), AttrAngle, AttrAngleValue);
483     LineAttributes(step, tool);
484 
485     return step;
486 }
487 
488 //---------------------------------------------------------------------------------------------------------------------
Line(const VToolRecord & record)489 QDomElement VPatternRecipe::Line(const VToolRecord &record)
490 {
491     auto *tool = GetPatternTool<VToolLine>(record.getId());
492 
493     QDomElement step = createElement(TagStep);
494 
495     SetAttribute(step, AttrType, QStringLiteral("segment"));
496     SetAttribute(step, AttrFirstPoint, tool->FirstPointName());
497     SetAttribute(step, AttrSecondPoint, tool->SecondPointName());
498     LineAttributes(step, tool);
499 
500     return step;
501 }
502 
503 //---------------------------------------------------------------------------------------------------------------------
AlongLine(const VToolRecord & record)504 QDomElement VPatternRecipe::AlongLine(const VToolRecord &record)
505 {
506     auto *tool = GetPatternTool<VToolAlongLine>(record.getId());
507 
508     QDomElement step = createElement(TagStep);
509 
510     ToolAttributes(step, tool);
511     SetAttribute(step, AttrBasePoint, tool->BasePointName());
512     SetAttribute(step, AttrSecondPoint, tool->SecondPointName());
513     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
514     LineAttributes(step, tool);
515 
516     return step;
517 }
518 
519 //---------------------------------------------------------------------------------------------------------------------
ShoulderPoint(const VToolRecord & record)520 QDomElement VPatternRecipe::ShoulderPoint(const VToolRecord &record)
521 {
522     auto *tool = GetPatternTool<VToolShoulderPoint>(record.getId());
523 
524     QDomElement step = createElement(TagStep);
525 
526     ToolAttributes(step, tool);
527     SetAttribute(step, AttrP1Line, tool->BasePointName());
528     SetAttribute(step, AttrP2Line, tool->SecondPointName());
529     SetAttribute(step, AttrPShoulder, tool->ShoulderPointName());
530     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
531     LineAttributes(step, tool);
532 
533     return step;
534 }
535 
536 //---------------------------------------------------------------------------------------------------------------------
Normal(const VToolRecord & record)537 QDomElement VPatternRecipe::Normal(const VToolRecord &record)
538 {
539     auto *tool = GetPatternTool<VToolNormal>(record.getId());
540 
541     QDomElement step = createElement(TagStep);
542 
543     ToolAttributes(step, tool);
544     SetAttribute(step, AttrFirstPoint, tool->BasePointName());
545     SetAttribute(step, AttrSecondPoint, tool->SecondPointName());
546     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
547     SetAttribute(step, AttrAngle, tool->GetAngle());
548     LineAttributes(step, tool);
549 
550     return step;
551 }
552 
553 //---------------------------------------------------------------------------------------------------------------------
Bisector(const VToolRecord & record)554 QDomElement VPatternRecipe::Bisector(const VToolRecord &record)
555 {
556     auto *tool = GetPatternTool<VToolBisector>(record.getId());
557 
558     QDomElement step = createElement(TagStep);
559 
560     ToolAttributes(step, tool);
561     SetAttribute(step, AttrFirstPoint, tool->FirstPointName());
562     SetAttribute(step, AttrSecondPoint, tool->BasePointName());
563     SetAttribute(step, AttrThirdPoint, tool->ThirdPointName());
564     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
565     LineAttributes(step, tool);
566 
567     return step;
568 }
569 
570 //---------------------------------------------------------------------------------------------------------------------
LineIntersect(const VToolRecord & record)571 QDomElement VPatternRecipe::LineIntersect(const VToolRecord &record)
572 {
573     auto *tool = GetPatternTool<VToolLineIntersect>(record.getId());
574 
575     QDomElement step = createElement(TagStep);
576 
577     ToolAttributes(step, tool);
578 
579     SetAttribute(step, AttrP1Line1, tool->Line1P1Name());
580     SetAttribute(step, AttrP2Line1, tool->Line1P2Name());
581     SetAttribute(step, AttrP1Line2, tool->Line2P1Name());
582     SetAttribute(step, AttrP2Line2, tool->Line2P2Name());
583 
584     return step;
585 }
586 
587 //---------------------------------------------------------------------------------------------------------------------
Spline(const VToolRecord & record)588 QDomElement VPatternRecipe::Spline(const VToolRecord &record)
589 {
590     auto *tool = GetPatternTool<VToolSpline>(record.getId());
591     VSpline spl = tool->getSpline();
592 
593     QDomElement step = createElement(TagStep);
594 
595     SetAttribute(step, AttrType, QStringLiteral("spline"));
596     SetAttribute(step, AttrLabel, tool->name());
597 
598     SetAttribute(step, AttrPoint1, spl.GetP1().name());
599     SetAttribute(step, AttrPoint4, spl.GetP4().name());
600 
601     SetAttribute(step, AttrAngle1, spl.GetStartAngleFormula());
602     SetAttribute(step, AttrAngle1Value, spl.GetStartAngle());
603 
604     SetAttribute(step, AttrAngle2, spl.GetEndAngleFormula());
605     SetAttribute(step, AttrAngle2Value, spl.GetEndAngle());
606 
607     SetAttribute(step, AttrLength1, spl.GetC1LengthFormula());
608     SetAttribute(step, AttrLength1Value, VAbstractValApplication::VApp()->fromPixel(spl.GetC1Length()));
609 
610     SetAttribute(step, AttrLength2, spl.GetC2LengthFormula());
611     SetAttribute(step, AttrLength2Value, VAbstractValApplication::VApp()->fromPixel(spl.GetC2Length()));
612 
613     CurveAttributes(step, tool);
614 
615     return step;
616 }
617 
618 //---------------------------------------------------------------------------------------------------------------------
CubicBezier(const VToolRecord & record)619 QDomElement VPatternRecipe::CubicBezier(const VToolRecord &record)
620 {
621     auto *tool = GetPatternTool<VToolCubicBezier>(record.getId());
622     VCubicBezier spl = tool->getSpline();
623 
624     QDomElement step = createElement(TagStep);
625 
626     ToolAttributes(step, tool);
627     SetAttribute(step, AttrPoint1, spl.GetP1().name());
628     SetAttribute(step, AttrPoint2, spl.GetP2().name());
629     SetAttribute(step, AttrPoint3, spl.GetP3().name());
630     SetAttribute(step, AttrPoint4, spl.GetP4().name());
631 
632     CurveAttributes(step, tool);
633 
634     return step;
635 }
636 
637 //---------------------------------------------------------------------------------------------------------------------
Arc(const VToolRecord & record)638 QDomElement VPatternRecipe::Arc(const VToolRecord &record)
639 {
640     auto *tool = GetPatternTool<VToolArc>(record.getId());
641 
642     QDomElement step = createElement(TagStep);
643 
644     SetAttribute(step, AttrType, QStringLiteral("arc"));
645     SetAttribute(step, AttrLabel, tool->name());
646     SetAttribute(step, AttrCenter, tool->CenterPointName());
647     Formula(step, tool->GetFormulaRadius(), AttrRadius, AttrRadiusValue);
648     Formula(step, tool->GetFormulaF1(), AttrAngle1, AttrAngle1Value);
649     Formula(step, tool->GetFormulaF2(), AttrAngle2, AttrAngle2Value);
650 
651     CurveAttributes(step, tool);
652 
653     return step;
654 }
655 
656 //---------------------------------------------------------------------------------------------------------------------
ArcWithLength(const VToolRecord & record)657 QDomElement VPatternRecipe::ArcWithLength(const VToolRecord &record)
658 {
659     auto *tool = GetPatternTool<VToolArcWithLength>(record.getId());
660 
661     QDomElement step = createElement(TagStep);
662 
663     ToolAttributes(step, tool);
664     SetAttribute(step, AttrCenter, tool->CenterPointName());
665     Formula(step, tool->GetFormulaRadius(), AttrRadius, AttrRadiusValue);
666     Formula(step, tool->GetFormulaF1(), AttrAngle1, AttrAngle1Value);
667     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
668 
669     CurveAttributes(step, tool);
670 
671     return step;
672 }
673 
674 //---------------------------------------------------------------------------------------------------------------------
SplinePath(const VToolRecord & record)675 QDomElement VPatternRecipe::SplinePath(const VToolRecord &record)
676 {
677     auto *tool = GetPatternTool<VToolSplinePath>(record.getId());
678     VSplinePath spl = tool->getSplinePath();
679 
680     QDomElement step = createElement(TagStep);
681 
682     SetAttribute(step, AttrType, QStringLiteral("splinePath"));
683     SetAttribute(step, AttrLabel, tool->name());
684 
685     QDomElement nodes = createElement(QStringLiteral("nodes"));
686     QVector<VSplinePoint> path = spl.GetSplinePath();
687 
688     if (path.isEmpty())
689     {
690         throw VExceptionInvalidHistory(QObject::tr("Empty list of nodes for tool with id '%1'.").arg(record.getId()));
691     }
692 
693     for (auto &pathNode : path)
694     {
695         QDomElement node = createElement(QStringLiteral("node"));
696 
697         SetAttribute(node, AttrPSpline, pathNode.P().name());
698 
699         SetAttribute(node, AttrAngle1, pathNode.Angle1Formula());
700         SetAttribute(node, AttrAngle1Value, pathNode.Angle1());
701 
702         SetAttribute(node, AttrAngle2, pathNode.Angle2Formula());
703         SetAttribute(node, AttrAngle2Value, pathNode.Angle2());
704 
705         SetAttribute(node, AttrLength1, pathNode.Length1Formula());
706         SetAttribute(node, AttrLength1Value, VAbstractValApplication::VApp()->fromPixel(pathNode.Length1()));
707 
708         SetAttribute(node, AttrLength2, pathNode.Length2Formula());
709         SetAttribute(node, AttrLength2Value, VAbstractValApplication::VApp()->fromPixel(pathNode.Length2()));
710 
711         nodes.appendChild(node);
712     }
713 
714     step.appendChild(nodes);
715 
716     CurveAttributes(step, tool);
717 
718     return step;
719 }
720 
721 //---------------------------------------------------------------------------------------------------------------------
CubicBezierPath(const VToolRecord & record)722 QDomElement VPatternRecipe::CubicBezierPath(const VToolRecord &record)
723 {
724     auto *tool = GetPatternTool<VToolCubicBezierPath>(record.getId());
725     VCubicBezierPath spl = tool->getSplinePath();
726 
727     QDomElement step = createElement(TagStep);
728 
729     ToolAttributes(step, tool);
730 
731     QDomElement nodes = createElement(QStringLiteral("nodes"));
732     QVector<VSplinePoint> path = spl.GetSplinePath();
733 
734     if (path.isEmpty())
735     {
736         throw VExceptionInvalidHistory(QObject::tr("Empty list of nodes for tool with id '%1'.").arg(record.getId()));
737     }
738 
739     for (auto &pathNode : path)
740     {
741         QDomElement node = createElement(QStringLiteral("node"));
742 
743         SetAttribute(node, AttrPSpline, pathNode.P().name());
744 
745         nodes.appendChild(node);
746     }
747 
748     step.appendChild(nodes);
749 
750     CurveAttributes(step, tool);
751 
752     return step;
753 }
754 
755 //---------------------------------------------------------------------------------------------------------------------
PointOfContact(const VToolRecord & record)756 QDomElement VPatternRecipe::PointOfContact(const VToolRecord &record)
757 {
758     auto *tool = GetPatternTool<VToolPointOfContact>(record.getId());
759 
760     QDomElement step = createElement(TagStep);
761 
762     ToolAttributes(step, tool);
763     SetAttribute(step, AttrCenter, tool->ArcCenterPointName());
764     SetAttribute(step, AttrFirstPoint, tool->FirstPointName());
765     SetAttribute(step, AttrSecondPoint, tool->SecondPointName());
766     Formula(step, tool->getArcRadius(), AttrRadius, AttrRadiusValue);
767 
768     return step;
769 }
770 
771 //---------------------------------------------------------------------------------------------------------------------
Height(const VToolRecord & record)772 QDomElement VPatternRecipe::Height(const VToolRecord &record)
773 {
774     auto *tool = GetPatternTool<VToolHeight>(record.getId());
775 
776     QDomElement step = createElement(TagStep);
777 
778     ToolAttributes(step, tool);
779     SetAttribute(step, AttrBasePoint, tool->BasePointName());
780     SetAttribute(step, AttrP1Line, tool->FirstLinePointName());
781     SetAttribute(step, AttrP2Line, tool->SecondLinePointName());
782     LineAttributes(step, tool);
783 
784     return step;
785 }
786 
787 //---------------------------------------------------------------------------------------------------------------------
Triangle(const VToolRecord & record)788 QDomElement VPatternRecipe::Triangle(const VToolRecord &record)
789 {
790     auto *tool = GetPatternTool<VToolTriangle>(record.getId());
791 
792     QDomElement step = createElement(TagStep);
793 
794     ToolAttributes(step, tool);
795     SetAttribute(step, AttrAxisP1, tool->AxisP1Name());
796     SetAttribute(step, AttrAxisP2, tool->AxisP2Name());
797     SetAttribute(step, AttrFirstPoint, tool->FirstPointName());
798     SetAttribute(step, AttrSecondPoint, tool->SecondPointName());
799 
800     return step;
801 }
802 
803 //---------------------------------------------------------------------------------------------------------------------
PointOfIntersection(const VToolRecord & record)804 QDomElement VPatternRecipe::PointOfIntersection(const VToolRecord &record)
805 {
806     auto *tool = GetPatternTool<VToolPointOfIntersection>(record.getId());
807 
808     QDomElement step = createElement(TagStep);
809 
810     ToolAttributes(step, tool);
811     SetAttribute(step, AttrFirstPoint, tool->FirstPointName());
812     SetAttribute(step, AttrSecondPoint, tool->SecondPointName());
813 
814     return step;
815 }
816 
817 //---------------------------------------------------------------------------------------------------------------------
CutArc(const VToolRecord & record)818 QDomElement VPatternRecipe::CutArc(const VToolRecord &record)
819 {
820     auto *tool = GetPatternTool<VToolCutArc>(record.getId());
821 
822     QDomElement step = createElement(TagStep);
823 
824     ToolAttributes(step, tool);
825     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
826     SetAttribute(step, AttrArc, tool->CurveName());
827 
828     CutCurveAttributes(step, tool);
829 
830     return step;
831 }
832 
833 //---------------------------------------------------------------------------------------------------------------------
CutSpline(const VToolRecord & record)834 QDomElement VPatternRecipe::CutSpline(const VToolRecord &record)
835 {
836     auto *tool = GetPatternTool<VToolCutSpline>(record.getId());
837 
838     QDomElement step = createElement(TagStep);
839 
840     ToolAttributes(step, tool);
841     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
842     SetAttribute(step, VToolCutSpline::AttrSpline, tool->CurveName());
843 
844     CutCurveAttributes(step, tool);
845 
846     return step;
847 }
848 
849 //---------------------------------------------------------------------------------------------------------------------
CutSplinePath(const VToolRecord & record)850 QDomElement VPatternRecipe::CutSplinePath(const VToolRecord &record)
851 {
852     auto *tool = GetPatternTool<VToolCutSplinePath>(record.getId());
853 
854     QDomElement step = createElement(TagStep);
855 
856     ToolAttributes(step, tool);
857     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
858     SetAttribute(step, VToolCutSplinePath::AttrSplinePath, tool->CurveName());
859 
860     CutCurveAttributes(step, tool);
861 
862     return step;
863 }
864 
865 //---------------------------------------------------------------------------------------------------------------------
LineIntersectAxis(const VToolRecord & record)866 QDomElement VPatternRecipe::LineIntersectAxis(const VToolRecord &record)
867 {
868     auto *tool = GetPatternTool<VToolLineIntersectAxis>(record.getId());
869 
870     QDomElement step = createElement(TagStep);
871 
872     ToolAttributes(step, tool);
873     SetAttribute(step, AttrBasePoint, tool->BasePointName());
874     SetAttribute(step, AttrP1Line, tool->FirstLinePoint());
875     SetAttribute(step, AttrP2Line, tool->SecondLinePoint());
876     Formula(step, tool->GetFormulaAngle(), AttrAngle, AttrAngleValue);
877     LineAttributes(step, tool);
878 
879     return step;
880 }
881 
882 //---------------------------------------------------------------------------------------------------------------------
CurveIntersectAxis(const VToolRecord & record)883 QDomElement VPatternRecipe::CurveIntersectAxis(const VToolRecord &record)
884 {
885     auto *tool = GetPatternTool<VToolCurveIntersectAxis>(record.getId());
886 
887     QDomElement step = createElement(TagStep);
888 
889     ToolAttributes(step, tool);
890     SetAttribute(step, AttrBasePoint, tool->BasePointName());
891     SetAttribute(step, AttrCurve, tool->CurveName());
892     Formula(step, tool->GetFormulaAngle(), AttrAngle, AttrAngleValue);
893     LineAttributes(step, tool);
894 
895     return step;
896 }
897 
898 //---------------------------------------------------------------------------------------------------------------------
PointOfIntersectionArcs(const VToolRecord & record)899 QDomElement VPatternRecipe::PointOfIntersectionArcs(const VToolRecord &record)
900 {
901     auto *tool = GetPatternTool<VToolPointOfIntersectionArcs>(record.getId());
902 
903     QDomElement step = createElement(TagStep);
904 
905     ToolAttributes(step, tool);
906     SetAttribute(step, AttrFirstArc, tool->FirstArcName());
907     SetAttribute(step, AttrSecondArc, tool->SecondArcName());
908     SetAttribute(step, AttrCrossPoint, static_cast<int>(tool->GetCrossCirclesPoint()));
909 
910     return step;
911 }
912 
913 //---------------------------------------------------------------------------------------------------------------------
PointOfIntersectionCircles(const VToolRecord & record)914 QDomElement VPatternRecipe::PointOfIntersectionCircles(const VToolRecord &record)
915 {
916     auto *tool = GetPatternTool<VToolPointOfIntersectionCircles>(record.getId());
917 
918     QDomElement step = createElement(TagStep);
919 
920     ToolAttributes(step, tool);
921     SetAttribute(step, AttrC1Center, tool->FirstCircleCenterPointName());
922     SetAttribute(step, AttrC2Center, tool->SecondCircleCenterPointName());
923     Formula(step, tool->GetFirstCircleRadius(), AttrC1Radius, AttrC1RadiusValue);
924     Formula(step, tool->GetSecondCircleRadius(), AttrC2Radius, AttrC2RadiusValue);
925     SetAttribute(step, AttrCrossPoint, static_cast<int>(tool->GetCrossCirclesPoint()));
926 
927     return step;
928 }
929 
930 //---------------------------------------------------------------------------------------------------------------------
PointOfIntersectionCurves(const VToolRecord & record)931 QDomElement VPatternRecipe::PointOfIntersectionCurves(const VToolRecord &record)
932 {
933     auto *tool = GetPatternTool<VToolPointOfIntersectionCurves>(record.getId());
934 
935     QDomElement step = createElement(TagStep);
936 
937     ToolAttributes(step, tool);
938     SetAttribute(step, AttrCurve1, tool->FirstCurveName());
939     SetAttribute(step, AttrCurve2, tool->SecondCurveName());
940     SetAttribute(step, AttrVCrossPoint, static_cast<int>(tool->GetVCrossPoint()));
941     SetAttribute(step, AttrHCrossPoint, static_cast<int>(tool->GetHCrossPoint()));
942 
943     return step;
944 }
945 
946 //---------------------------------------------------------------------------------------------------------------------
PointFromCircleAndTangent(const VToolRecord & record)947 QDomElement VPatternRecipe::PointFromCircleAndTangent(const VToolRecord &record)
948 {
949     auto *tool = GetPatternTool<VToolPointFromCircleAndTangent>(record.getId());
950 
951     QDomElement step = createElement(TagStep);
952 
953     ToolAttributes(step, tool);
954     SetAttribute(step, AttrCCenter, tool->CircleCenterPointName());
955     SetAttribute(step, AttrTangent, tool->TangentPointName());
956     Formula(step, tool->GetCircleRadius(), AttrCRadius, AttrCRadiusValue);
957     SetAttribute(step, AttrCrossPoint, static_cast<int>(tool->GetCrossCirclesPoint()));
958 
959     return step;
960 }
961 
962 //---------------------------------------------------------------------------------------------------------------------
PointFromArcAndTangent(const VToolRecord & record)963 QDomElement VPatternRecipe::PointFromArcAndTangent(const VToolRecord &record)
964 {
965     auto *tool = GetPatternTool<VToolPointFromArcAndTangent>(record.getId());
966 
967     QDomElement step = createElement(TagStep);
968 
969     ToolAttributes(step, tool);
970     SetAttribute(step, AttrArc, tool->ArcName());
971     SetAttribute(step, AttrTangent, tool->TangentPointName());
972     SetAttribute(step, AttrCrossPoint, static_cast<int>(tool->GetCrossCirclesPoint()));
973 
974     return step;
975 }
976 
977 //---------------------------------------------------------------------------------------------------------------------
TrueDarts(const VToolRecord & record)978 QDomElement VPatternRecipe::TrueDarts(const VToolRecord &record)
979 {
980     auto *tool = GetPatternTool<VToolTrueDarts>(record.getId());
981 
982     QDomElement step = createElement(TagStep);
983 
984     SetAttribute(step, AttrType, VToolTrueDarts::ToolType);
985     SetAttribute(step, AttrPoint1, tool->nameP1());
986     SetAttribute(step, AttrPoint2, tool->nameP2());
987     SetAttribute(step, AttrBaseLineP1, tool->BaseLineP1Name());
988     SetAttribute(step, AttrBaseLineP2, tool->BaseLineP2Name());
989     SetAttribute(step, AttrDartP1, tool->DartP1Name());
990     SetAttribute(step, AttrDartP2, tool->DartP2Name());
991     SetAttribute(step, AttrDartP3, tool->DartP3Name());
992 
993     return step;
994 }
995 
996 //---------------------------------------------------------------------------------------------------------------------
EllipticalArc(const VToolRecord & record)997 QDomElement VPatternRecipe::EllipticalArc(const VToolRecord &record)
998 {
999     auto *tool = GetPatternTool<VToolEllipticalArc>(record.getId());
1000 
1001     QDomElement step = createElement(TagStep);
1002 
1003     SetAttribute(step, AttrType, QStringLiteral("ellipticalArc"));
1004     SetAttribute(step, AttrLabel, tool->name());
1005 
1006     SetAttribute(step, AttrCenter, tool->CenterPointName());
1007     Formula(step, tool->GetFormulaRadius1(), AttrRadius1, AttrRadius1Value);
1008     Formula(step, tool->GetFormulaRadius2(), AttrRadius2, AttrRadius2Value);
1009     Formula(step, tool->GetFormulaF1(), AttrAngle1, AttrAngle1Value);
1010     Formula(step, tool->GetFormulaF2(), AttrAngle2, AttrAngle2Value);
1011     Formula(step, tool->GetFormulaRotationAngle(), AttrRotationAngle, AttrRotationAngleValue);
1012 
1013     CurveAttributes(step, tool);
1014 
1015     return step;
1016 }
1017 
1018 //---------------------------------------------------------------------------------------------------------------------
Rotation(const VToolRecord & record,const VContainer & data)1019 QDomElement VPatternRecipe::Rotation(const VToolRecord &record, const VContainer &data)
1020 {
1021     auto *tool = GetPatternTool<VToolRotation>(record.getId());
1022 
1023     QDomElement step = createElement(TagStep);
1024 
1025     SetAttribute(step, AttrType, VToolRotation::ToolType);
1026     SetAttribute(step, AttrCenter, tool->OriginPointName());
1027     Formula(step, tool->GetFormulaAngle(), AttrAngle, AttrAngleValue);
1028     SetAttribute(step, AttrSuffix, tool->Suffix());
1029 
1030     step.appendChild(GroupOperationSource(tool, record.getId(), data));
1031 
1032     return step;
1033 }
1034 
1035 //---------------------------------------------------------------------------------------------------------------------
FlippingByLine(const VToolRecord & record,const VContainer & data)1036 QDomElement VPatternRecipe::FlippingByLine(const VToolRecord &record, const VContainer &data)
1037 {
1038     auto *tool = GetPatternTool<VToolFlippingByLine>(record.getId());
1039 
1040     QDomElement step = createElement(TagStep);
1041 
1042     SetAttribute(step, AttrType, VToolFlippingByLine::ToolType);
1043     SetAttribute(step, AttrP1Line, tool->FirstLinePointName());
1044     SetAttribute(step, AttrP2Line, tool->SecondLinePointName());
1045     SetAttribute(step, AttrSuffix, tool->Suffix());
1046 
1047     step.appendChild(GroupOperationSource(tool, record.getId(), data));
1048 
1049     return step;
1050 }
1051 
1052 //---------------------------------------------------------------------------------------------------------------------
FlippingByAxis(const VToolRecord & record,const VContainer & data)1053 QDomElement VPatternRecipe::FlippingByAxis(const VToolRecord &record, const VContainer &data)
1054 {
1055     auto *tool = GetPatternTool<VToolFlippingByAxis>(record.getId());
1056 
1057     QDomElement step = createElement(TagStep);
1058 
1059     SetAttribute(step, AttrType, VToolFlippingByAxis::ToolType);
1060     SetAttribute(step, AttrCenter, tool->OriginPointName());
1061     SetAttribute(step, AttrAxisType, static_cast<int>(tool->GetAxisType()));
1062     SetAttribute(step, AttrSuffix, tool->Suffix());
1063 
1064     step.appendChild(GroupOperationSource(tool, record.getId(), data));
1065 
1066     return step;
1067 }
1068 
1069 //---------------------------------------------------------------------------------------------------------------------
Move(const VToolRecord & record,const VContainer & data)1070 QDomElement VPatternRecipe::Move(const VToolRecord &record, const VContainer &data)
1071 {
1072     auto *tool = GetPatternTool<VToolMove>(record.getId());
1073 
1074     QDomElement step = createElement(TagStep);
1075 
1076     SetAttribute(step, AttrType, VToolMove::ToolType);
1077     Formula(step, tool->GetFormulaAngle(), AttrAngle, AttrAngleValue);
1078     Formula(step, tool->GetFormulaRotationAngle(), AttrRotationAngle, AttrRotationAngleValue);
1079     Formula(step, tool->GetFormulaLength(), AttrLength, AttrLengthValue);
1080     SetAttribute(step, AttrCenter, tool->OriginPointName());
1081     SetAttribute(step, AttrSuffix, tool->Suffix());
1082 
1083     step.appendChild(GroupOperationSource(tool, record.getId(), data));
1084 
1085     return step;
1086 }
1087 
1088 //---------------------------------------------------------------------------------------------------------------------
Formula(QDomElement & step,const VFormula & formula,const QString & formulaStr,const QString & formulaValue)1089 inline void VPatternRecipe::Formula(QDomElement &step, const VFormula &formula, const QString &formulaStr,
1090                              const QString &formulaValue)
1091 {
1092     if (formula.error())
1093     {
1094         throw VExceptionInvalidHistory(QObject::tr("Invalid formula '%1' for tool with id '%2'. %3.")
1095                                        .arg(formula.GetFormula(FormulaType::ToSystem))
1096                                        .arg(formula.getToolId())
1097                                        .arg(formula.Reason()));
1098     }
1099 
1100     SetAttribute(step, formulaStr, formula.GetFormula(FormulaType::ToSystem));
1101     SetAttribute(step, formulaValue, formula.getDoubleValue());
1102 }
1103 
1104 //---------------------------------------------------------------------------------------------------------------------
1105 template<typename T>
LineAttributes(QDomElement & step,T * tool)1106 inline void VPatternRecipe::LineAttributes(QDomElement &step, T *tool)
1107 {
1108     SetAttribute(step, AttrLineColor, tool->GetLineColor());
1109     SetAttribute(step, AttrTypeLine, tool->getLineType());
1110 }
1111 
1112 //---------------------------------------------------------------------------------------------------------------------
1113 template<typename T>
CurveAttributes(QDomElement & step,T * tool)1114 void VPatternRecipe::CurveAttributes(QDomElement &step, T *tool)
1115 {
1116     SetAttribute(step, AttrLineColor, tool->GetLineColor());
1117     SetAttribute(step, AttrPenStyle, tool->GetPenStyle());
1118     SetAttribute(step, AttrAScale, tool->GetApproximationScale());
1119     SetAttribute(step, AttrDuplicate, tool->GetDuplicate());
1120     SetAttributeOrRemoveIf(step, AttrAlias, tool->GetAliasSuffix(), tool->GetAliasSuffix().isEmpty());
1121 }
1122 
1123 
1124 //---------------------------------------------------------------------------------------------------------------------
1125 template<typename T>
CutCurveAttributes(QDomElement & step,T * tool)1126 void VPatternRecipe::CutCurveAttributes(QDomElement &step, T *tool)
1127 {
1128     SetAttributeOrRemoveIf(step, AttrAlias1, tool->GetAliasSuffix1(), tool->GetAliasSuffix1().isEmpty());
1129     SetAttributeOrRemoveIf(step, AttrAlias2, tool->GetAliasSuffix2(), tool->GetAliasSuffix2().isEmpty());
1130 }
1131 
1132 //---------------------------------------------------------------------------------------------------------------------
1133 template<typename T>
ToolAttributes(QDomElement & step,T * tool)1134 inline void VPatternRecipe::ToolAttributes(QDomElement &step, T *tool)
1135 {
1136     SetAttribute(step, AttrType, T::ToolType);
1137     SetAttribute(step, AttrLabel, tool->name());
1138     SetAttribute(step, AttrNotes, tool->GetNotes());
1139 }
1140 
1141 //---------------------------------------------------------------------------------------------------------------------
GroupOperationSource(VAbstractOperation * tool,quint32 id,const VContainer & data)1142 QDomElement VPatternRecipe::GroupOperationSource(VAbstractOperation *tool, quint32 id, const VContainer &data)
1143 {
1144     SCASSERT(tool)
1145 
1146     QDomElement nodes = createElement(QStringLiteral("nodes"));
1147     QVector<SourceItem> items = tool->SourceItems();
1148 
1149     if (items.isEmpty())
1150     {
1151         throw VExceptionInvalidHistory(QObject::tr("Empty list of nodes for tool with id '%1'.").arg(id));
1152     }
1153 
1154     for (auto &item : items)
1155     {
1156         QDomElement node = createElement(QStringLiteral("node"));
1157 
1158         QSharedPointer<VGObject> obj;
1159 
1160         try
1161         {
1162             obj = data.GetGObject(item.id);
1163         }
1164         catch (const VExceptionBadId &e)
1165         {
1166             qCritical() << e.ErrorMessage()<<Q_FUNC_INFO;
1167             continue;
1168         }
1169 
1170         SetAttribute(node, AttrItem, obj->ObjectName());
1171         SetAttributeOrRemoveIf(node, AttrAlias, item.alias, item.alias.isEmpty());
1172 
1173         if (obj->getType() != GOType::Point)
1174         {
1175             if (item.penStyle != TypeLineDefault)
1176             {
1177                 SetAttribute(node, AttrPenStyle, item.penStyle);
1178             }
1179 
1180             if (item.color != ColorDefault)
1181             {
1182                 SetAttribute(node, AttrColor, item.color);
1183             }
1184         }
1185 
1186         QT_WARNING_PUSH
1187         QT_WARNING_DISABLE_GCC("-Wswitch-default")
1188         switch(static_cast<GOType>(obj->getType()))
1189         {
1190             case GOType::Point:
1191                 SetAttribute(node, AttrType, QStringLiteral("point"));
1192                 break;
1193             case GOType::Arc:
1194                 SetAttribute(node, AttrType, QStringLiteral("arc"));
1195                 break;
1196             case GOType::EllipticalArc:
1197                 SetAttribute(node, AttrType, QStringLiteral("elArc"));
1198                 break;
1199             case GOType::Spline:
1200             case GOType::CubicBezier:
1201                 SetAttribute(node, AttrType, QStringLiteral("spline"));
1202                 break;
1203             case GOType::SplinePath:
1204             case GOType::CubicBezierPath:
1205                 SetAttribute(node, AttrType, QStringLiteral("splinePath"));
1206                 break;
1207             case GOType::Unknown:
1208             case GOType::PlaceLabel:
1209                 Q_UNREACHABLE();
1210                 break;
1211         }
1212         QT_WARNING_POP
1213 
1214         nodes.appendChild(node);
1215     }
1216 
1217     return nodes;
1218 }
1219