1 /************************************************************************
2  **
3  **  @file   vtooltriangle.cpp
4  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
5  **  @date   November 15, 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 "vtooltriangle.h"
30 
31 #include <QLine>
32 #include <QLineF>
33 #include <QSharedPointer>
34 #include <QStaticStringData>
35 #include <QStringData>
36 #include <QStringDataPtr>
37 #include <new>
38 
39 #include "../../../../dialogs/tools/dialogtriangle.h"
40 #include "../../../../dialogs/tools/dialogtool.h"
41 #include "../../../../visualization/visualization.h"
42 #include "../../../../visualization/line/vistooltriangle.h"
43 #include "../ifc/exception/vexception.h"
44 #include "../ifc/exception/vexceptionobjecterror.h"
45 #include "../ifc/ifcdef.h"
46 #include "../vgeometry/vgobject.h"
47 #include "../vgeometry/vpointf.h"
48 #include "../vpatterndb/vcontainer.h"
49 #include "../vwidgets/vmaingraphicsscene.h"
50 #include "../../../vabstracttool.h"
51 #include "../../vdrawtool.h"
52 #include "vtoolsinglepoint.h"
53 #include "../vmisc/vmath.h"
54 #include "../vmisc/compatibility.h"
55 
56 template <class T> class QSharedPointer;
57 
58 const QString VToolTriangle::ToolType = QStringLiteral("triangle");
59 
60 //---------------------------------------------------------------------------------------------------------------------
61 /**
62  * @brief VToolTriangle constructor.
63  * @param initData init data.
64  * @param parent parent object.
65  */
VToolTriangle(const VToolTriangleInitData & initData,QGraphicsItem * parent)66 VToolTriangle::VToolTriangle(const VToolTriangleInitData &initData, QGraphicsItem *parent)
67     :VToolSinglePoint(initData.doc, initData.data, initData.id, initData.notes, parent),
68       axisP1Id(initData.axisP1Id),
69       axisP2Id(initData.axisP2Id),
70       firstPointId(initData.firstPointId),
71       secondPointId(initData.secondPointId)
72 {
73     ToolCreation(initData.typeCreation);
74 }
75 
76 //---------------------------------------------------------------------------------------------------------------------
77 /**
78  * @brief setDialog set dialog when user want change tool option.
79  */
setDialog()80 void VToolTriangle::setDialog()
81 {
82     SCASSERT(not m_dialog.isNull())
83     const QPointer<DialogTriangle> dialogTool = qobject_cast<DialogTriangle *>(m_dialog);
84     SCASSERT(not dialogTool.isNull())
85     const QSharedPointer<VPointF> p = VAbstractTool::data.GeometricObject<VPointF>(m_id);
86     dialogTool->SetAxisP1Id(axisP1Id);
87     dialogTool->SetAxisP2Id(axisP2Id);
88     dialogTool->SetFirstPointId(firstPointId);
89     dialogTool->SetSecondPointId(secondPointId);
90     dialogTool->SetPointName(p->name());
91     dialogTool->SetNotes(m_notes);
92 }
93 
94 //---------------------------------------------------------------------------------------------------------------------
95 /**
96  * @brief Create help create tool from GUI.
97  * @param dialog dialog.
98  * @param scene pointer to scene.
99  * @param doc dom document container.
100  * @param data container with variables.
101  * @return the created tool
102  */
Create(const QPointer<DialogTool> & dialog,VMainGraphicsScene * scene,VAbstractPattern * doc,VContainer * data)103 VToolTriangle* VToolTriangle::Create(const QPointer<DialogTool> &dialog, VMainGraphicsScene *scene,
104                                      VAbstractPattern *doc, VContainer *data)
105 {
106     SCASSERT(not dialog.isNull())
107     const QPointer<DialogTriangle> dialogTool = qobject_cast<DialogTriangle *>(dialog);
108     SCASSERT(not dialogTool.isNull())
109 
110     VToolTriangleInitData initData;
111     initData.axisP1Id = dialogTool->GetAxisP1Id();
112     initData.axisP2Id = dialogTool->GetAxisP2Id();
113     initData.firstPointId = dialogTool->GetFirstPointId();
114     initData.secondPointId = dialogTool->GetSecondPointId();
115     initData.name = dialogTool->GetPointName();
116     initData.scene = scene;
117     initData.doc = doc;
118     initData.data = data;
119     initData.parse = Document::FullParse;
120     initData.typeCreation = Source::FromGui;
121     initData.notes = dialogTool->GetNotes();
122 
123     VToolTriangle* point = Create(initData);
124     if (point != nullptr)
125     {
126         point->m_dialog = dialog;
127     }
128     return point;
129 }
130 
131 //---------------------------------------------------------------------------------------------------------------------
132 /**
133  * @brief Create helps to create the tool.
134  * @param initData init data.
135  * @return the created tool
136  */
Create(VToolTriangleInitData initData)137 VToolTriangle* VToolTriangle::Create(VToolTriangleInitData initData)
138 {
139     const QSharedPointer<VPointF> axisP1 = initData.data->GeometricObject<VPointF>(initData.axisP1Id);
140     const QSharedPointer<VPointF> axisP2 = initData.data->GeometricObject<VPointF>(initData.axisP2Id);
141     const QSharedPointer<VPointF> firstPoint = initData.data->GeometricObject<VPointF>(initData.firstPointId);
142     const QSharedPointer<VPointF> secondPoint = initData.data->GeometricObject<VPointF>(initData.secondPointId);
143 
144     QPointF point;
145     const bool success = FindPoint(static_cast<QPointF>(*axisP1), static_cast<QPointF>(*axisP2),
146                                    static_cast<QPointF>(*firstPoint), static_cast<QPointF>(*secondPoint), &point);
147 
148     if (not success)
149     {
150         const QString errorMsg = tr("Error calculating point '%1'. Point of intersection cannot be found")
151                       .arg(initData.name);
152         VAbstractApplication::VApp()->IsPedantic() ? throw VExceptionObjectError(errorMsg) :
153                                               qWarning() << VAbstractValApplication::warningMessageSignature + errorMsg;
154     }
155 
156     VPointF *p = new VPointF(point, initData.name, initData.mx, initData.my);
157     p->SetShowLabel(initData.showLabel);
158 
159     if (initData.typeCreation == Source::FromGui)
160     {
161         initData.id = initData.data->AddGObject(p);
162     }
163     else
164     {
165         initData.data->UpdateGObject(initData.id, p);
166         if (initData.parse != Document::FullParse)
167         {
168             initData.doc->UpdateToolData(initData.id, initData.data);
169         }
170     }
171 
172     if (initData.parse == Document::FullParse)
173     {
174         VAbstractTool::AddRecord(initData.id, Tool::Triangle, initData.doc);
175         VToolTriangle *point = new VToolTriangle(initData);
176         initData.scene->addItem(point);
177         InitToolConnections(initData.scene, point);
178         VAbstractPattern::AddTool(initData.id, point);
179         initData.doc->IncrementReferens(axisP1->getIdTool());
180         initData.doc->IncrementReferens(axisP2->getIdTool());
181         initData.doc->IncrementReferens(firstPoint->getIdTool());
182         initData.doc->IncrementReferens(secondPoint->getIdTool());
183         return point;
184     }
185     return nullptr;
186 }
187 
188 //---------------------------------------------------------------------------------------------------------------------
189 /**
190  * @brief FindPoint find point intersection two foots right triangle.
191  * @param axisP1 first axis point.
192  * @param axisP2 second axis point.
193  * @param firstPoint first triangle point, what lies on the hypotenuse.
194  * @param secondPoint second triangle point, what lies on the hypotenuse.
195  * @param intersectionPoint point intersection two foots right triangle
196  * @return true if the intersection exists.
197  */
FindPoint(const QPointF & axisP1,const QPointF & axisP2,const QPointF & firstPoint,const QPointF & secondPoint,QPointF * intersectionPoint)198 bool VToolTriangle::FindPoint(const QPointF &axisP1, const QPointF &axisP2, const QPointF &firstPoint,
199                               const QPointF &secondPoint, QPointF *intersectionPoint)
200 {
201     SCASSERT(intersectionPoint != nullptr)
202 
203     QLineF axis(axisP1, axisP2);
204     QLineF hypotenuse(firstPoint, secondPoint);
205 
206     QPointF startPoint;
207     QLineF::IntersectType intersect = Intersects(axis, hypotenuse, &startPoint);
208 
209     if (intersect != QLineF::UnboundedIntersection && intersect != QLineF::BoundedIntersection)
210     {
211         return false;
212     }
213     if (VFuzzyComparePossibleNulls(axis.angle(), hypotenuse.angle())
214         || VFuzzyComparePossibleNulls(qAbs(axis.angle() - hypotenuse.angle()), 180))
215     {
216         return false;
217     }
218 
219     qreal step = 1;
220 
221     QLineF line;
222     line.setP1(startPoint);
223     line.setAngle(axis.angle());
224     line.setLength(step);
225 
226     qint64 c = qFloor(hypotenuse.length());
227     while (1)
228     {
229         line.setLength(line.length()+step);
230         qint64 a = qFloor(QLineF(line.p2(), firstPoint).length());
231         qint64 b = qFloor(QLineF(line.p2(), secondPoint).length());
232         if (c*c <= (a*a + b*b))
233         {
234             *intersectionPoint = line.p2();
235             return true;
236         }
237     }
238     return false;
239 }
240 
241 //---------------------------------------------------------------------------------------------------------------------
AxisP1Name() const242 QString VToolTriangle::AxisP1Name() const
243 {
244     return VAbstractTool::data.GetGObject(axisP1Id)->name();
245 }
246 
247 //---------------------------------------------------------------------------------------------------------------------
AxisP2Name() const248 QString VToolTriangle::AxisP2Name() const
249 {
250     return VAbstractTool::data.GetGObject(axisP2Id)->name();
251 }
252 
253 //---------------------------------------------------------------------------------------------------------------------
FirstPointName() const254 QString VToolTriangle::FirstPointName() const
255 {
256     return VAbstractTool::data.GetGObject(firstPointId)->name();
257 }
258 
259 //---------------------------------------------------------------------------------------------------------------------
SecondPointName() const260 QString VToolTriangle::SecondPointName() const
261 {
262     return VAbstractTool::data.GetGObject(secondPointId)->name();
263 }
264 
265 //---------------------------------------------------------------------------------------------------------------------
266 /**
267  * @brief RemoveReferens decrement value of reference.
268  */
RemoveReferens()269 void VToolTriangle::RemoveReferens()
270 {
271     const auto axisP1 = VAbstractTool::data.GetGObject(axisP1Id);
272     const auto axisP2 = VAbstractTool::data.GetGObject(axisP2Id);
273     const auto firstPoint = VAbstractTool::data.GetGObject(firstPointId);
274     const auto secondPoint = VAbstractTool::data.GetGObject(secondPointId);
275 
276     doc->DecrementReferens(axisP1->getIdTool());
277     doc->DecrementReferens(axisP2->getIdTool());
278     doc->DecrementReferens(firstPoint->getIdTool());
279     doc->DecrementReferens(secondPoint->getIdTool());
280 }
281 
282 //---------------------------------------------------------------------------------------------------------------------
283 /**
284  * @brief SaveDialog save options into file after change in dialog.
285  */
SaveDialog(QDomElement & domElement,QList<quint32> & oldDependencies,QList<quint32> & newDependencies)286 void VToolTriangle::SaveDialog(QDomElement &domElement, QList<quint32> &oldDependencies,
287                                QList<quint32> &newDependencies)
288 {
289     SCASSERT(not m_dialog.isNull())
290     const QPointer<DialogTriangle> dialogTool = qobject_cast<DialogTriangle *>(m_dialog);
291     SCASSERT(not dialogTool.isNull())
292 
293     AddDependence(oldDependencies, axisP1Id);
294     AddDependence(oldDependencies, axisP2Id);
295     AddDependence(oldDependencies, firstPointId);
296     AddDependence(oldDependencies, secondPointId);
297     AddDependence(newDependencies, dialogTool->GetAxisP1Id());
298     AddDependence(newDependencies, dialogTool->GetAxisP2Id());
299     AddDependence(newDependencies, dialogTool->GetFirstPointId());
300     AddDependence(newDependencies, dialogTool->GetSecondPointId());
301 
302     doc->SetAttribute(domElement, AttrName, dialogTool->GetPointName());
303     doc->SetAttribute(domElement, AttrAxisP1, QString().setNum(dialogTool->GetAxisP1Id()));
304     doc->SetAttribute(domElement, AttrAxisP2, QString().setNum(dialogTool->GetAxisP2Id()));
305     doc->SetAttribute(domElement, AttrFirstPoint, QString().setNum(dialogTool->GetFirstPointId()));
306     doc->SetAttribute(domElement, AttrSecondPoint, QString().setNum(dialogTool->GetSecondPointId()));
307 
308     const QString notes = dialogTool->GetNotes();
309     doc->SetAttributeOrRemoveIf(domElement, AttrNotes, notes, notes.isEmpty());
310 }
311 
312 //---------------------------------------------------------------------------------------------------------------------
SaveOptions(QDomElement & tag,QSharedPointer<VGObject> & obj)313 void VToolTriangle::SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj)
314 {
315     VToolSinglePoint::SaveOptions(tag, obj);
316 
317     doc->SetAttribute(tag, AttrType, ToolType);
318     doc->SetAttribute(tag, AttrAxisP1, axisP1Id);
319     doc->SetAttribute(tag, AttrAxisP2, axisP2Id);
320     doc->SetAttribute(tag, AttrFirstPoint, firstPointId);
321     doc->SetAttribute(tag, AttrSecondPoint, secondPointId);
322 }
323 
324 //---------------------------------------------------------------------------------------------------------------------
ReadToolAttributes(const QDomElement & domElement)325 void VToolTriangle::ReadToolAttributes(const QDomElement &domElement)
326 {
327     VToolSinglePoint::ReadToolAttributes(domElement);
328 
329     axisP1Id = doc->GetParametrUInt(domElement, AttrAxisP1, NULL_ID_STR);
330     axisP2Id = doc->GetParametrUInt(domElement, AttrAxisP2, NULL_ID_STR);
331     firstPointId = doc->GetParametrUInt(domElement, AttrFirstPoint, NULL_ID_STR);
332     secondPointId = doc->GetParametrUInt(domElement, AttrSecondPoint, NULL_ID_STR);
333 }
334 
335 //---------------------------------------------------------------------------------------------------------------------
SetVisualization()336 void VToolTriangle::SetVisualization()
337 {
338     if (not vis.isNull())
339     {
340         VisToolTriangle * visual = qobject_cast<VisToolTriangle *>(vis);
341         SCASSERT(visual != nullptr)
342 
343         visual->setObject1Id(axisP1Id);
344         visual->setObject2Id(axisP2Id);
345         visual->setHypotenuseP1Id(firstPointId);
346         visual->setHypotenuseP2Id(secondPointId);
347         visual->RefreshGeometry();
348     }
349 }
350 
351 //---------------------------------------------------------------------------------------------------------------------
ShowContextMenu(QGraphicsSceneContextMenuEvent * event,quint32 id)352 void VToolTriangle::ShowContextMenu(QGraphicsSceneContextMenuEvent *event, quint32 id)
353 {
354     try
355     {
356         ContextMenu<DialogTriangle>(event, id);
357     }
358     catch(const VExceptionToolWasDeleted &e)
359     {
360         Q_UNUSED(e)
361         return;//Leave this method immediately!!!
362     }
363 }
364 
365 //---------------------------------------------------------------------------------------------------------------------
ShowVisualization(bool show)366 void VToolTriangle::ShowVisualization(bool show)
367 {
368     ShowToolVisualization<VisToolTriangle>(show);
369 }
370