source: orange/source/orangeqt/networkcurve.cpp @ 10721:99d22150267d

Revision 10721:99d22150267d, 32.8 KB checked in by mstajdohar, 2 years ago (diff)

Fixes segfault on deleting nodes.

Line 
1/*
2    This file is part of the plot module for Orange
3    Copyright (C) 2011  Miha Čančula <miha@noughmad.eu>
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include "networkcurve.h"
20#include "point.h"
21
22#include <QtCore/QMap>
23#include <QtCore/QList>
24#include <QtGui/QTextBlockFormat>
25#include <QtGui/QTextCursor>
26
27#include <QtCore/qmath.h>
28#include <limits>
29#include <QStyleOptionGraphicsItem>
30#include <QCoreApplication>
31
32#include <QtCore/QTime>
33#include <QtCore/QParallelAnimationGroup>
34
35/************/
36/* NodeItem */ 
37/************/
38
39#define PI 3.14159265
40
41
42ModelItem::ModelItem(int index, int symbol, QColor color, int size, QGraphicsItem* parent): NodeItem(index, symbol, color, size, parent)
43{
44
45}
46
47void ModelItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
48{
49    NetworkCurve *curve = (NetworkCurve*)parentItem();
50    //bool on_marked_only = curve->labels_on_marked();
51
52    if (image != NULL)
53    {
54        const int ps = size() + 4;
55        double style = 1;
56        int _size = size() + 5;
57
58        painter->setPen(QPen(QBrush(color()), 1, Qt::SolidLine, Qt::RoundCap));
59
60        QRadialGradient gradient(QPointF(0, 0), _size);
61        gradient.setColorAt(0, color());
62        gradient.setColorAt(1, QColor(255, 255, 255, 0));
63
64        if (is_selected())
65        {
66            QColor brushColor(Qt::yellow);
67            brushColor.setAlpha(150);
68            gradient = QRadialGradient(QPointF(0, 0), _size);
69            gradient.setColorAt(0, brushColor);
70            gradient.setColorAt(1, QColor(255, 255, 255, 0));
71        }
72        else if (is_marked())
73        {
74            QColor brushColor(Qt::cyan);
75            brushColor.setAlpha(80);
76            gradient = QRadialGradient(QPointF(0, 0), _size);
77            gradient.setColorAt(0, brushColor);
78            gradient.setColorAt(1, QColor(255, 255, 255, 0));
79        }
80
81        painter->setBrush(QBrush(gradient));
82        painter->drawRoundedRect(-_size/2, -_size/2, _size, _size, style, style, Qt::RelativeSize);
83
84        _size = image->size().width();
85        painter->drawPixmap(QPointF(-_size/2, -_size/2), *image);
86        /*
87        if (!on_marked_only || is_marked() || is_selected())
88        {
89            QFontMetrics metrics = option->fontMetrics;
90            int th = metrics.height();
91            int tw = metrics.width(label());
92            QRect r(-tw/2, 0, tw, th);
93            //painter->fillRect(r, QBrush(Qt::white));
94            painter->drawText(r, Qt::AlignHCenter, label());
95        }
96        */
97    }
98    /*
99    else
100    {
101        const QString l = label();
102        if (on_marked_only && !(is_marked() || is_selected()))
103        {
104            set_label(QString());
105        }
106
107        Point::paint(painter, option, widget);
108
109        set_label(l);
110    }
111    */
112}
113
114NodeItem::NodeItem(int index, int symbol, QColor color, int size, QGraphicsItem* parent): Point(symbol, color, size, parent)
115{
116    set_index(index);
117    set_coordinates(((qreal)(qrand() % 1000)) * 1000, ((qreal)(qrand() % 1000)) * 1000);
118    setZValue(0.5);
119    m_size_value = 1;
120    set_marked(false);
121    set_selected(false);
122    //set_label("");
123    setAcceptHoverEvents(true);
124    set_transparent(false);
125    image = NULL;
126}
127
128NodeItem::~NodeItem()
129{
130}
131
132void NodeItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
133{
134    NetworkCurve *curve = (NetworkCurve*)parentItem();
135    /*
136    bool on_marked_only = curve->labels_on_marked_only();
137    const QString l = label();
138
139    if (on_marked_only && !(is_marked() || is_selected()))
140    {
141        set_label(QString());
142    }
143    */
144    if (image != NULL)
145    {
146        const int ps = size() + 4;
147        painter->drawPixmap(QPointF(-0.5*ps, -0.5*ps), *image);
148        /*
149        if (!label().isEmpty())
150        {
151            QFontMetrics metrics = option->fontMetrics;
152            int th = metrics.height();
153            int tw = metrics.width(label());
154            QRect r(-tw/2, 0, tw, th);
155            //painter->fillRect(r, QBrush(Qt::white));
156            painter->drawText(r, Qt::AlignHCenter, label());
157        }
158        */
159    }
160    else
161    {
162        Point::paint(painter, option, widget);
163    }
164
165    //set_label(l);
166}
167
168void NodeItem::set_image(QPixmap* im)
169{
170    image = im;
171}
172
173void NodeItem::set_coordinates(double x, double y)
174{
175    m_x = x;
176    m_y = y;
177   
178    DataPoint p;
179    p.x = m_x;
180    p.y = m_y;
181    Point::set_coordinates(p);
182}
183
184void NodeItem::set_index(int index)
185{
186    m_index = index;
187}
188
189int NodeItem::index() const
190{
191    return m_index;
192}
193
194void NodeItem::set_graph_transform(const QTransform& transform)
195{
196    m_graph_transform = transform;
197    set_coordinates(m_x, m_y);
198}
199
200QTransform NodeItem::graph_transform() const
201{
202    return m_graph_transform;
203}
204
205void NodeItem::set_x(double x)
206{
207    set_coordinates(x, m_y);
208}
209
210double NodeItem::x() const
211{
212    return m_x;
213}
214
215void NodeItem::set_y(double y)
216{
217    set_coordinates(m_x, y);
218}
219
220double NodeItem::y() const
221{
222    return m_y;
223}
224
225void NodeItem::set_tooltip(const QString& tooltip)
226{
227    setToolTip(tooltip);
228}
229
230void NodeItem::set_uuid(int uuid)
231{
232    m_uuid = uuid;
233}
234
235int NodeItem::uuid() const
236{
237    return m_uuid;
238}
239
240void NodeItem::add_connected_edge(EdgeItem* edge)
241{
242    if (!m_connected_edges.contains(edge))
243    {
244        m_connected_edges << edge;
245    }
246}
247
248void NodeItem::remove_connected_edge(EdgeItem* edge)
249{
250    m_connected_edges.removeAll(edge);
251}
252
253QList<EdgeItem*> NodeItem::connected_edges()
254{
255    return m_connected_edges;
256}
257
258QList<NodeItem*> NodeItem::neighbors()
259{
260    QList<NodeItem*> neighbors;
261
262    EdgeItem *e;
263    QList<EdgeItem*> edges = connected_edges();
264    int size = edges.size();
265    foreach(e, edges)
266    {
267        if (e->u()->index() == index())
268        {
269            neighbors.append(e->v());
270        }
271        else
272        {
273            neighbors.append(e->u());
274        }
275    }
276
277    return neighbors;
278}
279
280/************/
281/* EdgeItem */
282/************/
283
284QHash<ArrowData, QPixmap> EdgeItem::arrow_cache;
285
286uint qHash(const ArrowData& data)
287{
288    // uint has 32 bits:
289    uint ret = data.size;
290    // QRgb takes the full uins, so we just XOR by it
291    ret ^= data.color.rgba();
292    return ret;
293}
294
295bool operator==(const ArrowData& one, const ArrowData& other)
296{
297    return one.size == other.size && one.color == other.color;
298}
299
300EdgeItem::EdgeItem(NodeItem* u, NodeItem* v, QGraphicsItem* parent, QGraphicsScene* scene): QAbstractGraphicsShapeItem(parent, scene),
301m_u(0), m_v(0)
302{
303    set_u(u);
304    set_v(v);
305    QPen p = pen();
306    p.setWidthF(1);
307    p.setCosmetic(true);
308    setPen(p);
309    setZValue(0);
310    //setFlag(ItemIgnoresTransformations);
311}
312
313EdgeItem::~EdgeItem()
314{
315    if (m_u)
316    {
317        m_u->remove_connected_edge(this);
318    }
319    if (m_v)
320    {
321        m_v->remove_connected_edge(this);
322    }
323}
324
325
326void EdgeItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
327{
328    painter->setRenderHint(QPainter::Antialiasing, false);
329    painter->setPen(pen());
330    QLineF _line;
331    if (m_u && m_v)
332    {
333        _line.setPoints(m_u->pos(), m_v->pos());
334        painter->drawLine(_line);
335
336        if ((m_arrows & (ArrowU | ArrowV)) && m_u->pos() != m_v->pos())
337        {
338            double size = 10;
339            double half_size = 0.5 * size;
340            const ArrowData key(1, pen().color());
341            if (!arrow_cache.contains(key))
342            {
343                QBrush brush(key.color);
344                QPixmap pixmap(size, size);
345                pixmap.fill(Qt::transparent);
346                QPainter p;
347
348                QPen pen(key.color);
349                //pen.setWidth(0);
350                pen.setStyle(Qt::NoPen);
351
352                p.begin(&pixmap);
353                p.setRenderHints(painter->renderHints() | QPainter::Antialiasing);
354
355                QPainterPath path;
356                path.moveTo(half_size, 0);
357                path.lineTo(size, size);
358                path.lineTo(0, size);
359
360                p.setBrush(brush);
361                p.setPen(pen);
362                p.drawPath(path);
363                arrow_cache.insert(key, pixmap);
364            }
365            double x1 = m_u->pos().x();
366            double y1 = m_u->pos().y();
367            double x2 = m_v->pos().x();
368            double y2 = m_v->pos().y();
369            if (m_arrows & ArrowU)
370            {
371                double phi = atan2(y1-y2, x1-x2) * 180 / PI + 90;
372                painter->save();
373                painter->translate(m_u->pos());
374                painter->rotate(phi);
375                //painter->setViewTransformEnabled(false);
376                painter->drawPixmap(-half_size, 0.5 * m_u->size(), arrow_cache.value(key));
377                painter->restore();
378            }
379
380            if (m_arrows & ArrowV)
381            {
382                double phi = atan2(y2-y1, x2-x1) * 180 / PI + 90;
383                painter->save();
384                painter->translate(m_v->pos());
385                painter->rotate(phi);
386                //painter->setViewTransformEnabled(false);
387                painter->drawPixmap(-half_size, 0.5 * m_v->size(), arrow_cache.value(key));
388                painter->restore();
389            }
390        }
391    }
392
393    if (!m_label.isEmpty())
394    {
395        NetworkCurve *curve = (NetworkCurve*)parentItem();
396        bool on_marked_only = curve->labels_on_marked();
397        bool is_marked = (u()->is_marked() || u()->is_selected()) && (v()->is_marked() || v()->is_selected());
398
399        if(!on_marked_only || (on_marked_only && is_marked))
400        {
401            double x = (_line.x1() + _line.x2()) / 2;
402            double y = (_line.y1() + _line.y2()) / 2;
403            QFontMetrics metrics = option->fontMetrics;
404            int th = metrics.height();
405            int tw = metrics.width(m_label);
406            QRect r(x-tw/2, y-th/2, tw, th);
407            //painter->fillRect(r, QBrush(Qt::white));
408            QPen p = painter->pen();
409            p.setColor(Qt::black);
410            painter->setPen(p);
411            painter->drawText(r, Qt::AlignHCenter, m_label);
412        }
413    }
414}
415
416QRectF EdgeItem::boundingRect() const
417{
418    return QRectF(m_u->pos(), m_v->pos());
419}
420
421QPainterPath EdgeItem::shape() const
422{
423    QPainterPath path;
424    path.moveTo(m_u->pos());
425    path.lineTo(m_v->pos());
426    return path;
427}
428
429void EdgeItem::set_u(NodeItem* item)
430{
431    if (m_u)
432    {
433        m_u->remove_connected_edge(this);
434    }
435    if (item)
436    {
437        item->add_connected_edge(this);
438    }
439    m_u = item;
440}
441
442NodeItem* EdgeItem::u()
443{
444    return m_u;
445}
446
447void EdgeItem::set_v(NodeItem* item)
448{
449    if (m_v)
450    {
451        m_v->remove_connected_edge(this);
452    }
453    if (item)
454    {
455        item->add_connected_edge(this);
456    }
457    m_v = item;
458}
459
460NodeItem* EdgeItem::v()
461{
462    return m_v;
463}
464
465void EdgeItem::set_tooltip(const QString& tooltip)
466{
467    setToolTip(tooltip);
468}
469
470void EdgeItem::set_label(const QString& label)
471{
472    m_label = label;
473}
474
475QString EdgeItem::label() const
476{
477    return m_label;
478}
479
480void EdgeItem::set_links_index(int index)
481{
482    m_links_index = index;
483}
484
485int EdgeItem::links_index() const
486{
487    return m_links_index;
488}
489
490void EdgeItem::set_arrow(EdgeItem::Arrow arrow, bool enable)
491{
492    if (enable)
493    {
494        set_arrows(arrows() | arrow);
495    }
496    else
497    {
498        set_arrows(arrows() & ~arrow);
499    }
500}
501
502EdgeItem::Arrows EdgeItem::arrows()
503{
504    return m_arrows;
505}
506
507void EdgeItem::set_arrows(EdgeItem::Arrows arrows)
508{
509    m_arrows = arrows;
510    // TODO: Update the QGraphicsItem element, add arrows
511}
512
513void EdgeItem::set_weight(double weight)
514{
515    m_weight = weight;
516}
517
518double EdgeItem::weight() const
519{
520    return m_weight;
521}
522
523/****************/
524/* NetworkCurve */
525/****************/
526
527NetworkCurve::NetworkCurve(QGraphicsItem* parent): Curve(parent)
528{
529     m_min_node_size = 5;
530     m_max_node_size = 5;
531}
532
533NetworkCurve::~NetworkCurve()
534{
535    cancel_all_updates();
536    qDeleteAll(m_edges);
537    m_edges.clear();
538    qDeleteAll(m_nodes);
539    m_nodes.clear();
540    qDeleteAll(m_labels);
541    m_labels.clear();
542}
543
544
545void NetworkCurve::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
546{
547    NetworkCurve::paint(painter, option, widget);
548
549    if (m_show_component_distances)
550    {
551        // TODO: move code from Python to C++
552    }
553}
554
555
556void NetworkCurve::update_properties()
557{
558    const QTransform t = graph_transform();
559    update_point_positions();
560}
561
562QRectF NetworkCurve::data_rect() const
563{
564    QRectF r;
565    bool first = true;
566    foreach (const NodeItem* node, m_nodes)
567    {
568        if (first)
569        {
570            r = QRectF(node->x(), node->y(), 0, 0);
571            first = false;
572        }
573        else
574        {
575            r.setTop( qMin(r.top(), node->y()) );
576            r.setBottom( qMax(r.bottom(), node->y()) );
577            r.setLeft( qMin(r.left(), node->x()) );
578            r.setRight( qMax(r.right(), node->x()) );
579        }
580    }
581    return r;
582}
583
584int NetworkCurve::random()
585{
586    Nodes::ConstIterator uit = m_nodes.constBegin();
587    Nodes::ConstIterator uend = m_nodes.constEnd();
588
589    for (; uit != uend; ++uit)
590    {
591        uit.value()->set_coordinates(((qreal)(qrand() % 1000)) * 1000, ((qreal)(qrand() % 1000)) * 1000);
592    }
593
594    return 0;
595}
596
597#define PI 3.14159265
598
599int NetworkCurve::circular(CircularLayoutType type)
600{
601    // type
602    // 0 - original
603    // 1 - random
604    // 2 - crossing reduction
605
606    if (type == NetworkCurve::circular_crossing)
607    {
608        qDebug() << "crossing_reduction";
609        return circular_crossing_reduction();
610    }
611
612    if (type == NetworkCurve::circular_original)
613        qDebug() << "original";
614
615    if (type == NetworkCurve::circular_random)
616            qDebug() << "random";
617
618    QRectF rect = data_rect();
619    int xCenter = rect.width() / 2;
620    int yCenter = rect.height() / 2;
621    int r = (rect.width() < rect.height()) ? rect.width() * 0.38 : rect.height() * 0.38;
622
623    int i;
624    double fi = PI;
625    double step = 2 * PI / m_nodes.size();
626
627    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
628    std::vector<int> vertices;
629    Nodes::ConstIterator it;
630    for (it = m_nodes.constBegin(); it != m_nodes.constEnd(); ++it)
631    {
632        vertices.push_back(it.key());
633    }
634
635    for (i = 0; i < m_nodes.size(); ++i)
636    {
637        if (type == NetworkCurve::circular_original)
638        {
639            m_nodes[vertices[i]]->set_coordinates(r * cos(fi) + xCenter, r * sin(fi) + yCenter);
640        }
641        else if (type == NetworkCurve::circular_random)
642        {
643            int ndx = rand() % vertices.size();
644                        m_nodes[vertices[ndx]]->set_coordinates(r * cos(fi) + xCenter, r * sin(fi) + yCenter);
645            vertices.erase(vertices.begin() + ndx);
646        }
647        fi = fi - step;
648    }
649    register_points();
650    return 0;
651}
652
653
654int NetworkCurve::circular_crossing_reduction()
655{
656    QMap<int, QueueVertex*> qvertices;
657    std::vector<QueueVertex*> vertices;
658    std::vector<QueueVertex*> original;
659
660    Nodes::ConstIterator it;
661    for (it = m_nodes.constBegin(); it != m_nodes.constEnd(); ++it)
662    {
663        QueueVertex *vertex = new QueueVertex();
664        vertex->ndx = it.key();
665        qvertices[it.key()] = vertex;
666
667        std::vector<int> neighbours;
668        vertex->unplacedNeighbours = neighbours.size();
669        vertex->neighbours = neighbours;
670        vertices.push_back(vertex);
671    }
672    int i;
673    EdgeItem *edge;
674    for (i = 0; i < m_edges.size(); i++)
675    {
676        edge = m_edges[i];
677        int u = edge->u()->index();
678        int v = edge->v()->index();
679        qvertices[u]->neighbours.push_back(v);
680        qvertices[u]->unplacedNeighbours += 1;
681        qvertices[v]->neighbours.push_back(u);
682        qvertices[v]->unplacedNeighbours += 1;
683    }
684    original.assign(vertices.begin(), vertices.end());
685
686    std::deque<int> positions;
687    while (vertices.size() > 0)
688    {
689        std::sort(vertices.begin(), vertices.end(), QueueVertex());
690        QueueVertex *vertex = vertices.back();
691
692
693        // update neighbours
694        for (i = 0; i < vertex->neighbours.size(); ++i)
695        {
696            int ndx = vertex->neighbours[i];
697
698            original[ndx]->placedNeighbours++;
699            original[ndx]->unplacedNeighbours--;
700        }
701
702        // count left & right crossings
703        if (vertex->placedNeighbours > 0)
704        {
705            int left = 0;
706            std::vector<int> lCrossings;
707            std::vector<int> rCrossings;
708            for (i = 0; i < positions.size(); ++i)
709            {
710                int ndx = positions[i];
711
712                if (vertex->hasNeighbour(ndx))
713                {
714                    lCrossings.push_back(left);
715                    left += original[ndx]->unplacedNeighbours;
716                    rCrossings.push_back(left);
717                }
718                else
719                    left += original[ndx]->unplacedNeighbours;
720            }
721
722            int leftCrossings = 0;
723            int rightCrossings = 0;
724
725            for (i = 0; i < lCrossings.size(); --i)
726                leftCrossings += lCrossings[i];
727
728            rCrossings.push_back(left);
729            for (i = rCrossings.size() - 1; i > 0 ; --i)
730                rightCrossings += rCrossings[i] - rCrossings[i - 1];
731            //cout << "left: " << leftCrossings << " right: " <<rightCrossings << endl;
732            if (leftCrossings < rightCrossings)
733                positions.push_front(vertex->ndx);
734            else
735                positions.push_back(vertex->ndx);
736
737        }
738        else
739            positions.push_back(vertex->ndx);
740
741        vertices.pop_back();
742    }
743
744    // Circular sifting
745    for (i = 0; i < positions.size(); ++i)
746        original[positions[i]]->position = i;
747
748    int step;
749    for (step = 0; step < 5; ++step)
750    {
751        for (i = 0; i < m_nodes.size(); ++i)
752        {
753            bool stop = false;
754            int switchNdx = -1;
755            QueueVertex *u = original[positions[i]];
756            int vNdx = (i + 1) % m_nodes.size();
757
758            while (!stop)
759            {
760                QueueVertex *v = original[positions[vNdx]];
761
762                int midCrossings = u->neighbours.size() * v->neighbours.size() / 2;
763                int crossings = 0;
764                int j,k;
765                for (j = 0; j < u->neighbours.size(); ++j)
766                    for (k = 0; k < v->neighbours.size(); ++k)
767                        if ((original[u->neighbours[j]]->position == v->position) || (original[v->neighbours[k]]->position == u->position))
768                            midCrossings = (u->neighbours.size() - 1) * (v->neighbours.size() - 1) / 2;
769                        else if ((original[u->neighbours[j]]->position + m_nodes.size() - u->position) % m_nodes.size() < (original[v->neighbours[k]]->position + m_nodes.size() - u->position) % m_nodes.size())
770                            ++crossings;
771
772                //cout << "v: " <<  v->ndx << " crossings: " << crossings << " u.n.size: " << u->neighbours.size() << " v.n.size: " << v->neighbours.size() << " mid: " << midCrossings << endl;
773                if (crossings > midCrossings)
774                    switchNdx = vNdx;
775                else
776                    stop = true;
777
778                vNdx = (vNdx + 1) % m_nodes.size();
779            }
780            int j;
781            if (switchNdx > -1)
782            {
783                //cout << "u: " << u->ndx << " switch: " << original[switchNdx]->ndx << endl << endl;
784                positions.erase(positions.begin() + i);
785                positions.insert(positions.begin() + switchNdx, u->ndx);
786
787                for (j = i; j <= switchNdx; ++j)
788                    original[positions[j]]->position = j;
789            }
790            //else
791            //  cout << "u: " << u->ndx << " switch: " << switchNdx << endl;
792        }
793    }
794
795    QRectF rect = data_rect();
796    int xCenter = rect.width() / 2;
797    int yCenter = rect.height() / 2;
798    int r = (rect.width() < rect.height()) ? rect.width() * 0.38 : rect.height() * 0.38;
799    double fi = PI;
800    double fiStep = 2 * PI / m_nodes.size();
801
802    for (i = 0; i < m_nodes.size(); ++i)
803    {
804        m_nodes[positions[i]]->set_x(r * cos(fi) + xCenter);
805        m_nodes[positions[i]]->set_y(r * sin(fi) + yCenter);
806        fi = fi - fiStep;
807    }
808
809        qDeleteAll(original);
810
811    original.clear();
812    vertices.clear();
813    qvertices.clear();
814       
815        register_points();
816       
817    return 0;
818}
819
820int NetworkCurve::fr(int steps, bool weighted, bool smooth_cooling)
821{
822    int i, j;
823    int count = 0;
824    NodeItem *u, *v;
825    EdgeItem *edge;
826    m_stop_optimization = false;
827
828    double rect[4] = {std::numeric_limits<double>::max(),
829              std::numeric_limits<double>::max(),
830              std::numeric_limits<double>::min(),
831              std::numeric_limits<double>::min()};
832
833    QMap<int, DataPoint> disp;
834    foreach (const NodeItem*   node, m_nodes)
835    {
836        disp[node->index()] = node->coordinates();
837
838        double x = node->x();
839        double y = node->y();
840        if (rect[0] > x) rect[0] = x;
841        if (rect[1] > y) rect[1] = y;
842        if (rect[2] < x) rect[2] = x;
843        if (rect[3] < y) rect[3] = y;
844    }
845    QRectF data_r(rect[0], rect[1], rect[2]-rect[0], rect[3]-rect[1]);
846    double area = data_r.width() * data_r.height();
847    double k2 = area / m_nodes.size();
848    double k = sqrt(k2);
849    double kk = 2 * k;
850    double kk2 = kk * kk;
851    double jitter = sqrt(area) / 2000;
852    double temperature, cooling, cooling_switch, cooling_1, cooling_2;
853    temperature = sqrt(area) / 5;
854    cooling = exp(log(k / 10 / temperature) / steps);
855
856    if (steps > 20)
857    {
858        cooling_switch = sqrt(area) / 100;
859        cooling_1 = (temperature - cooling_switch) / 20;
860        cooling_2 = (cooling_switch - sqrt(area) / 2000 ) / (steps - 20);
861    }
862    else
863    {
864        cooling_switch = sqrt(area) / 1000;
865        cooling_1 = (temperature - cooling_switch) / steps;
866        cooling_2 = 0;
867    }
868
869    if (smooth_cooling)
870    {
871        if (steps < 20)
872        {
873            steps = 20;
874        }
875        temperature = cooling_switch;
876        cooling_1 = 0;
877        cooling_2 = (cooling_switch - sqrt(area) / 2000 ) / steps;
878    }
879
880    // iterations
881    //clock_t refresh_time = clock() + 0.05 * CLOCKS_PER_SEC;
882    Plot *p = plot();
883    bool animation_enabled = p->animate_points;
884    p->animate_points = false;
885
886    QTime refresh_time = QTime::currentTime();
887    for (i = 0; i < steps; ++i)
888    {
889        foreach (const NodeItem* node, m_nodes)
890        {
891            disp[node->index()].x = 0;
892            disp[node->index()].y = 0;
893        }
894
895        // calculate repulsive force
896        Nodes::ConstIterator uit = m_nodes.constBegin();
897        Nodes::ConstIterator uend = m_nodes.constEnd();
898        for (; uit != uend; ++uit)
899        {
900            u = uit.value();
901            Nodes::ConstIterator vit(uit);
902            ++vit;
903            for (; vit != uend; ++vit)
904            {
905                v = vit.value();
906
907                double difx = u->x() - v->x();
908                double dify = u->y() - v->y();
909
910                double dif2 = difx * difx + dify * dify;
911
912                // if nodes are close, apply repulsive force
913                if (dif2 < kk2)
914                {
915                    // if nodes overlap
916                    if (dif2 == 0)
917                    {
918                        dif2 = 1 / k;
919                        u->set_x(u->x() + jitter);
920                        u->set_y(u->y() + jitter);
921                        v->set_x(v->x() - jitter);
922                        v->set_y(v->y() - jitter);
923                    }
924
925                    double dX = difx * k2 / dif2;
926                    double dY = dify * k2 / dif2;
927
928                    disp[u->index()].x += dX;
929                    disp[u->index()].y += dY;
930
931                    disp[v->index()].x -= dX;
932                    disp[v->index()].y -= dY;
933                }
934            }
935        }
936        // calculate attractive forces
937        for (j = 0; j < m_edges.size(); ++j)
938        {
939            edge = m_edges[j];
940            double difx = edge->u()->x() - edge->v()->x();
941            double dify = edge->u()->y() - edge->v()->y();
942
943            double dif = sqrt(difx * difx + dify * dify);
944
945            double dX = difx * dif / k;
946            double dY = dify * dif / k;
947
948            if (weighted) {
949                dX *= edge->weight();
950                dY *= edge->weight();
951            }
952
953            disp[edge->u()->index()].x -= dX;
954            disp[edge->u()->index()].y -= dY;
955
956            disp[edge->v()->index()].x += dX;
957            disp[edge->v()->index()].y += dY;
958        }
959
960        // limit the maximum displacement to the temperature t
961        // and then prevent from being displaced outside frame
962        Nodes::Iterator nit = m_nodes.begin();
963        for (; nit != m_nodes.end(); ++nit)
964        {
965            u = nit.value();
966            double dif = sqrt(disp[u->index()].x * disp[u->index()].x + disp[u->index()].y * disp[u->index()].y);
967
968            if (dif == 0)
969                dif = 1;
970
971            u->set_coordinates(u->x() + (disp[u->index()].x * qMin(fabs(disp[u->index()].x), temperature) / dif),
972                               u->y() + (disp[u->index()].y * qMin(fabs(disp[u->index()].y), temperature) / dif));
973        }
974
975        QTime before_refresh_time = QTime::currentTime();
976        if (before_refresh_time > refresh_time && i % 2 == 0)
977        {
978            update_properties();
979            QCoreApplication::processEvents();
980            int refresh_duration = before_refresh_time.msecsTo(QTime::currentTime());
981
982            refresh_time = before_refresh_time.addMSecs(qMax(refresh_duration * 3, 10));
983        }
984        if (m_stop_optimization)
985        {
986            break;
987        }
988        if (floor(temperature) > cooling_switch)
989        {
990            temperature -= cooling_1;
991        }
992        else
993        {
994            temperature -= cooling_2;
995        }
996    }
997
998    p->animate_points = animation_enabled;
999    register_points();
1000    return 0;
1001}
1002
1003NetworkCurve::Labels NetworkCurve::labels() const
1004{
1005    return m_labels;
1006}
1007
1008void NetworkCurve::set_labels(const NetworkCurve::Labels& labels)
1009{
1010    cancel_all_updates();
1011    qDeleteAll(m_labels);
1012    m_labels = labels;
1013    //Q_ASSERT(m_labels.uniqueKeys() == m_labels.keys());
1014    //register_points();
1015}
1016
1017void NetworkCurve::add_labels(const NetworkCurve::Labels& labels)
1018{
1019    Labels::ConstIterator it = labels.constBegin();
1020    Labels::ConstIterator end = labels.constEnd();
1021    QList<int> indices;
1022    for (it; it != end; ++it)
1023    {
1024        indices.append(it.key());
1025
1026        if (m_labels.contains(it.key()))
1027        {
1028            remove_label(it.key());
1029        }
1030    }
1031
1032    m_labels.unite(labels);
1033    Q_ASSERT(m_labels.uniqueKeys() == m_labels.keys());
1034    //register_points();
1035}
1036
1037void NetworkCurve::remove_label(int index)
1038{
1039    cancel_all_updates();
1040    if (!m_labels.contains(index))
1041    {
1042        qWarning() << "Trying to remove label for node " << index << " which is not in the network";
1043        return;
1044    }
1045    QGraphicsItem* label = m_labels.take(index);
1046    //Q_ASSERT(node->index() == index);
1047    /*
1048    Plot* p = plot();
1049    if (p)
1050    {
1051        p->remove_point(node, this);
1052    }
1053    */
1054    delete label;
1055}
1056
1057void NetworkCurve::remove_labels(const QList<int>& labels)
1058{
1059    cancel_all_updates();
1060    foreach (int i, labels)
1061    {
1062        remove_label(i);
1063    }
1064
1065}
1066
1067void NetworkCurve::set_edges(const NetworkCurve::Edges& edges)
1068{
1069    cancel_all_updates();
1070    qDeleteAll(m_edges);
1071    m_edges = edges;
1072}
1073
1074NetworkCurve::Edges NetworkCurve::edges() const
1075{
1076    return m_edges;
1077}
1078
1079QList<QPair<int, int> > NetworkCurve::edge_indices()
1080{
1081    int i;
1082    EdgeItem *e;
1083    QList<QPair<int, int> > edge_indices;
1084
1085    for (i = 0; i < m_edges.size(); ++i)
1086    {
1087        e = m_edges[i];
1088        edge_indices.append(QPair<int, int>(e->u()->index(), e->v()->index()));
1089    }
1090
1091    return edge_indices;
1092}
1093
1094void NetworkCurve::set_nodes(const NetworkCurve::Nodes& nodes)
1095{
1096    cancel_all_updates();
1097    qDeleteAll(m_edges);
1098    m_edges.clear();
1099    qDeleteAll(m_nodes);
1100    m_nodes = nodes;
1101    Q_ASSERT(m_nodes.uniqueKeys() == m_nodes.keys());
1102    register_points();
1103}
1104
1105NetworkCurve::Nodes NetworkCurve::nodes() const
1106{
1107    return m_nodes;
1108}
1109
1110void NetworkCurve::remove_nodes(const QList<int>& nodes)
1111{
1112    cancel_all_updates();
1113    foreach (int i, nodes)
1114    {
1115        remove_node(i);
1116    }
1117}
1118
1119void NetworkCurve::remove_node(int index)
1120{
1121    cancel_all_updates();
1122    if (!m_nodes.contains(index))
1123    {
1124        qWarning() << "Trying to remove node" << index << "which is not in the network";
1125        return;
1126    }
1127    NodeItem* node = m_nodes.take(index);
1128    Q_ASSERT(node->index() == index);
1129
1130    if (node->label != NULL)
1131    {
1132        remove_label(index);
1133        node->label = NULL;
1134    }
1135
1136    Plot* p = plot();
1137    if (p)
1138    {
1139        p->remove_point(node, this);
1140    }
1141   
1142    foreach (EdgeItem* edge, node->connected_edges())
1143    {
1144        m_edges.removeOne(edge);
1145        delete edge;
1146    }
1147    Q_ASSERT(node->connected_edges().isEmpty());
1148    delete node;
1149}
1150
1151void NetworkCurve::add_edges(const NetworkCurve::Edges& edges)
1152{
1153    m_edges.append(edges);
1154}
1155
1156void NetworkCurve::add_nodes(const NetworkCurve::Nodes& nodes)
1157{
1158    Nodes::ConstIterator it = nodes.constBegin();
1159    Nodes::ConstIterator end = nodes.constEnd();
1160    QList<int> indices;
1161    for (it; it != end; ++it)
1162    {
1163        indices.append(it.key());
1164
1165        if (m_nodes.contains(it.key()))
1166        {
1167            remove_node(it.key());
1168        }
1169    }
1170
1171    m_nodes.unite(nodes);
1172    Q_ASSERT(m_nodes.uniqueKeys() == m_nodes.keys());
1173    register_points();
1174}
1175
1176void NetworkCurve::set_node_colors(const QMap<int, QColor>& colors)
1177{
1178    QMap<int, QColor>::ConstIterator it;
1179    for (it = colors.constBegin(); it != colors.constEnd(); ++it)
1180    {
1181        m_nodes[it.key()]->set_color(it.value());
1182    }
1183}
1184
1185void NetworkCurve::set_node_sizes(const QMap<int, double>& sizes, double min_size, double max_size)
1186{
1187    cancel_all_updates();
1188
1189    NodeItem* node;
1190    Nodes::ConstIterator nit;
1191
1192    double min_size_value = std::numeric_limits<double>::max();
1193    double max_size_value = std::numeric_limits<double>::min();
1194
1195    QMap<int, double>::ConstIterator it;
1196    for (it = sizes.begin(); it != sizes.end(); ++it)
1197    {
1198        m_nodes[it.key()]->m_size_value = it.value();
1199
1200        if (it.value() < min_size_value)
1201        {
1202            min_size_value = it.value();
1203        }
1204
1205        if (it.value() > max_size_value)
1206        {
1207            max_size_value = it.value();
1208        }
1209    }
1210
1211    // find min and max size value in nodes dict
1212    bool min_changed = true;
1213    bool max_changed = true;
1214    for (nit = m_nodes.constBegin(); nit != m_nodes.constEnd(); ++nit)
1215    {
1216        node = nit.value();
1217
1218        if (node->m_size_value < min_size_value)
1219        {
1220            min_size_value = node->m_size_value;
1221            min_changed = false;
1222        }
1223
1224        if (node->m_size_value > max_size_value)
1225        {
1226            max_size_value = node->m_size_value;
1227            max_changed = false;
1228        }
1229    }
1230
1231    double size_span = max_size_value - min_size_value;
1232
1233
1234    if (min_size > 0 || max_size > 0 || min_changed || max_changed)
1235    {
1236        if (min_size > 0)
1237        {
1238            m_min_node_size = min_size;
1239        }
1240
1241        if (max_size > 0)
1242        {
1243            m_max_node_size = max_size;
1244        }
1245
1246        double node_size_span = m_max_node_size - m_min_node_size;
1247        // recalibrate all
1248        if (size_span > 0)
1249        {
1250            for (nit = m_nodes.constBegin(); nit != m_nodes.constEnd(); ++nit)
1251            {
1252                node = nit.value();
1253                node->set_size((node->m_size_value - min_size_value) / size_span * node_size_span + m_min_node_size);
1254            }
1255        }
1256        else
1257        {
1258            for (nit = m_nodes.constBegin(); nit != m_nodes.constEnd(); ++nit)
1259            {
1260                node = nit.value();
1261                node->set_size(m_min_node_size);
1262            }
1263        }
1264    }
1265    else if (sizes.size() > 0)
1266    {
1267        double node_size_span = m_max_node_size - m_min_node_size;
1268        // recalibrate given
1269        if (size_span > 0)
1270        {
1271            for (it = sizes.begin(); it != sizes.end(); ++it)
1272            {
1273                node = m_nodes[it.key()];
1274                node->set_size((node->m_size_value - min_size_value) / size_span * node_size_span + m_min_node_size);
1275            }
1276        }
1277        else
1278        {
1279            for (it = sizes.begin(); it != sizes.end(); ++it)
1280            {
1281                node = m_nodes[it.key()];
1282                node->set_size(m_min_node_size);
1283            }
1284        }
1285    }
1286}
1287
1288void NetworkCurve::set_node_labels(const QMap<int, QString>& labels)
1289{
1290    cancel_all_updates();
1291    foreach (int i, m_labels.keys())
1292    {
1293        m_nodes[i]->label = NULL;
1294    }
1295    qDeleteAll(m_labels);
1296    m_labels.clear();
1297    QMap<int, QString>::ConstIterator it;
1298    for (it = labels.constBegin(); it != labels.constEnd(); ++it)
1299    {
1300        LabelItem* item = new LabelItem(it.value(), this);
1301        item->setZValue(0.6);
1302        item->setFont(plot()->font());
1303        item->setFlag(ItemIgnoresTransformations);
1304        //item->setPos(m_nodes[it.key()]->pos() - QPointF(item->boundingRect().width() / 2, 0));
1305        item->setPos(m_nodes[it.key()]->pos());
1306
1307        /*
1308        QFontMetrics fm(item->font());
1309        QTransform t;
1310        t.translate(-(fm.width(it.value()) / 2), -5);
1311        item->setTransform(t);
1312        item->setTextWidth(item->boundingRect().width());
1313        QTextBlockFormat format;
1314        format.setAlignment(Qt::AlignHCenter);
1315        QTextCursor cursor = item->textCursor();
1316        cursor.select(QTextCursor::Document);
1317        cursor.mergeBlockFormat(format);
1318        cursor.clearSelection();
1319        item->setTextCursor(cursor);
1320        */
1321        if (labels_on_marked() && !(m_nodes[it.key()]->is_marked() || m_nodes[it.key()]->is_selected()))
1322        {
1323            item->hide();
1324        }
1325        m_nodes[it.key()]->label = item;
1326        m_labels.insert(it.key(), item);
1327    }
1328}
1329
1330void NetworkCurve::set_node_tooltips(const QMap<int, QString>& tooltips)
1331{
1332    cancel_all_updates();
1333    QMap<int, QString>::ConstIterator it;
1334    for (it = tooltips.constBegin(); it != tooltips.constEnd(); ++it)
1335    {
1336        m_nodes[it.key()]->setToolTip(it.value());
1337    }
1338}
1339
1340void NetworkCurve::set_node_marks(const QMap<int, bool>& marks)
1341{
1342    cancel_all_updates();
1343    QMap<int, bool>::ConstIterator it;
1344    for (it = marks.constBegin(); it != marks.constEnd(); ++it)
1345    {
1346        m_nodes[it.key()]->set_marked(it.value());
1347    }
1348
1349    plot()->emit_marked_points_changed();
1350}
1351
1352void NetworkCurve::clear_node_marks()
1353{
1354    cancel_all_updates();
1355    Nodes::Iterator it;
1356    for (it = m_nodes.begin(); it != m_nodes.end(); ++it)
1357    {
1358        it.value()->set_marked(false);
1359    }
1360
1361    plot()->emit_marked_points_changed();
1362}
1363
1364void NetworkCurve::set_node_coordinates(const QMap<int, QPair<double, double> >& coordinates)
1365{
1366    NodeItem *node;
1367    QMap<int, QPair<double, double> >::ConstIterator it = coordinates.constBegin();
1368    for (; it != coordinates.constEnd(); ++it)
1369    {
1370        node = m_nodes[it.key()];
1371        node->set_x(it.value().first);
1372        node->set_y(it.value().second);
1373    }
1374    register_points();
1375}
1376
1377void NetworkCurve::set_edge_colors(const QList<QColor>& colors)
1378{
1379    cancel_all_updates();
1380    int i;
1381    for (i = 0; i < colors.size(); ++i)
1382    {
1383        QPen p = m_edges[i]->pen();
1384        p.setColor(colors[i]);
1385        m_edges[i]->setPen(p);
1386    }
1387}
1388
1389void NetworkCurve::set_edge_sizes(double max_size)
1390{
1391    cancel_all_updates();
1392
1393    double min_size_value = std::numeric_limits<double>::max();
1394    double max_size_value = std::numeric_limits<double>::min();
1395
1396    int i;
1397    for (i = 0; i < m_edges.size(); ++i)
1398    {
1399        double w = m_edges[i]->weight();
1400        if (w < min_size_value)
1401        {
1402            min_size_value = w;
1403        }
1404        if (w > max_size_value)
1405        {
1406            max_size_value = w;
1407        }
1408    }
1409
1410    double size_span = max_size_value - min_size_value;
1411    double edge_size_span = (max_size > 0) ? max_size - 1 : 0;
1412
1413    if (size_span > 0 && edge_size_span > 0)
1414    {
1415        for (i = 0; i < m_edges.size(); ++i)
1416        {
1417            double w = m_edges[i]->weight();
1418            QPen p = m_edges[i]->pen();
1419            p.setWidthF((w - min_size_value) / size_span * edge_size_span + 1);
1420            m_edges[i]->setPen(p);
1421        }
1422    }
1423    else
1424    {
1425        for (i = 0; i < m_edges.size(); ++i)
1426        {
1427            QPen p = m_edges[i]->pen();
1428            p.setWidthF(1);
1429            m_edges[i]->setPen(p);
1430        }
1431    }
1432}
1433
1434void NetworkCurve::set_edge_labels(const QList<QString>& labels)
1435{
1436    cancel_all_updates();
1437    int i;
1438    for (i = 0; i < labels.size(); ++i)
1439    {
1440        m_edges[i]->set_label(labels[i]);
1441    }
1442}
1443
1444void NetworkCurve::set_min_node_size(double size)
1445{
1446    set_node_sizes(QMap<int, double>(), size, 0);
1447}
1448
1449double NetworkCurve::min_node_size() const
1450{
1451    return m_min_node_size;
1452}
1453
1454void NetworkCurve::set_max_node_size(double size)
1455{
1456    set_node_sizes(QMap<int, double>(), 0, size);
1457}
1458
1459double NetworkCurve::max_node_size() const
1460{
1461    return m_max_node_size;
1462}
1463
1464void NetworkCurve::register_points()
1465{
1466    QList<Point*> list;
1467    foreach (NodeItem* node, m_nodes)
1468    {
1469        list << node;
1470    }
1471    set_points(list);
1472    Curve::register_points();
1473}
1474
1475void NetworkCurve::set_use_animations(bool use_animations)
1476{
1477    m_use_animations = use_animations;
1478}
1479
1480bool NetworkCurve::use_animations() const
1481{
1482    return m_use_animations;
1483}
1484
1485void NetworkCurve::set_show_component_distances(bool show_component_distances)
1486{
1487    m_show_component_distances = show_component_distances;
1488}
1489 
1490void NetworkCurve::stop_optimization()
1491{
1492    m_stop_optimization = true;
1493}
Note: See TracBrowser for help on using the repository browser.