0024665: A sample for advanced function mechanism
[occt.git] / samples / qt / FuncDemo / src / graphwidget.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2006-2007 Trolltech ASA. All rights reserved.
4 **
5 ** This file is part of the example classes of the Qt Toolkit.
6 **
7 ** Licensees holding a valid Qt License Agreement may use this file in
8 ** accordance with the rights, responsibilities and obligations
9 ** contained therein.  Please consult your licensing agreement or
10 ** contact sales@trolltech.com if any conditions of this licensing
11 ** agreement are not clear to you.
12 **
13 ** Further information about Qt licensing is available at:
14 ** http://www.trolltech.com/products/qt/licensing.html or by
15 ** contacting info@trolltech.com.
16 **
17 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 **
20 ****************************************************************************/
21
22 #include "graphwidget.h"
23 #include "edge.h"
24 #include "node.h"
25
26 #include <QDebug>
27 #include <QGraphicsScene>
28 #include <QWheelEvent>
29 #include <QApplication>
30
31 #include <math.h>
32
33 #include <TFunction_Iterator.hxx>
34 #include <TFunction_IFunction.hxx>
35 #include <TFunction_GraphNode.hxx>
36 #include <TFunction_Scope.hxx>
37 #include <TFunction_DriverTable.hxx>
38 #include <TFunction_Driver.hxx>
39 #include <TFunction_Function.hxx>
40
41 #include <TDataStd_Name.hxx>
42 #include <TDF_ChildIterator.hxx>
43 #include <TDF_ListIteratorOfLabelList.hxx>
44 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
45
46 #include "SimpleDriver.h"
47 #include "PointDriver.h"
48 #include "CircleDriver.h"
49 #include "PrismDriver.h"
50 #include "ConeDriver.h"
51 #include "CylinderDriver.h"
52 #include "ShapeSaverDriver.h"
53 #include "SimpleDriver.h"
54
55 GraphWidget::GraphWidget(QWidget* parent):QGraphicsView(parent),
56     myThread1(0),myThread2(0),myThread3(0),myThread4(0)
57 {
58     QGraphicsScene *scene = new QGraphicsScene(this);
59     scene->setItemIndexMethod(QGraphicsScene::NoIndex);
60     scene->setSceneRect(1, 1, parent->width(), parent->height());
61     setScene(scene);
62     setCacheMode(CacheBackground);
63     setRenderHint(QPainter::Antialiasing);
64     setTransformationAnchor(AnchorUnderMouse);
65     setResizeAnchor(AnchorViewCenter);
66
67     scale(0.7, 0.81);
68     setMinimumSize(400, 400);
69     setWindowTitle(tr("Function Mechanism"));
70
71     setNbThreads(1);
72 }
73
74 GraphWidget::~GraphWidget()
75 {
76     if (myThread1)
77     {
78         myThread1->wait();
79         myThread1->deleteLater();
80     }
81     if (myThread2)
82     {
83         myThread2->wait();
84         myThread2->deleteLater();
85     }
86     if (myThread3)
87     {
88         myThread3->wait();
89         myThread3->deleteLater();
90     }
91     if (myThread4)
92     {
93         myThread4->wait();
94         myThread4->deleteLater();
95     }
96 }
97
98 bool GraphWidget::createModel(const Handle(TDocStd_Document)& doc)
99 {
100     myDocument = doc;
101     
102     TFunction_Iterator fIterator(myDocument->Main());
103     fIterator.SetUsageOfExecutionStatus(false);
104     Handle(TFunction_Scope) scope = TFunction_Scope::Set(myDocument->Main());
105
106     // Find out the size of the grid: number of functions in X and Y directions
107     int nbx = 0, nby = 0;
108     while (!fIterator.Current().IsEmpty())
109     {
110         const TDF_LabelList& funcs = fIterator.Current();
111         if (funcs.Extent() > nbx)
112             nbx = funcs.Extent();
113         nby++;
114         fIterator.Next();
115     }
116     if (!nbx || !nby)
117         return false;
118
119     // Grid of functions
120     int dx = width() / nbx, dy = height() / nby;
121     int x0 = dx / 2, y0 = dy / 2; // start position
122
123     // Draw functions
124     double x = x0, y = y0;
125     fIterator.Init(myDocument->Main());
126     while (!fIterator.Current().IsEmpty())
127     {
128         const TDF_LabelList& funcs = fIterator.Current();
129         TDF_ListIteratorOfLabelList itrl(funcs);
130         for (; itrl.More(); itrl.Next())
131         {
132             TDF_Label L = itrl.Value();
133             Node *node = new Node(this);
134             node->setFunction(L);
135             scene()->addItem(node);
136             node->setPos(x, y);
137             x += dx;
138             if (x > width())
139                 x = x0;
140         }
141         y += dy;
142         if (y > height())
143             y = y0;
144         fIterator.Next();
145     }
146
147     // Draw dependencies
148     fIterator.Init(myDocument->Main());
149     while (!fIterator.Current().IsEmpty())
150     {
151         const TDF_LabelList& funcs = fIterator.Current();
152         TDF_ListIteratorOfLabelList itrl(funcs);
153         for (; itrl.More(); itrl.Next())
154         {
155             TDF_Label L = itrl.Value();
156             Node* node = findNode(L);
157             if (!node)
158                 continue;
159
160             // Find backward dependencies of the function
161             TFunction_IFunction iFunc(L);
162             Handle(TFunction_GraphNode) graphNode = iFunc.GetGraphNode();
163             const TColStd_MapOfInteger& prev = graphNode->GetPrevious();
164             TColStd_MapIteratorOfMapOfInteger itrm(prev);
165             for (; itrm.More(); itrm.Next())
166             {
167                 const int argID = itrm.Key();
168                 const TDF_Label& argL = scope->GetFunction(argID);
169                 Node* n = findNode(argL);
170                 if (!n)
171                     continue;
172                 scene()->addItem(new Edge(n, node));
173             }
174         }
175         fIterator.Next();
176     }
177
178     return !myDocument.IsNull();
179 }
180
181 void GraphWidget::wheelEvent(QWheelEvent *event)
182 {
183     scaleView(pow((double)2, -event->delta() / 240.0));
184 }
185
186 void GraphWidget::drawBackground(QPainter *painter, const QRectF &rect)
187 {
188     Q_UNUSED(rect);
189
190     // Shadow
191     QRectF sceneRect = this->sceneRect();
192     QRectF rightShadow(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height());
193     QRectF bottomShadow(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5);
194     if (rightShadow.intersects(rect) || rightShadow.contains(rect))
195         painter->fillRect(rightShadow, Qt::darkGray);
196     if (bottomShadow.intersects(rect) || bottomShadow.contains(rect))
197         painter->fillRect(bottomShadow, Qt::darkGray);
198
199     // Fill
200     QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight());
201     gradient.setColorAt(0, Qt::white);
202     gradient.setColorAt(1, Qt::lightGray);
203     painter->fillRect(rect.intersect(sceneRect), gradient);
204     painter->setBrush(Qt::NoBrush);
205     painter->drawRect(sceneRect);
206 }
207
208 void GraphWidget::scaleView(qreal scaleFactor)
209 {
210     qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
211     if (factor < 0.07 || factor > 100)
212         return;
213
214     scale(scaleFactor, scaleFactor);
215 }
216
217 // Find node of the function
218 Node* GraphWidget::findNode(const TDF_Label& L)
219 {
220     Node* node = 0;
221     for (int i = 0; i < scene()->items().size(); i++)
222     {
223         Node* n = qgraphicsitem_cast<Node *>(scene()->items().at(i));
224         if (n && n->getFunction() == L)
225         {
226             node = n;
227             break;
228         }
229     }
230     return node;
231 }
232
233 void GraphWidget::compute()
234 {
235     myNbFinishedThreads = 0;
236
237     TFunction_Iterator fIterator(myDocument->Main());
238     fIterator.SetUsageOfExecutionStatus(true);
239
240     myThread1 = new FThread();
241     if (myNbThreads > 1)
242         myThread2 = new FThread();
243     if (myNbThreads > 2)
244         myThread3 = new FThread();
245     if (myNbThreads > 3)
246         myThread4 = new FThread();
247
248     // Logbook
249     Handle(TFunction_Logbook) log = TFunction_Scope::Set(myDocument->Main())->GetLogbook();
250     myThread1->setLogbook(log);
251     if (myNbThreads > 1)
252         myThread2->setLogbook(log);
253     if (myNbThreads > 2)
254         myThread3->setLogbook(log);
255     if (myNbThreads > 3)
256         myThread4->setLogbook(log);
257
258     myThread1->setIterator(fIterator);
259     if (myNbThreads > 1)
260         myThread2->setIterator(fIterator);
261     if (myNbThreads > 2)
262         myThread3->setIterator(fIterator);
263     if (myNbThreads > 3)
264         myThread4->setIterator(fIterator);
265
266     myThread1->setGraph(this);
267     if (myNbThreads > 1)
268         myThread2->setGraph(this);
269     if (myNbThreads > 2)
270         myThread3->setGraph(this);
271     if (myNbThreads > 3)
272         myThread4->setGraph(this);
273
274     myThread1->setThreadIndex(1);
275     if (myNbThreads > 1)
276         myThread2->setThreadIndex(2);
277     if (myNbThreads > 2)
278         myThread3->setThreadIndex(3);
279     if (myNbThreads > 3)
280         myThread4->setThreadIndex(4);
281
282     QThread::Priority priority = QThread::LowestPriority;
283     if (!myThread1->isRunning())
284         myThread1->start(priority);
285     if (myNbThreads > 1 && !myThread2->isRunning())
286         myThread2->start(priority);
287     if (myNbThreads > 2 && !myThread3->isRunning())
288         myThread3->start(priority);
289     if (myNbThreads > 3 && !myThread4->isRunning())
290         myThread4->start(priority);
291 }
292
293 void GraphWidget::setNbThreads(const int nb)
294 {
295     myNbThreads = nb;
296     if (myNbThreads < 4 && myThread4)
297     {
298         myThread4->wait();
299         myThread4->deleteLater();
300         myThread4 = 0;
301     }
302     if (myNbThreads < 3 && myThread3)
303     {
304         myThread3->wait();
305         myThread3->deleteLater();
306         myThread3 = 0;
307     }
308     if (myNbThreads < 2 && myThread2)
309     {
310         myThread2->wait();
311         myThread2->deleteLater();
312         myThread2 = 0;
313     }
314
315     for (int i = 1; i <= myNbThreads; i++)
316     {
317         TFunction_DriverTable::Get()->AddDriver(PointDriver::GetID(), new PointDriver(), i);
318         TFunction_DriverTable::Get()->AddDriver(CircleDriver::GetID(), new CircleDriver(), i);
319         TFunction_DriverTable::Get()->AddDriver(PrismDriver::GetID(), new PrismDriver(), i);
320         TFunction_DriverTable::Get()->AddDriver(ConeDriver::GetID(), new ConeDriver(), i);
321         TFunction_DriverTable::Get()->AddDriver(CylinderDriver::GetID(), new CylinderDriver(), i);
322         TFunction_DriverTable::Get()->AddDriver(ShapeSaverDriver::GetID(), new ShapeSaverDriver(), i);
323         TFunction_DriverTable::Get()->AddDriver(SimpleDriver::GetID(), new SimpleDriver(), i);
324     }
325 }
326
327 int GraphWidget::getNbThreads()
328 {
329     return myNbThreads;
330 }
331
332 void GraphWidget::setFinished()
333 {
334     myNbFinishedThreads++;
335 }
336
337 bool GraphWidget::isFinished()
338 {
339     return myNbThreads == myNbFinishedThreads ;
340 }
341
342 void GraphWidget::accelerateThread(const int thread_index)
343 {
344     bool all_slow = true;
345     if (myThread1 && myThread1->priority() != QThread::LowPriority)
346         all_slow = false;
347     if (all_slow && myThread2 && myThread2->priority() != QThread::LowPriority)
348         all_slow = false;
349     if (all_slow && myThread3 && myThread3->priority() != QThread::LowPriority)
350         all_slow = false;
351     if (all_slow && myThread4 && myThread4->priority() != QThread::LowPriority)
352         all_slow = false;
353     if (!all_slow)
354         return;
355
356     QThread::Priority priority = QThread::NormalPriority;
357     switch (thread_index)
358     {
359     case 1:
360         myThread1->setPriority(priority);
361         break;
362     case 2:
363         myThread2->setPriority(priority);
364         break;
365     case 3:
366         myThread3->setPriority(priority);
367         break;
368     case 4:
369         myThread4->setPriority(priority);
370         break;
371     }
372 }
373
374 void GraphWidget::slowDownThread(const int thread_index)
375 {
376     QThread::Priority priority = QThread::LowPriority;
377     switch (thread_index)
378     {
379     case 1:
380         myThread1->setPriority(priority);
381         break;
382     case 2:
383         myThread2->setPriority(priority);
384         break;
385     case 3:
386         myThread3->setPriority(priority);
387         break;
388     case 4:
389         myThread4->setPriority(priority);
390         break;
391     }
392 }