5
#include "graph_renderer.h"
8
const int GraphRenderer::K1F;
9
const int GraphRenderer::K1N;
10
const int GraphRenderer::K2;
11
const int GraphRenderer::K3;
16
// algorithm by D.E.Knuth (TAOCP Vol.3 Sec. 4.2.2)
17
static bool eq(double d1, double d2)
21
long long i1 = * (long long*) &d1;
22
long long i2 = * (long long*) &d2;
26
i1 = -i1;//0x8000000000000000 - i1;
30
i2 = -i2;//0x8000000000000000 - i2;
33
long long v = i1 - i2;
43
static inline bool edge_is_special(GraphEdge& edge)
45
return edge.is_special();
48
static inline void reset_visited(GraphNode *node)
50
node->set_visited(false);
53
double GraphNode::distance(const GraphNode& n1, const GraphNode& n2)
55
double xdist, left, right, leftw;
56
double ydist, top, bottom, toph;
58
if(n1._left < n2._left)
71
xdist = right - left - leftw;
90
ydist = bottom - top - toph;
96
return sqrt(xdist*xdist + ydist*ydist);
99
bool operator == (const GraphNode& n1, const GraphNode& n2)
101
return (n1._left == n2._left) && (n1._top == n2._top) && (n1._width == n2._width) && (n1._height == n2._height);
104
GraphRenderer::GraphRenderer(double margin, double maxwidth, double maxheight)
105
: focus_recalced(false), _length(50), _left(0), _top(0), _right(200), _bottom(200), _avg_force(-1)
112
GraphRenderer::~GraphRenderer()
114
GraphNodeRefList::iterator e= _allnodes.end();
115
for(GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
121
void GraphRenderer::mark_neighbours(const GraphNode& node)
123
std::for_each(_allnodes.begin(), _allnodes.end(), reset_visited);
125
for(GraphEdgeList::const_iterator it= _alledges.begin(); it != _alledges.end(); ++it)
130
e.get_other(node).set_visited(true);
135
bool GraphRenderer::is_focus_node(const GraphNode& node) const
139
for(GraphEdgeList::const_iterator edgeit= _alledges.begin(); edgeit != _alledges.end(); edgeit++)
141
GraphEdge e= *edgeit;
153
// horizontal with vertical
154
static inline bool hv_lines_intersect(double x11, double x12, double y1, double x2, double y21, double y22)
156
return (x2 >= x11) && (x2 <= x12) && (y1 >= y21) && (y1 <= y22);
159
static inline bool nodes_intersect(double l, double t, double w, double h,
160
double ol, double ot, double ow, double oh)
162
// to simplify things
163
// this doesn't test full inclusion (which is very improbable)
164
return hv_lines_intersect(l, l+w, t, ol, ot, ot+oh)
165
|| hv_lines_intersect(l, l+w, t+h, ol, ot, ot+oh)
166
|| hv_lines_intersect(l, l+w, t, ol+ow, ot, ot+oh)
167
|| hv_lines_intersect(l, l+w, t+h, ol+ow, ot, ot+oh)
168
|| hv_lines_intersect(ol, ol+ow, ot, l, t, t+h)
169
|| hv_lines_intersect(ol, ol+ow, ot+oh, l, t, t+h)
170
|| hv_lines_intersect(ol, ol+ow, ot, l+w, t, t+h)
171
|| hv_lines_intersect(ol, ol+ow, ot+oh, l+w, t, t+h);
174
bool GraphRenderer::has_intersections() const
176
GraphNodeRefList::const_iterator e= _allnodes.end();
177
for(GraphNodeRefList::const_iterator it= _allnodes.begin(); it != e; ++it)
179
GraphNode& node= **it;
180
double l= node.left();
181
double t= node.top();
182
double w= node.width();
183
double h= node.height();
185
GraphNodeRefList::const_iterator it2= it;
187
for(; it2 != e; it2++)
189
GraphNode& other= **it2;
190
double ol= other.left();
191
double ot= other.top();
192
double ow= other.width();
193
double oh= other.height();
195
bool ix= nodes_intersect(l, t, w, h, ol, ot, ow, oh);
203
void GraphRenderer::get_delta(const GraphNode& node, double *deltax, double *deltay)
205
static const int NNODES= 2;
207
mark_neighbours(node);
209
double ccx= node.left();
210
double ccy= node.top();
211
bool node_is_focus= node.is_focus();
213
double all_sum_x= 0.;
214
double all_sum_y= 0.;
216
GraphNodeRefList::iterator e= _allnodes.end();
217
for(GraphNodeRefList::const_iterator it= _allnodes.begin(); it != e; ++it)
219
const GraphNode* nei[NNODES];
242
nei[1]= nei[0]; // we waste calculations but save if() jumps
248
d0= GraphNode::distance(node, *nei[0]);
249
d1= GraphNode::distance(node, *nei[1]);
259
dcx[0]= ccx - nei[0]->left();
260
dcy[0]= ccy - nei[0]->top();
261
dcx[1]= ccx - nei[1]->left();
262
dcy[1]= ccy - nei[1]->top();
276
neif[0]= nei[0]->is_focus();
277
neif[1]= nei[1]->is_focus();
279
vx0 *= GraphRenderer::K2;
280
vy0 *= GraphRenderer::K2;
281
vx1 *= GraphRenderer::K2;
282
vy1 *= GraphRenderer::K2;
305
if(nei[0]->is_visisted())
307
double k= _length - d0;
312
k= (node_is_focus || neif[0]) ? GraphRenderer::K1F : GraphRenderer::K1N;
320
if(nei[1]->is_visisted())
322
double k= _length - d1;
327
k= (node_is_focus || neif[1]) ? GraphRenderer::K1F : GraphRenderer::K1N;
336
static const double t= 10.; // threshold
337
static const double s= 4.; // step
341
else if(all_sum_x <= -t)
348
else if(all_sum_y <= -t)
354
*deltax= std::min(*deltax, _right - node.left() - node.width());
355
*deltay= std::min(*deltay, _bottom - node.top() - node.height());
356
*deltax= std::min(*deltax, _maxw - node.left() - node.width());
357
*deltay= std::min(*deltay, _maxh - node.top() - node.height());
361
GraphNode *GraphRenderer::add_node(double left, double top, double width, double height)
363
GraphNode *node= new GraphNode(left, top, width, height);
364
_allnodes.push_back(node);
365
focus_recalced= false;
369
void GraphRenderer::add_edge(GraphNode *n1, GraphNode *n2)
371
_alledges.push_back(GraphEdge(*n1, *n2));
372
focus_recalced= false;
375
void GraphRenderer::add_special_edge(GraphNode *n1, GraphNode *n2)
377
_alledges.push_back(GraphEdge(*n1, *n2, true));
378
focus_recalced= false;
381
void GraphRenderer::mark_reachable(GraphNode& node)
383
if(node.is_visisted())
386
node.set_visited(true);
388
for(GraphRenderer::GraphEdgeList::iterator it= _alledges.begin(); it != _alledges.end(); ++it)
390
GraphEdge& edge= *it;
391
if(!edge.contains(node))
393
GraphNode& other= edge.get_other(node);
394
mark_reachable(other);
398
void GraphRenderer::concat_graph(GraphNode& node)
400
mark_reachable(node);
402
GraphNodeRefList::iterator e= _allnodes.end();
403
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
405
GraphNode& next= **it;
406
if(!next.is_visisted())
408
add_special_edge(&node, &next);
409
mark_reachable(next);
414
void GraphRenderer::recalc_focus_nodes()
419
GraphNodeRefList::iterator e= _allnodes.end();
420
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
422
GraphNode& node = **it;
423
node.set_focus(is_focus_node(node));
426
// add edges to avoid unconnected nodes/pieces
427
std::remove_if(_alledges.begin(), _alledges.end(), edge_is_special);
428
std::for_each(_allnodes.begin(), _allnodes.end(), reset_visited);
429
if(_allnodes.size() > 0)
431
GraphNode* node = _allnodes.front();
435
focus_recalced= true;
438
void GraphRenderer::recalc_outer_rect()
445
GraphNodeRefList::iterator e= _allnodes.end();
446
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
448
GraphNode& node = **it;
449
double left = node.left();
450
double top = node.top();
451
double right = left + node.width();
452
double bottom = top + node.height();
463
if(_bottom < bottom) {
469
void GraphRenderer::recalc_positions()
475
GraphRenderer::GraphNodeRefList::iterator e= _allnodes.end();
476
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
478
GraphNode& node= **it;
480
if(!node.is_movable())
483
get_delta(node, &xf, &yf);
484
node.setnewleft(node.left() + xf);
485
node.setnewtop(node.top() + yf);
486
_avg_force += sqrt(xf*xf + yf*yf);
487
std::pair<CoordSet::iterator, bool> pr = cs.insert(CoordPair(node.newleft(), node.newtop()));
490
node.setnewleft(node.newleft() + 1);
491
node.setnewtop(node.newtop() + 1);
492
pr = cs.insert(CoordPair(node.newleft(), node.newtop()));
496
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
498
GraphNode& node = **it;
499
if(!node.is_movable())
505
void GraphRenderer::rotate_point(double *x, double *y, double angle)
509
double sina= sin(angle);
510
double cosa= cos(angle);
511
*x = x0*cosa + y0*sina;
512
*y = -x0*sina + y0*cosa;
515
void GraphRenderer::move(double dx, double dy)
517
GraphRenderer::GraphNodeRefList::iterator e= _allnodes.end();
518
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
520
GraphNode& node = **it;
521
node.setnewleft(node.left() + dx);
522
node.setnewtop(node.top() + dy);
527
void GraphRenderer::rotate()
529
static double pi = 3.1415926535;
530
static double step = pi/300.;
532
double curmsd = 0, posmsd = 0, negmsd = 0;
533
double yzero = (_top + _bottom)/2.;
534
double xzero = (_left + _right)/2.;
536
GraphRenderer::GraphNodeRefList::iterator e= _allnodes.end();
537
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
539
GraphNode& node = **it;
541
if(!node.is_movable())
544
double x = node.centerx() - xzero;
545
double y = node.centery() - yzero;
551
rotate_point(&x1, &y1, step);
552
rotate_point(&x2, &y2, -step);
564
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
566
GraphNode& node = **it;
568
if(!node.is_movable())
571
double x = node.left() - xzero;
572
double y = node.top() - yzero;
573
rotate_point(&x, &y, step);
577
xzero= std::min(xzero, _right - node.width());
578
yzero= std::min(yzero, _bottom - node.height());
579
xzero= std::min(xzero, _maxw - node.width());
580
yzero= std::min(yzero, _maxh - node.height());
583
node.setnewleft(x + xzero);
584
node.setnewtop( y + yzero);
589
void GraphRenderer::shift_to_origin()
591
GraphRenderer::GraphNodeRefList::iterator e= _allnodes.end();
592
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
594
GraphNode& node= **it;
595
node.setnewleft(node.left() - _left + _margin);
596
node.setnewtop(node.top() - _top + _margin);
605
void GraphRenderer::scale(double xfactor, double yfactor)
607
GraphRenderer::GraphNodeRefList::iterator e= _allnodes.end();
608
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
610
GraphNode& node= **it;
611
node.setnewleft(node.left()*xfactor);
612
node.setnewtop(node.top()*yfactor);
617
bool GraphRenderer::has_nonmovable_nodes() const
619
GraphRenderer::GraphNodeRefList::const_iterator e= _allnodes.end();
620
for(GraphRenderer::GraphNodeRefList::const_iterator it= _allnodes.begin(); it != e; ++it)
622
GraphNode& node= **it;
623
if(!node.is_movable())
629
void GraphRenderer::scale_up()
631
double scale_factor_x= 1;
632
double scale_factor_y= 1;
634
GraphNodeRefList::const_iterator e= _allnodes.end();
635
for(GraphNodeRefList::const_iterator it= _allnodes.begin(); it != e; ++it)
637
GraphNode& node= **it;
638
double l= node.left();
639
double t= node.top();
640
double w= node.width();
641
double h= node.height();
643
GraphNodeRefList::const_iterator it2= it;
645
for(; it2 != e; it2++)
647
GraphNode& other= **it2;
648
double ol= other.left();
649
double ot= other.top();
650
double ow= other.width();
651
double oh= other.height();
653
if(nodes_intersect(l, t, w, h, ol, ot, ow, oh))
672
if((minl + minw + _margin) > maxl)
674
double f= (minw + _margin)/(maxl - minl);
675
if(f > scale_factor_x)
692
if((minl + minw + _margin) > maxl)
694
double f= (minw + _margin)/(maxl - minl);
695
if(f > scale_factor_y)
702
scale(scale_factor_x, scale_factor_y);
705
void GraphRenderer::scale_down()
707
double maxw= _maxw - 2*_margin;
708
double maxh= _maxh - 2*_margin;
710
if((maxw >= (_right - _left)) && (maxh >= (_bottom - _top)))
713
double xfactor= maxw < (_right - _left) ? maxw/(_right - _left) : 1;
714
double yfactor= maxh < (_bottom - _top) ? maxh/(_bottom - _top) : 1;
716
scale(xfactor, yfactor);
719
void GraphRenderer::recalc()
722
unsigned iter_count= 200;
723
bool has_nonmovable= has_nonmovable_nodes();
725
double temp_maxw= _maxw;
726
double temp_maxh= _maxh;
740
recalc_focus_nodes();
742
while(!is_steady() && (count < iter_count))
754
recalc_focus_nodes();
755
while(has_intersections() && (count < iter_count))
781
void GraphRenderer::get_outer_rect(double *left, double *top, double *right, double *bottom)
789
void GraphRenderer::recalc_length()
793
double cx= (_left+_right)/2.;
794
double cy= (_top+_bottom)/2.;
796
GraphRenderer::GraphNodeRefList::iterator e= _allnodes.end();
797
for(GraphRenderer::GraphNodeRefList::iterator it= _allnodes.begin(); it != e; ++it)
799
GraphNode& node= **it;
800
_density_ratio += node.width()*node.height();
802
idx += node.centerx() < cx ? 0 : 1;
803
idx += node.centery() < cy ? 0 : 2;
806
_density_ratio /= (_right - _left)*(_bottom - _top);
807
_length= 1000.*_density_ratio*_density_ratio;