1 /****************************************************************************
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the examples of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
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
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.
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."
39 ****************************************************************************/
41 #include "graphwidget.h"
45 #include <Standard_WarningsDisable.hxx>
47 #include <Standard_WarningsRestore.hxx>
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>
59 #include <TDataStd_Name.hxx>
60 #include <TDF_ChildIterator.hxx>
61 #include <TDF_ListIteratorOfLabelList.hxx>
62 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
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"
74 GraphWidget::GraphWidget(QWidget *parent)
75 : QGraphicsView(parent), timerId(0),
76 myThread1(0),myThread2(0),myThread3(0),myThread4(0)
78 QGraphicsScene *scene = new QGraphicsScene(this);
79 scene->setItemIndexMethod(QGraphicsScene::NoIndex);
80 scene->setSceneRect(-200, -200, 400, 400);
82 setCacheMode(CacheBackground);
83 setViewportUpdateMode(BoundingRectViewportUpdate);
84 setRenderHint(QPainter::Antialiasing);
85 setTransformationAnchor(AnchorUnderMouse);
87 scale(qreal(0.8), qreal(0.8));
88 setMinimumSize(400, 400);
89 setWindowTitle(tr("Function Mechanism"));
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));
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);
141 GraphWidget::~GraphWidget()
146 myThread1->deleteLater();
151 myThread2->deleteLater();
156 myThread3->deleteLater();
161 myThread4->deleteLater();
165 bool GraphWidget::createModel(const Handle(TDocStd_Document)& doc)
169 TFunction_Iterator fIterator(myDocument->Main());
170 fIterator.SetUsageOfExecutionStatus(false);
171 Handle(TFunction_Scope) scope = TFunction_Scope::Set(myDocument->Main());
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())
177 const TDF_LabelList& funcs = fIterator.Current();
178 if (funcs.Extent() > nbx)
179 nbx = funcs.Extent();
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
191 double x = x0, y = y0;
192 fIterator.Init(myDocument->Main());
193 while (!fIterator.Current().IsEmpty())
195 const TDF_LabelList& funcs = fIterator.Current();
196 TDF_ListIteratorOfLabelList itrl(funcs);
197 for (; itrl.More(); itrl.Next())
199 TDF_Label L = itrl.Value();
200 Node *node = new Node(this);
201 node->setFunction(L);
202 scene()->addItem(node);
216 fIterator.Init(myDocument->Main());
217 while (!fIterator.Current().IsEmpty())
219 const TDF_LabelList& funcs = fIterator.Current();
220 TDF_ListIteratorOfLabelList itrl(funcs);
221 for (; itrl.More(); itrl.Next())
223 TDF_Label L = itrl.Value();
224 Node* node = findNode(L);
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())
235 const int argID = itrm.Key();
236 const TDF_Label& argL = scope->GetFunction(argID);
237 Node* n = findNode(argL);
240 scene()->addItem(new Edge(n, node));
246 return !myDocument.IsNull();
250 void GraphWidget::itemMoved()
253 timerId = startTimer(1000 / 25);
258 void GraphWidget::keyPressEvent(QKeyEvent *event)
260 switch (event->key()) {
262 centerNode->moveBy(0, -20);
265 centerNode->moveBy(0, 20);
268 centerNode->moveBy(-20, 0);
271 centerNode->moveBy(20, 0);
284 QGraphicsView::keyPressEvent(event);
290 void GraphWidget::timerEvent(QTimerEvent *event)
295 foreach (QGraphicsItem *item, scene()->items()) {
296 if (Node *node = qgraphicsitem_cast<Node *>(item))
300 foreach (Node *node, nodes)
301 node->calculateForces();
303 bool itemsMoved = false;
304 foreach (Node *node, nodes) {
317 void GraphWidget::wheelEvent(QWheelEvent *event)
319 scaleView(pow((double)2, -event->delta() / 240.0));
324 void GraphWidget::drawBackground(QPainter* painter, const QRectF &rect)
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);
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);
346 //#if !defined(Q_OS_SYMBIAN) && !defined(Q_WS_MAEMO_5)
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"));
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);
366 void GraphWidget::scaleView(qreal scaleFactor)
368 qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
369 if (factor < 0.07 || factor > 100)
372 scale(scaleFactor, scaleFactor);
376 void GraphWidget::shuffle()
378 foreach (QGraphicsItem *item, scene()->items()) {
379 if (qgraphicsitem_cast<Node *>(item))
380 item->setPos(-150 + qrand() % 300, -150 + qrand() % 300);
384 void GraphWidget::zoomIn()
386 scaleView(qreal(1.2));
389 void GraphWidget::zoomOut()
391 scaleView(1 / qreal(1.2));
395 // Find node of the function
396 Node* GraphWidget::findNode(const TDF_Label& L)
399 for (int i = 0; i < scene()->items().size(); i++)
401 Node* n = qgraphicsitem_cast<Node *>(scene()->items().at(i));
402 if (n && n->getFunction() == L)
411 void GraphWidget::compute()
413 myNbFinishedThreads = 0;
415 TFunction_Iterator fIterator(myDocument->Main());
416 fIterator.SetUsageOfExecutionStatus(true);
418 myThread1 = new FThread();
420 myThread2 = new FThread();
422 myThread3 = new FThread();
424 myThread4 = new FThread();
427 Handle(TFunction_Logbook) log = TFunction_Scope::Set(myDocument->Main())->GetLogbook();
428 myThread1->setLogbook(log);
430 myThread2->setLogbook(log);
432 myThread3->setLogbook(log);
434 myThread4->setLogbook(log);
436 myThread1->setIterator(fIterator);
438 myThread2->setIterator(fIterator);
440 myThread3->setIterator(fIterator);
442 myThread4->setIterator(fIterator);
444 myThread1->setGraph(this);
446 myThread2->setGraph(this);
448 myThread3->setGraph(this);
450 myThread4->setGraph(this);
452 myThread1->setThreadIndex(1);
454 myThread2->setThreadIndex(2);
456 myThread3->setThreadIndex(3);
458 myThread4->setThreadIndex(4);
460 myThread1->setMutex(&myMutex);
462 myThread2->setMutex(&myMutex);
464 myThread3->setMutex(&myMutex);
466 myThread4->setMutex(&myMutex);
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);
479 void GraphWidget::setNbThreads(const int nb)
482 if (myNbThreads < 4 && myThread4)
485 myThread4->deleteLater();
488 if (myNbThreads < 3 && myThread3)
491 myThread3->deleteLater();
494 if (myNbThreads < 2 && myThread2)
497 myThread2->deleteLater();
501 for (int i = 1; i <= myNbThreads; i++)
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);
513 int GraphWidget::getNbThreads()
518 void GraphWidget::setFinished()
520 myNbFinishedThreads++;
523 bool GraphWidget::isFinished()
525 return myNbThreads == myNbFinishedThreads ;
528 void GraphWidget::accelerateThread(const int thread_index)
530 bool all_slow = true;
531 if (myThread1 && myThread1->priority() != QThread::LowPriority)
533 if (all_slow && myThread2 && myThread2->priority() != QThread::LowPriority)
535 if (all_slow && myThread3 && myThread3->priority() != QThread::LowPriority)
537 if (all_slow && myThread4 && myThread4->priority() != QThread::LowPriority)
542 QThread::Priority priority = QThread::NormalPriority;
543 switch (thread_index)
546 myThread1->setPriority(priority);
549 myThread2->setPriority(priority);
552 myThread3->setPriority(priority);
555 myThread4->setPriority(priority);
560 void GraphWidget::slowDownThread(const int thread_index)
562 QThread::Priority priority = QThread::LowPriority;
563 switch (thread_index)
566 myThread1->setPriority(priority);
569 myThread2->setPriority(priority);
572 myThread3->setPriority(priority);
575 myThread4->setPriority(priority);