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