0031875: Draw Harness, ViewerTest - command vaspects -mostContinuity lacks g1 and...
[occt.git] / samples / qt / FuncDemo / src / graphwidget.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 **     of its contributors may be used to endorse or promote products derived
22 **     from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "graphwidget.h"
42 #include "edge.h"
43 #include "node.h"
44
45 #include <Standard_WarningsDisable.hxx>
46 #include <QDebug>
47 #include <QGraphicsScene>
48 #include <QWheelEvent>
49 #include <QApplication>
50 #include <Standard_WarningsRestore.hxx>
51
52 #include <math.h>
53
54 #include <TFunction_Iterator.hxx>
55 #include <TFunction_IFunction.hxx>
56 #include <TFunction_GraphNode.hxx>
57 #include <TFunction_Scope.hxx>
58 #include <TFunction_DriverTable.hxx>
59 #include <TFunction_Driver.hxx>
60 #include <TFunction_Function.hxx>
61
62 #include <TDataStd_Name.hxx>
63 #include <TDF_ChildIterator.hxx>
64 #include <TDF_ListIteratorOfLabelList.hxx>
65 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
66
67 #include "SimpleDriver.h"
68 #include "PointDriver.h"
69 #include "CircleDriver.h"
70 #include "PrismDriver.h"
71 #include "ConeDriver.h"
72 #include "CylinderDriver.h"
73 #include "ShapeSaverDriver.h"
74 #include "SimpleDriver.h"
75
76 GraphWidget::GraphWidget(QWidget* parent):QGraphicsView(parent),
77     myThread1(0),myThread2(0),myThread3(0),myThread4(0)
78 {
79     QGraphicsScene *scene = new QGraphicsScene(this);
80     scene->setItemIndexMethod(QGraphicsScene::NoIndex);
81     scene->setSceneRect(1, 1, parent->width(), parent->height());
82     setScene(scene);
83     setCacheMode(CacheBackground);
84     setRenderHint(QPainter::Antialiasing);
85     setTransformationAnchor(AnchorUnderMouse);
86     setResizeAnchor(AnchorViewCenter);
87
88     scale(0.7, 0.81);
89     setMinimumSize(400, 400);
90     setWindowTitle(tr("Function Mechanism"));
91
92     setNbThreads(1);
93 }
94
95 GraphWidget::~GraphWidget()
96 {
97     if (myThread1)
98     {
99         myThread1->wait();
100         myThread1->deleteLater();
101     }
102     if (myThread2)
103     {
104         myThread2->wait();
105         myThread2->deleteLater();
106     }
107     if (myThread3)
108     {
109         myThread3->wait();
110         myThread3->deleteLater();
111     }
112     if (myThread4)
113     {
114         myThread4->wait();
115         myThread4->deleteLater();
116     }
117 }
118
119 bool GraphWidget::createModel(const Handle(TDocStd_Document)& doc)
120 {
121     myDocument = doc;
122     
123     TFunction_Iterator fIterator(myDocument->Main());
124     fIterator.SetUsageOfExecutionStatus(false);
125     Handle(TFunction_Scope) scope = TFunction_Scope::Set(myDocument->Main());
126
127     // Find out the size of the grid: number of functions in X and Y directions
128     int nbx = 0, nby = 0;
129     while (!fIterator.Current().IsEmpty())
130     {
131         const TDF_LabelList& funcs = fIterator.Current();
132         if (funcs.Extent() > nbx)
133             nbx = funcs.Extent();
134         nby++;
135         fIterator.Next();
136     }
137     if (!nbx || !nby)
138         return false;
139
140     // Grid of functions
141     int dx = width() / nbx, dy = height() / nby;
142     int x0 = dx / 2, y0 = dy / 2; // start position
143
144     // Draw functions
145     double x = x0, y = y0;
146     fIterator.Init(myDocument->Main());
147     while (!fIterator.Current().IsEmpty())
148     {
149         const TDF_LabelList& funcs = fIterator.Current();
150         TDF_ListIteratorOfLabelList itrl(funcs);
151         for (; itrl.More(); itrl.Next())
152         {
153             TDF_Label L = itrl.Value();
154             Node *node = new Node(this);
155             node->setFunction(L);
156             scene()->addItem(node);
157             node->setPos(x, y);
158             x += dx;
159             if (x > width())
160                 x = x0;
161         }
162         y += dy;
163         if (y > height())
164             y = y0;
165         fIterator.Next();
166     }
167
168     // Draw dependencies
169     fIterator.Init(myDocument->Main());
170     while (!fIterator.Current().IsEmpty())
171     {
172         const TDF_LabelList& funcs = fIterator.Current();
173         TDF_ListIteratorOfLabelList itrl(funcs);
174         for (; itrl.More(); itrl.Next())
175         {
176             TDF_Label L = itrl.Value();
177             Node* node = findNode(L);
178             if (!node)
179                 continue;
180
181             // Find backward dependencies of the function
182             TFunction_IFunction iFunc(L);
183             Handle(TFunction_GraphNode) graphNode = iFunc.GetGraphNode();
184             const TColStd_MapOfInteger& prev = graphNode->GetPrevious();
185             TColStd_MapIteratorOfMapOfInteger itrm(prev);
186             for (; itrm.More(); itrm.Next())
187             {
188                 const int argID = itrm.Key();
189                 const TDF_Label& argL = scope->GetFunction(argID);
190                 Node* n = findNode(argL);
191                 if (!n)
192                     continue;
193                 scene()->addItem(new Edge(n, node));
194             }
195         }
196         fIterator.Next();
197     }
198
199     return !myDocument.IsNull();
200 }
201
202 void GraphWidget::wheelEvent(QWheelEvent *event)
203 {
204     scaleView(pow((double)2, -event->delta() / 240.0));
205 }
206
207 void GraphWidget::drawBackground(QPainter *painter, const QRectF &rect)
208 {
209     Q_UNUSED(rect);
210
211     // Shadow
212     QRectF sceneRect = this->sceneRect();
213     QRectF rightShadow(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height());
214     QRectF bottomShadow(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5);
215     if (rightShadow.intersects(rect) || rightShadow.contains(rect))
216         painter->fillRect(rightShadow, Qt::darkGray);
217     if (bottomShadow.intersects(rect) || bottomShadow.contains(rect))
218         painter->fillRect(bottomShadow, Qt::darkGray);
219
220     // Fill
221     QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight());
222     gradient.setColorAt(0, Qt::white);
223     gradient.setColorAt(1, Qt::lightGray);
224     painter->fillRect(rect.intersected(sceneRect), gradient);
225     painter->setBrush(Qt::NoBrush);
226     painter->drawRect(sceneRect);
227 }
228
229 void GraphWidget::scaleView(qreal scaleFactor)
230 {
231     qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
232     if (factor < 0.07 || factor > 100)
233         return;
234
235     scale(scaleFactor, scaleFactor);
236 }
237
238 // Find node of the function
239 Node* GraphWidget::findNode(const TDF_Label& L)
240 {
241     Node* node = 0;
242     for (int i = 0; i < scene()->items().size(); i++)
243     {
244         Node* n = qgraphicsitem_cast<Node *>(scene()->items().at(i));
245         if (n && n->getFunction() == L)
246         {
247             node = n;
248             break;
249         }
250     }
251     return node;
252 }
253
254 void GraphWidget::compute()
255 {
256     myNbFinishedThreads = 0;
257
258     TFunction_Iterator fIterator(myDocument->Main());
259     fIterator.SetUsageOfExecutionStatus(true);
260
261     myThread1 = new FThread();
262     if (myNbThreads > 1)
263         myThread2 = new FThread();
264     if (myNbThreads > 2)
265         myThread3 = new FThread();
266     if (myNbThreads > 3)
267         myThread4 = new FThread();
268
269     // Logbook
270     Handle(TFunction_Logbook) log = TFunction_Scope::Set(myDocument->Main())->GetLogbook();
271     myThread1->setLogbook(log);
272     if (myNbThreads > 1)
273         myThread2->setLogbook(log);
274     if (myNbThreads > 2)
275         myThread3->setLogbook(log);
276     if (myNbThreads > 3)
277         myThread4->setLogbook(log);
278
279     myThread1->setIterator(fIterator);
280     if (myNbThreads > 1)
281         myThread2->setIterator(fIterator);
282     if (myNbThreads > 2)
283         myThread3->setIterator(fIterator);
284     if (myNbThreads > 3)
285         myThread4->setIterator(fIterator);
286
287     myThread1->setGraph(this);
288     if (myNbThreads > 1)
289         myThread2->setGraph(this);
290     if (myNbThreads > 2)
291         myThread3->setGraph(this);
292     if (myNbThreads > 3)
293         myThread4->setGraph(this);
294
295     myThread1->setThreadIndex(1);
296     if (myNbThreads > 1)
297         myThread2->setThreadIndex(2);
298     if (myNbThreads > 2)
299         myThread3->setThreadIndex(3);
300     if (myNbThreads > 3)
301         myThread4->setThreadIndex(4);
302
303     QThread::Priority priority = QThread::LowestPriority;
304     if (!myThread1->isRunning())
305         myThread1->start(priority);
306     if (myNbThreads > 1 && !myThread2->isRunning())
307         myThread2->start(priority);
308     if (myNbThreads > 2 && !myThread3->isRunning())
309         myThread3->start(priority);
310     if (myNbThreads > 3 && !myThread4->isRunning())
311         myThread4->start(priority);
312 }
313
314 void GraphWidget::setNbThreads(const int nb)
315 {
316     myNbThreads = nb;
317     if (myNbThreads < 4 && myThread4)
318     {
319         myThread4->wait();
320         myThread4->deleteLater();
321         myThread4 = 0;
322     }
323     if (myNbThreads < 3 && myThread3)
324     {
325         myThread3->wait();
326         myThread3->deleteLater();
327         myThread3 = 0;
328     }
329     if (myNbThreads < 2 && myThread2)
330     {
331         myThread2->wait();
332         myThread2->deleteLater();
333         myThread2 = 0;
334     }
335
336     for (int i = 1; i <= myNbThreads; i++)
337     {
338         TFunction_DriverTable::Get()->AddDriver(PointDriver::GetID(), new PointDriver(), i);
339         TFunction_DriverTable::Get()->AddDriver(CircleDriver::GetID(), new CircleDriver(), i);
340         TFunction_DriverTable::Get()->AddDriver(PrismDriver::GetID(), new PrismDriver(), i);
341         TFunction_DriverTable::Get()->AddDriver(ConeDriver::GetID(), new ConeDriver(), i);
342         TFunction_DriverTable::Get()->AddDriver(CylinderDriver::GetID(), new CylinderDriver(), i);
343         TFunction_DriverTable::Get()->AddDriver(ShapeSaverDriver::GetID(), new ShapeSaverDriver(), i);
344         TFunction_DriverTable::Get()->AddDriver(SimpleDriver::GetID(), new SimpleDriver(), i);
345     }
346 }
347
348 int GraphWidget::getNbThreads()
349 {
350     return myNbThreads;
351 }
352
353 void GraphWidget::setFinished()
354 {
355     myNbFinishedThreads++;
356 }
357
358 bool GraphWidget::isFinished()
359 {
360     return myNbThreads == myNbFinishedThreads ;
361 }
362
363 void GraphWidget::accelerateThread(const int thread_index)
364 {
365     bool all_slow = true;
366     if (myThread1 && myThread1->priority() != QThread::LowPriority)
367         all_slow = false;
368     if (all_slow && myThread2 && myThread2->priority() != QThread::LowPriority)
369         all_slow = false;
370     if (all_slow && myThread3 && myThread3->priority() != QThread::LowPriority)
371         all_slow = false;
372     if (all_slow && myThread4 && myThread4->priority() != QThread::LowPriority)
373         all_slow = false;
374     if (!all_slow)
375         return;
376
377     QThread::Priority priority = QThread::NormalPriority;
378     switch (thread_index)
379     {
380     case 1:
381         myThread1->setPriority(priority);
382         break;
383     case 2:
384         myThread2->setPriority(priority);
385         break;
386     case 3:
387         myThread3->setPriority(priority);
388         break;
389     case 4:
390         myThread4->setPriority(priority);
391         break;
392     }
393 }
394
395 void GraphWidget::slowDownThread(const int thread_index)
396 {
397     QThread::Priority priority = QThread::LowPriority;
398     switch (thread_index)
399     {
400     case 1:
401         myThread1->setPriority(priority);
402         break;
403     case 2:
404         myThread2->setPriority(priority);
405         break;
406     case 3:
407         myThread3->setPriority(priority);
408         break;
409     case 4:
410         myThread4->setPriority(priority);
411         break;
412     }
413 }