source: orange/source/orangeqt/networkcurve.cpp @ 10923:6e12b80e24c1

Revision 10923:6e12b80e24c1, 33.7 KB checked in by mstajdohar, 22 months ago (diff)

Added a margin around graph.

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