0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[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 <QtGui>
47 #include <Standard_WarningsRestore.hxx>
48
49 #include <math.h>
50
51 #include <TFunction_Iterator.hxx>
52 #include <TFunction_IFunction.hxx>
53 #include <TFunction_GraphNode.hxx>
54 #include <TFunction_Scope.hxx>
55 #include <TFunction_DriverTable.hxx>
56 #include <TFunction_Driver.hxx>
57 #include <TFunction_Function.hxx>
58
59 #include <TDataStd_Name.hxx>
60 #include <TDF_ChildIterator.hxx>
61 #include <TDF_ListIteratorOfLabelList.hxx>
62 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
63
64 #include "SimpleDriver.h"
65 #include "PointDriver.h"
66 #include "CircleDriver.h"
67 #include "PrismDriver.h"
68 #include "ConeDriver.h"
69 #include "CylinderDriver.h"
70 #include "ShapeSaverDriver.h"
71 #include "SimpleDriver.h"
72
73 //! [0]
74 GraphWidget::GraphWidget(QWidget *parent)
75     : QGraphicsView(parent), timerId(0),
76       myThread1(0),myThread2(0),myThread3(0),myThread4(0)
77 {
78     QGraphicsScene *scene = new QGraphicsScene(this);
79     scene->setItemIndexMethod(QGraphicsScene::NoIndex);
80     scene->setSceneRect(-200, -200, 400, 400);
81     setScene(scene);
82     setCacheMode(CacheBackground);
83     setViewportUpdateMode(BoundingRectViewportUpdate);
84     setRenderHint(QPainter::Antialiasing);
85     setTransformationAnchor(AnchorUnderMouse);
86
87     scale(qreal(0.8), qreal(0.8));
88     setMinimumSize(400, 400);
89     setWindowTitle(tr("Function Mechanism"));
90
91 //! [0]
92
93 //! [1]
94 /*
95     Node *node1 = new Node(this);
96     Node *node2 = new Node(this);
97     Node *node3 = new Node(this);
98     Node *node4 = new Node(this);
99     centerNode = new Node(this);
100     Node *node6 = new Node(this);
101     Node *node7 = new Node(this);
102     Node *node8 = new Node(this);
103     Node *node9 = new Node(this);
104     scene->addItem(node1);
105     scene->addItem(node2);
106     scene->addItem(node3);
107     scene->addItem(node4);
108     scene->addItem(centerNode);
109     scene->addItem(node6);
110     scene->addItem(node7);
111     scene->addItem(node8);
112     scene->addItem(node9);
113     scene->addItem(new Edge(node1, node2));
114     scene->addItem(new Edge(node2, node3));
115     scene->addItem(new Edge(node2, centerNode));
116     scene->addItem(new Edge(node3, node6));
117     scene->addItem(new Edge(node4, node1));
118     scene->addItem(new Edge(node4, centerNode));
119     scene->addItem(new Edge(centerNode, node6));
120     scene->addItem(new Edge(centerNode, node8));
121     scene->addItem(new Edge(node6, node9));
122     scene->addItem(new Edge(node7, node4));
123     scene->addItem(new Edge(node8, node7));
124     scene->addItem(new Edge(node9, node8));
125
126     node1->setPos(-50, -50);
127     node2->setPos(0, -50);
128     node3->setPos(50, -50);
129     node4->setPos(-50, 0);
130     centerNode->setPos(0, 0);
131     node6->setPos(50, 0);
132     node7->setPos(-50, 50);
133     node8->setPos(0, 50);
134     node9->setPos(50, 50);
135 */
136
137     setNbThreads(4);
138 }
139 //! [1]
140
141 GraphWidget::~GraphWidget()
142 {
143     if (myThread1)
144     {
145         myThread1->wait();
146         myThread1->deleteLater();
147     }
148     if (myThread2)
149     {
150         myThread2->wait();
151         myThread2->deleteLater();
152     }
153     if (myThread3)
154     {
155         myThread3->wait();
156         myThread3->deleteLater();
157     }
158     if (myThread4)
159     {
160         myThread4->wait();
161         myThread4->deleteLater();
162     }
163 }
164
165 bool GraphWidget::createModel(const Handle(TDocStd_Document)& doc)
166 {
167     myDocument = doc;
168     
169     TFunction_Iterator fIterator(myDocument->Main());
170     fIterator.SetUsageOfExecutionStatus(false);
171     Handle(TFunction_Scope) scope = TFunction_Scope::Set(myDocument->Main());
172
173     // Find out the size of the grid: number of functions in X and Y directions
174     int nbx = 0, nby = 0;
175     while (!fIterator.Current().IsEmpty())
176     {
177         const TDF_LabelList& funcs = fIterator.Current();
178         if (funcs.Extent() > nbx)
179             nbx = funcs.Extent();
180         nby++;
181         fIterator.Next();
182     }
183     if (!nbx || !nby)
184         return false;
185
186     // Grid of functions
187     int dx = width() / nbx / 2, dy = height() / nby;
188     int x0 = int(-double(width()) / 1.5) + dx, y0 = int(-double(height()) / 1.5) + dy; // start position
189
190     // Draw functions
191     double x = x0, y = y0;
192     fIterator.Init(myDocument->Main());
193     while (!fIterator.Current().IsEmpty())
194     {
195         const TDF_LabelList& funcs = fIterator.Current();
196         TDF_ListIteratorOfLabelList itrl(funcs);
197         for (; itrl.More(); itrl.Next())
198         {
199             TDF_Label L = itrl.Value();
200             Node *node = new Node(this);
201             node->setFunction(L);
202             scene()->addItem(node);
203             node->setPos(x, y);
204             x += dx;
205             if (x > width())
206                 x = x0;
207         }
208         y += dy;
209         if (y > height())
210             y = y0;
211         fIterator.Next();
212         x = x0 + dx;
213     }
214
215     // Draw dependencies
216     fIterator.Init(myDocument->Main());
217     while (!fIterator.Current().IsEmpty())
218     {
219         const TDF_LabelList& funcs = fIterator.Current();
220         TDF_ListIteratorOfLabelList itrl(funcs);
221         for (; itrl.More(); itrl.Next())
222         {
223             TDF_Label L = itrl.Value();
224             Node* node = findNode(L);
225             if (!node)
226                 continue;
227
228             // Find backward dependencies of the function
229             TFunction_IFunction iFunc(L);
230             Handle(TFunction_GraphNode) graphNode = iFunc.GetGraphNode();
231             const TColStd_MapOfInteger& prev = graphNode->GetPrevious();
232             TColStd_MapIteratorOfMapOfInteger itrm(prev);
233             for (; itrm.More(); itrm.Next())
234             {
235                 const int argID = itrm.Key();
236                 const TDF_Label& argL = scope->GetFunction(argID);
237                 Node* n = findNode(argL);
238                 if (!n)
239                     continue;
240                 scene()->addItem(new Edge(n, node));
241             }
242         }
243         fIterator.Next();
244     }
245
246     return !myDocument.IsNull();
247 }
248
249 //! [2]
250 void GraphWidget::itemMoved()
251 {
252     if (!timerId)
253         timerId = startTimer(1000 / 25);
254 }
255 //! [2]
256
257 //! [3]
258 void GraphWidget::keyPressEvent(QKeyEvent *event)
259 {
260     switch (event->key()) {
261     case Qt::Key_Up:
262         centerNode->moveBy(0, -20);
263         break;
264     case Qt::Key_Down:
265         centerNode->moveBy(0, 20);
266         break;
267     case Qt::Key_Left:
268         centerNode->moveBy(-20, 0);
269         break;
270     case Qt::Key_Right:
271         centerNode->moveBy(20, 0);
272         break;
273     case Qt::Key_Plus:
274         zoomIn();
275         break;
276     case Qt::Key_Minus:
277         zoomOut();
278         break;
279     case Qt::Key_Space:
280     case Qt::Key_Enter:
281         shuffle();
282         break;
283     default:
284         QGraphicsView::keyPressEvent(event);
285     }
286 }
287 //! [3]
288
289 //! [4]
290 void GraphWidget::timerEvent(QTimerEvent *event)
291 {
292     Q_UNUSED(event);
293
294     QList<Node *> nodes;
295     foreach (QGraphicsItem *item, scene()->items()) {
296         if (Node *node = qgraphicsitem_cast<Node *>(item))
297             nodes << node;
298     }
299
300     foreach (Node *node, nodes)
301         node->calculateForces();
302
303     bool itemsMoved = false;
304     foreach (Node *node, nodes) {
305         if (node->advance())
306             itemsMoved = true;
307     }
308
309     if (!itemsMoved) {
310         killTimer(timerId);
311         timerId = 0;
312     }
313 }
314 //! [4]
315
316 //! [5]
317 void GraphWidget::wheelEvent(QWheelEvent *event)
318 {
319     scaleView(pow((double)2, -event->delta() / 240.0));
320 }
321 //! [5]
322
323 //! [6]
324 void GraphWidget::drawBackground(QPainter* painter, const QRectF &rect)
325 {
326     Q_UNUSED(rect);
327     Q_UNUSED(painter);
328
329 //    // Shadow
330 //    QRectF sceneRect = this->sceneRect();
331 //    QRectF rightShadow(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height());
332 //    QRectF bottomShadow(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5);
333 //    if (rightShadow.intersects(rect) || rightShadow.contains(rect))
334 //      painter->fillRect(rightShadow, Qt::darkGray);
335 //    if (bottomShadow.intersects(rect) || bottomShadow.contains(rect))
336 //      painter->fillRect(bottomShadow, Qt::darkGray);
337 //
338 //    // Fill
339 //    QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight());
340 //    gradient.setColorAt(0, Qt::white);
341 //    gradient.setColorAt(1, Qt::lightGray);
342 //    painter->fillRect(rect.intersect(sceneRect), gradient);
343 //    painter->setBrush(Qt::NoBrush);
344 //    painter->drawRect(sceneRect);
345 //
346 //#if !defined(Q_OS_SYMBIAN) && !defined(Q_WS_MAEMO_5)
347 //    // Text
348 //    QRectF textRect(sceneRect.left() + 4, sceneRect.top() + 4,
349 //                    sceneRect.width() - 4, sceneRect.height() - 4);
350 //    QString message(tr("Click and drag the nodes around, and zoom with the mouse "
351 //                       "wheel or the '+' and '-' keys"));
352 //
353 //    QFont font = painter->font();
354 //    font.setBold(true);
355 //    font.setPointSize(14);
356 //    painter->setFont(font);
357 //    painter->setPen(Qt::lightGray);
358 //    painter->drawText(textRect.translated(2, 2), message);
359 //    painter->setPen(Qt::black);
360 //    painter->drawText(textRect, message);
361 //#endif
362 }
363 //! [6]
364
365 //! [7]
366 void GraphWidget::scaleView(qreal scaleFactor)
367 {
368     qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
369     if (factor < 0.07 || factor > 100)
370         return;
371
372     scale(scaleFactor, scaleFactor);
373 }
374 //! [7]
375
376 void GraphWidget::shuffle()
377 {
378     foreach (QGraphicsItem *item, scene()->items()) {
379         if (qgraphicsitem_cast<Node *>(item))
380             item->setPos(-150 + qrand() % 300, -150 + qrand() % 300);
381     }
382 }
383
384 void GraphWidget::zoomIn()
385 {
386     scaleView(qreal(1.2));
387 }
388
389 void GraphWidget::zoomOut()
390 {
391     scaleView(1 / qreal(1.2));
392 }
393
394
395 // Find node of the function
396 Node* GraphWidget::findNode(const TDF_Label& L)
397 {
398     Node* node = 0;
399     for (int i = 0; i < scene()->items().size(); i++)
400     {
401         Node* n = qgraphicsitem_cast<Node *>(scene()->items().at(i));
402         if (n && n->getFunction() == L)
403         {
404             node = n;
405             break;
406         }
407     }
408     return node;
409 }
410
411 void GraphWidget::compute()
412 {
413     myNbFinishedThreads = 0;
414
415     TFunction_Iterator fIterator(myDocument->Main());
416     fIterator.SetUsageOfExecutionStatus(true);
417
418     myThread1 = new FThread();
419     if (myNbThreads > 1)
420         myThread2 = new FThread();
421     if (myNbThreads > 2)
422         myThread3 = new FThread();
423     if (myNbThreads > 3)
424         myThread4 = new FThread();
425
426     // Logbook
427     Handle(TFunction_Logbook) log = TFunction_Scope::Set(myDocument->Main())->GetLogbook();
428     myThread1->setLogbook(log);
429     if (myNbThreads > 1)
430         myThread2->setLogbook(log);
431     if (myNbThreads > 2)
432         myThread3->setLogbook(log);
433     if (myNbThreads > 3)
434         myThread4->setLogbook(log);
435
436     myThread1->setIterator(fIterator);
437     if (myNbThreads > 1)
438         myThread2->setIterator(fIterator);
439     if (myNbThreads > 2)
440         myThread3->setIterator(fIterator);
441     if (myNbThreads > 3)
442         myThread4->setIterator(fIterator);
443
444     myThread1->setGraph(this);
445     if (myNbThreads > 1)
446         myThread2->setGraph(this);
447     if (myNbThreads > 2)
448         myThread3->setGraph(this);
449     if (myNbThreads > 3)
450         myThread4->setGraph(this);
451
452     myThread1->setThreadIndex(1);
453     if (myNbThreads > 1)
454         myThread2->setThreadIndex(2);
455     if (myNbThreads > 2)
456         myThread3->setThreadIndex(3);
457     if (myNbThreads > 3)
458         myThread4->setThreadIndex(4);
459
460     myThread1->setMutex(&myMutex);
461     if (myNbThreads > 1)
462         myThread2->setMutex(&myMutex);
463     if (myNbThreads > 2)
464         myThread3->setMutex(&myMutex);
465     if (myNbThreads > 3)
466         myThread4->setMutex(&myMutex);
467
468     QThread::Priority priority = QThread::LowestPriority;
469     if (!myThread1->isRunning())
470         myThread1->start(priority);
471     if (myNbThreads > 1 && !myThread2->isRunning())
472         myThread2->start(priority);
473     if (myNbThreads > 2 && !myThread3->isRunning())
474         myThread3->start(priority);
475     if (myNbThreads > 3 && !myThread4->isRunning())
476         myThread4->start(priority);
477 }
478
479 void GraphWidget::setNbThreads(const int nb)
480 {
481     myNbThreads = nb;
482     if (myNbThreads < 4 && myThread4)
483     {
484         myThread4->wait();
485         myThread4->deleteLater();
486         myThread4 = 0;
487     }
488     if (myNbThreads < 3 && myThread3)
489     {
490         myThread3->wait();
491         myThread3->deleteLater();
492         myThread3 = 0;
493     }
494     if (myNbThreads < 2 && myThread2)
495     {
496         myThread2->wait();
497         myThread2->deleteLater();
498         myThread2 = 0;
499     }
500
501     for (int i = 1; i <= myNbThreads; i++)
502     {
503         TFunction_DriverTable::Get()->AddDriver(PointDriver::GetID(), new PointDriver(), i);
504         TFunction_DriverTable::Get()->AddDriver(CircleDriver::GetID(), new CircleDriver(), i);
505         TFunction_DriverTable::Get()->AddDriver(PrismDriver::GetID(), new PrismDriver(), i);
506         TFunction_DriverTable::Get()->AddDriver(ConeDriver::GetID(), new ConeDriver(), i);
507         TFunction_DriverTable::Get()->AddDriver(CylinderDriver::GetID(), new CylinderDriver(), i);
508         TFunction_DriverTable::Get()->AddDriver(ShapeSaverDriver::GetID(), new ShapeSaverDriver(), i);
509         TFunction_DriverTable::Get()->AddDriver(SimpleDriver::GetID(), new SimpleDriver(), i);
510     }
511 }
512
513 int GraphWidget::getNbThreads()
514 {
515     return myNbThreads;
516 }
517
518 void GraphWidget::setFinished()
519 {
520     myNbFinishedThreads++;
521 }
522
523 bool GraphWidget::isFinished()
524 {
525     return myNbThreads == myNbFinishedThreads ;
526 }
527
528 void GraphWidget::accelerateThread(const int thread_index)
529 {
530     bool all_slow = true;
531     if (myThread1 && myThread1->priority() != QThread::LowPriority)
532         all_slow = false;
533     if (all_slow && myThread2 && myThread2->priority() != QThread::LowPriority)
534         all_slow = false;
535     if (all_slow && myThread3 && myThread3->priority() != QThread::LowPriority)
536         all_slow = false;
537     if (all_slow && myThread4 && myThread4->priority() != QThread::LowPriority)
538         all_slow = false;
539     if (!all_slow)
540         return;
541
542     QThread::Priority priority = QThread::NormalPriority;
543     switch (thread_index)
544     {
545     case 1:
546         myThread1->setPriority(priority);
547         break;
548     case 2:
549         myThread2->setPriority(priority);
550         break;
551     case 3:
552         myThread3->setPriority(priority);
553         break;
554     case 4:
555         myThread4->setPriority(priority);
556         break;
557     }
558 }
559
560 void GraphWidget::slowDownThread(const int thread_index)
561 {
562     QThread::Priority priority = QThread::LowPriority;
563     switch (thread_index)
564     {
565     case 1:
566         myThread1->setPriority(priority);
567         break;
568     case 2:
569         myThread2->setPriority(priority);
570         break;
571     case 3:
572         myThread3->setPriority(priority);
573         break;
574     case 4:
575         myThread4->setPriority(priority);
576         break;
577     }
578 }