1 /************************************************************************
2  **
3  **  @file   vtoolcutsplinepath.cpp
4  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
5  **  @date   15 12, 2013
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) 2013-2015 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 "vtoolcutsplinepath.h"
30 
31 #include <QPointF>
32 #include <QSharedPointer>
33 #include <QStaticStringData>
34 #include <QStringData>
35 #include <QStringDataPtr>
36 #include <QVector>
37 #include <new>
38 
39 #include "../../../../../dialogs/tools/dialogcutsplinepath.h"
40 #include "../../../../../dialogs/tools/dialogtool.h"
41 #include "../../../../../visualization/visualization.h"
42 #include "../../../../../visualization/path/vistoolcutsplinepath.h"
43 #include "../ifc/exception/vexception.h"
44 #include "../ifc/ifcdef.h"
45 #include "../vgeometry/vabstractcubicbezierpath.h"
46 #include "../vgeometry/vabstractcurve.h"
47 #include "../vgeometry/vpointf.h"
48 #include "../vgeometry/vspline.h"
49 #include "../vgeometry/vsplinepath.h"
50 #include "../vgeometry/vsplinepoint.h"
51 #include "../vmisc/vabstractapplication.h"
52 #include "../vmisc/vcommonsettings.h"
53 #include "../vpatterndb/vcontainer.h"
54 #include "../vpatterndb/vtranslatevars.h"
55 #include "../vwidgets/vmaingraphicsscene.h"
56 #include "../../../../vabstracttool.h"
57 #include "../../../vdrawtool.h"
58 #include "vtoolcut.h"
59 
60 template <class T> class QSharedPointer;
61 
62 const QString VToolCutSplinePath::ToolType       = QStringLiteral("cutSplinePath");
63 const QString VToolCutSplinePath::AttrSplinePath = QStringLiteral("splinePath");
64 
65 //---------------------------------------------------------------------------------------------------------------------
66 /**
67  * @brief VToolCutSplinePath constructor.
68  * @param initData init data.
69  * @param parent parent object.
70  */
VToolCutSplinePath(const VToolCutInitData & initData,QGraphicsItem * parent)71 VToolCutSplinePath::VToolCutSplinePath(const VToolCutInitData &initData, QGraphicsItem *parent)
72     :VToolCut(initData, parent)
73 {
74     ToolCreation(initData.typeCreation);
75 }
76 
77 //---------------------------------------------------------------------------------------------------------------------
78 /**
79  * @brief setDialog set dialog when user want change tool option.
80  */
setDialog()81 void VToolCutSplinePath::setDialog()
82 {
83     SCASSERT(not m_dialog.isNull())
84     const QPointer<DialogCutSplinePath> dialogTool = qobject_cast<DialogCutSplinePath *>(m_dialog);
85     SCASSERT(not dialogTool.isNull())
86     const QSharedPointer<VPointF> point = VAbstractTool::data.GeometricObject<VPointF>(m_id);
87     dialogTool->SetFormula(formula);
88     dialogTool->setSplinePathId(baseCurveId);
89     dialogTool->SetPointName(point->name());
90     dialogTool->SetNotes(m_notes);
91     dialogTool->SetAliasSuffix1(m_aliasSuffix1);
92     dialogTool->SetAliasSuffix2(m_aliasSuffix2);
93 }
94 
95 //---------------------------------------------------------------------------------------------------------------------
96 /**
97  * @brief Create help create tool form GUI.
98  * @param dialog dialog.
99  * @param scene pointer to scene.
100  * @param doc dom document container.
101  * @param data container with variables.
102  */
Create(const QPointer<DialogTool> & dialog,VMainGraphicsScene * scene,VAbstractPattern * doc,VContainer * data)103 VToolCutSplinePath* VToolCutSplinePath::Create(const QPointer<DialogTool> &dialog, VMainGraphicsScene *scene,
104                                                VAbstractPattern *doc, VContainer *data)
105 {
106     SCASSERT(not dialog.isNull())
107     const QPointer<DialogCutSplinePath> dialogTool = qobject_cast<DialogCutSplinePath *>(dialog);
108     SCASSERT(not dialogTool.isNull())
109 
110     VToolCutInitData initData;
111     initData.formula = dialogTool->GetFormula();
112     initData.baseCurveId = dialogTool->getSplinePathId();
113     initData.name = dialogTool->GetPointName();
114     initData.scene = scene;
115     initData.doc = doc;
116     initData.data = data;
117     initData.parse = Document::FullParse;
118     initData.typeCreation = Source::FromGui;
119     initData.notes = dialogTool->GetNotes();
120     initData.aliasSuffix1 = dialogTool->GetAliasSuffix1();
121     initData.aliasSuffix2 = dialogTool->GetAliasSuffix2();
122 
123     VToolCutSplinePath* point = Create(initData);
124     if (point != nullptr)
125     {
126         point->m_dialog = dialog;
127     }
128     return point;
129 }
130 
131 //---------------------------------------------------------------------------------------------------------------------
132 /**
133  * @brief Create help create tool.
134  * @param initData init data.
135  */
Create(VToolCutInitData & initData)136 VToolCutSplinePath* VToolCutSplinePath::Create(VToolCutInitData &initData)
137 {
138     const auto splPath = initData.data->GeometricObject<VAbstractCubicBezierPath>(initData.baseCurveId);
139     SCASSERT(splPath != nullptr)
140 
141     //Declare special variable "CurrentLength"
142     VCurveLength *length = new VCurveLength(initData.baseCurveId, initData.baseCurveId, splPath.data(),
143                                             *initData.data->GetPatternUnit());
144     length->SetName(currentLength);
145     initData.data->AddVariable(length);
146 
147     const qreal result = CheckFormula(initData.id, initData.formula, initData.data);
148 
149     VSplinePath *splPath1 = nullptr;
150     VSplinePath *splPath2 = nullptr;
151     VPointF *p = VToolCutSplinePath::CutSplinePath(
152                 VAbstractValApplication::VApp()->toPixel(result), splPath, initData.name, &splPath1, &splPath2);
153 
154     SCASSERT(splPath1 != nullptr)
155     SCASSERT(splPath2 != nullptr)
156     SCASSERT(p != nullptr)
157 
158     p->setMx(initData.mx);
159     p->setMy(initData.my);
160     p->SetShowLabel(initData.showLabel);
161 
162     splPath1->SetAliasSuffix(initData.aliasSuffix1);
163     splPath2->SetAliasSuffix(initData.aliasSuffix2);
164 
165     if (initData.typeCreation == Source::FromGui)
166     {
167         initData.id = initData.data->AddGObject(p);
168 
169         auto path1 = QSharedPointer<VAbstractBezier>(splPath1);
170         initData.data->AddSpline(path1, NULL_ID, initData.id);
171         initData.data->RegisterUniqueName(path1);
172 
173         auto path2 = QSharedPointer<VAbstractBezier>(splPath2);
174         initData.data->AddSpline(path2, NULL_ID, initData.id);
175         initData.data->RegisterUniqueName(path2);
176     }
177     else
178     {
179         initData.data->UpdateGObject(initData.id, p);
180 
181         auto path1 = QSharedPointer<VAbstractBezier>(splPath1);
182         initData.data->AddSpline(path1, NULL_ID, initData.id);
183         initData.data->RegisterUniqueName(path1);
184 
185         auto path2 = QSharedPointer<VAbstractBezier>(splPath2);
186         initData.data->AddSpline(path2, NULL_ID, initData.id);
187         initData.data->RegisterUniqueName(path2);
188 
189         if (initData.parse != Document::FullParse)
190         {
191             initData.doc->UpdateToolData(initData.id, initData.data);
192         }
193     }
194 
195     VToolCutSplinePath *tool = nullptr;
196     if (initData.parse == Document::FullParse)
197     {
198         VAbstractTool::AddRecord(initData.id, Tool::CutSplinePath, initData.doc);
199         tool = new VToolCutSplinePath(initData);
200         initData.scene->addItem(tool);
201         InitToolConnections(initData.scene, tool);
202         VAbstractPattern::AddTool(initData.id, tool);
203         initData.doc->IncrementReferens(splPath->getIdTool());
204     }
205     //Very important to delete it. Only this tool need this special variable.
206     initData.data->RemoveVariable(currentLength);
207     return tool;
208 }
209 
210 //---------------------------------------------------------------------------------------------------------------------
ShowVisualization(bool show)211 void VToolCutSplinePath::ShowVisualization(bool show)
212 {
213     ShowToolVisualization<VisToolCutSplinePath>(show);
214 }
215 
216 //---------------------------------------------------------------------------------------------------------------------
CutSplinePath(qreal length,const QSharedPointer<VAbstractCubicBezierPath> & splPath,const QString & pName,VSplinePath ** splPath1,VSplinePath ** splPath2)217 VPointF *VToolCutSplinePath::CutSplinePath(qreal length, const QSharedPointer<VAbstractCubicBezierPath> &splPath,
218                                            const QString &pName, VSplinePath **splPath1, VSplinePath **splPath2)
219 {
220     SCASSERT(splPath != nullptr)
221 
222     QPointF spl1p2, spl1p3, spl2p2, spl2p3;
223     qint32 p1 = 0, p2 = 0;
224 
225     const QPointF point = splPath->CutSplinePath(length, p1, p2, spl1p2, spl1p3, spl2p2, spl2p3);
226     VPointF *p = new VPointF(point);
227     p->setName(pName);
228 
229     const QVector<VSplinePoint> points = splPath->GetSplinePath();
230 
231     const VSplinePoint splP1 = points.at(p1);
232     const VSplinePoint splP2 = points.at(p2);
233 
234     VSpline spl1 = VSpline(splP1.P(), spl1p2, spl1p3, *p);
235     spl1.SetApproximationScale(splPath->GetApproximationScale());
236 
237     VSpline spl2 = VSpline(*p, spl2p2, spl2p3, splP2.P());
238     spl2.SetApproximationScale(splPath->GetApproximationScale());
239 
240     *splPath1 = new VSplinePath();
241     (*splPath1)->SetApproximationScale(splPath->GetApproximationScale());
242     *splPath2 = new VSplinePath();
243     (*splPath2)->SetApproximationScale(splPath->GetApproximationScale());
244 
245     for (qint32 i = 0; i < points.size(); i++)
246     {
247         if (i <= p1 && i < p2)
248         {
249             if (i == p1)
250             {
251                 const qreal angle1 = spl1.GetStartAngle()+180;
252                 const QString angle1F = QString().number(angle1);
253 
254                 (*splPath1)->append(VSplinePoint(splP1.P(), angle1, angle1F, spl1.GetStartAngle(),
255                                                  spl1.GetStartAngleFormula(), splP1.Length1(), splP1.Length1Formula(),
256                                                  spl1.GetC1Length(), spl1.GetC1LengthFormula()));
257 
258                 const qreal angle2 = spl1.GetEndAngle()+180;
259                 const QString angle2F = QString().number(angle2);
260 
261                 const auto cutPoint = VSplinePoint(*p, spl1.GetEndAngle(), spl1.GetEndAngleFormula(), angle2, angle2F,
262                                                    spl1.GetC2Length(), spl1.GetC2LengthFormula(), spl2.GetC1Length(),
263                                                    spl2.GetC1LengthFormula());
264                 (*splPath1)->append(cutPoint);
265                 continue;
266             }
267             (*splPath1)->append(points.at(i));
268         }
269         else
270         {
271             if (i == p2)
272             {
273                 const qreal angle1 = spl2.GetStartAngle()+180;
274                 const QString angle1F = QString().number(angle1);
275 
276                 const auto cutPoint = VSplinePoint(*p, angle1, angle1F, spl2.GetStartAngle(),
277                                                    spl2.GetStartAngleFormula(), spl1.GetC2Length(),
278                                                    spl1.GetC2LengthFormula(), spl2.GetC1Length(),
279                                                    spl2.GetC1LengthFormula());
280 
281                 (*splPath2)->append(cutPoint);
282 
283                 const qreal angle2 = spl2.GetEndAngle()+180;
284                 const QString angle2F = QString().number(angle2);
285 
286                 (*splPath2)->append(VSplinePoint(splP2.P(), spl2.GetEndAngle(), spl2.GetEndAngleFormula(), angle2,
287                                                  angle2F, spl2.GetC2Length(), spl2.GetC2LengthFormula(),
288                                                  splP2.Length2(), splP2.Length2Formula()));
289                 continue;
290             }
291             (*splPath2)->append(points.at(i));
292         }
293     }
294 
295     return p;
296 }
297 
298 //---------------------------------------------------------------------------------------------------------------------
ShowContextMenu(QGraphicsSceneContextMenuEvent * event,quint32 id)299 void VToolCutSplinePath::ShowContextMenu(QGraphicsSceneContextMenuEvent *event, quint32 id)
300 {
301     try
302     {
303         ContextMenu<DialogCutSplinePath>(event, id);
304     }
305     catch(const VExceptionToolWasDeleted &e)
306     {
307         Q_UNUSED(e)
308         return;//Leave this method immediately!!!
309     }
310 }
311 
312 //---------------------------------------------------------------------------------------------------------------------
313 /**
314  * @brief SaveDialog save options into file after change in dialog.
315  */
SaveDialog(QDomElement & domElement,QList<quint32> & oldDependencies,QList<quint32> & newDependencies)316 void VToolCutSplinePath::SaveDialog(QDomElement &domElement, QList<quint32> &oldDependencies,
317                                     QList<quint32> &newDependencies)
318 {
319     SCASSERT(not m_dialog.isNull())
320     const QPointer<DialogCutSplinePath> dialogTool = qobject_cast<DialogCutSplinePath *>(m_dialog);
321     SCASSERT(not dialogTool.isNull())
322 
323     AddDependence(oldDependencies, baseCurveId);
324     AddDependence(newDependencies, dialogTool->getSplinePathId());
325 
326     doc->SetAttribute(domElement, AttrName, dialogTool->GetPointName());
327     doc->SetAttribute(domElement, AttrLength, dialogTool->GetFormula());
328     doc->SetAttribute(domElement, AttrSplinePath, QString().setNum(dialogTool->getSplinePathId()));
329     doc->SetAttributeOrRemoveIf(domElement, AttrAlias1, dialogTool->GetAliasSuffix1(),
330                                 dialogTool->GetAliasSuffix1().isEmpty());
331     doc->SetAttributeOrRemoveIf(domElement, AttrAlias2, dialogTool->GetAliasSuffix2(),
332                                 dialogTool->GetAliasSuffix2().isEmpty());
333 
334     const QString notes = dialogTool->GetNotes();
335     doc->SetAttributeOrRemoveIf(domElement, AttrNotes, notes, notes.isEmpty());
336 }
337 
338 //---------------------------------------------------------------------------------------------------------------------
SaveOptions(QDomElement & tag,QSharedPointer<VGObject> & obj)339 void VToolCutSplinePath::SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj)
340 {
341     VToolCut::SaveOptions(tag, obj);
342 
343     doc->SetAttribute(tag, AttrType, ToolType);
344     doc->SetAttribute(tag, AttrLength, formula);
345     doc->SetAttribute(tag, AttrSplinePath, baseCurveId);
346 }
347 
348 //---------------------------------------------------------------------------------------------------------------------
ReadToolAttributes(const QDomElement & domElement)349 void VToolCutSplinePath::ReadToolAttributes(const QDomElement &domElement)
350 {
351     VToolCut::ReadToolAttributes(domElement);
352 
353     formula = doc->GetParametrString(domElement, AttrLength, QString());
354     baseCurveId = doc->GetParametrUInt(domElement, AttrSplinePath, NULL_ID_STR);
355 }
356 
357 //---------------------------------------------------------------------------------------------------------------------
SetVisualization()358 void VToolCutSplinePath::SetVisualization()
359 {
360     if (not vis.isNull())
361     {
362         VisToolCutSplinePath *visual = qobject_cast<VisToolCutSplinePath *>(vis);
363         SCASSERT(visual != nullptr)
364 
365         visual->setObject1Id(baseCurveId);
366         visual->setLength(VAbstractApplication::VApp()->TrVars()
367                           ->FormulaToUser(formula, VAbstractApplication::VApp()->Settings()->GetOsSeparator()));
368 
369         const QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(baseCurveId);
370         visual->setLineStyle(LineStyleToPenStyle(curve->GetPenStyle()));
371 
372         visual->RefreshGeometry();
373     }
374 }
375 
376 //---------------------------------------------------------------------------------------------------------------------
MakeToolTip() const377 QString VToolCutSplinePath::MakeToolTip() const
378 {
379     const auto splPath = VAbstractTool::data.GeometricObject<VAbstractCubicBezierPath>(baseCurveId);
380 
381     const QString expression = VAbstractApplication::VApp()->TrVars()
382             ->FormulaToUser(formula, VAbstractApplication::VApp()->Settings()->GetOsSeparator());
383     const qreal length = Visualization::FindValFromUser(expression, VAbstractTool::data.DataVariables());
384 
385     VSplinePath *splPath1 = nullptr;
386     VSplinePath *splPath2 = nullptr;
387     VPointF *p = VToolCutSplinePath::CutSplinePath(
388                 VAbstractValApplication::VApp()->toPixel(length), splPath, "X", &splPath1, &splPath2);
389     delete p; // Don't need this point
390 
391     splPath1->SetAliasSuffix(m_aliasSuffix1);
392     splPath2->SetAliasSuffix(m_aliasSuffix2);
393 
394     const QString curveStr = tr("Curve");
395     const QString lengthStr = tr("length");
396 
397     const QString toolTip = QString("<table>"
398                                     "<tr> <td><b>%6:</b> %7</td> </tr>"
399                                     "<tr> <td><b>%1:</b> %2 %3</td> </tr>"
400                                     "<tr> <td><b>%8:</b> %9</td> </tr>"
401                                     "<tr> <td><b>%4:</b> %5 %3</td> </tr>"
402                                     "</table>")
403             .arg(curveStr + QLatin1String("1 ") + lengthStr)
404             .arg(VAbstractValApplication::VApp()->fromPixel(splPath1->GetLength()))
405             .arg(UnitsToStr(VAbstractValApplication::VApp()->patternUnits(), true),
406                  curveStr + QLatin1String("2 ") + lengthStr)
407             .arg(VAbstractValApplication::VApp()->fromPixel(splPath2->GetLength()))
408             .arg(curveStr + QLatin1String(" 1") + tr("label"), splPath1->ObjectName(),
409                  curveStr + QLatin1String(" 2") + tr("label"), splPath2->ObjectName());
410 
411     delete splPath1;
412     delete splPath2;
413 
414     return toolTip;
415 }
416