6 * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of class FruchtermanReingold (computation of forces).
12 * \author Stefan Hachul
15 * This file is part of the Open Graph Drawing Framework (OGDF).
19 * See README.txt in the root directory of the OGDF installation for details.
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * Version 2 or 3 as published by the Free Software Foundation;
25 * see the file LICENSE.txt included in the packaging of this file
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
35 * You should have received a copy of the GNU General Public
36 * License along with this program; if not, write to the Free
37 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
38 * Boston, MA 02110-1301, USA.
40 * \see http://www.gnu.org/copyleft/gpl.html
41 ***************************************************************/
44 #include <ogdf/internal/energybased/FruchtermanReingold.h>
46 #include "numexcept.h"
47 #include <ogdf/basic/Array2D.h>
52 FruchtermanReingold::FruchtermanReingold()
58 void FruchtermanReingold::calculate_exact_repulsive_forces(
60 NodeArray
<NodeAttributes
> &A
,
61 NodeArray
<DPoint
>& F_rep
)
63 //naive algorithm by Fruchterman & Reingold
67 DPoint vector_v_minus_u
;
69 DPoint
nullpoint (0,0);
70 double norm_v_minus_u
;
71 long node_number
= G
.numberOfNodes();
72 Array
<node
> array_of_the_nodes (node_number
+1);
82 array_of_the_nodes
[counter
]=v
;
86 for(i
= 1; i
<node_number
;i
++)
87 for(j
= i
+1;j
<=node_number
;j
++)
89 u
= array_of_the_nodes
[i
];
90 v
= array_of_the_nodes
[j
];
91 pos_u
= A
[u
].get_position();
92 pos_v
= A
[v
].get_position();
94 {//if2 (Exception handling if two nodes have the same position)
95 pos_u
= N
.choose_distinct_random_point_in_radius_epsilon(pos_u
);
97 vector_v_minus_u
= pos_v
- pos_u
;
98 norm_v_minus_u
= vector_v_minus_u
.norm();
99 if(!N
.f_rep_near_machine_precision(norm_v_minus_u
,f_rep_u_on_v
))
101 scalar
= f_rep_scalar(norm_v_minus_u
)/norm_v_minus_u
;
102 f_rep_u_on_v
.m_x
= scalar
* vector_v_minus_u
.m_x
;
103 f_rep_u_on_v
.m_y
= scalar
* vector_v_minus_u
.m_y
;
105 F_rep
[v
] = F_rep
[v
] + f_rep_u_on_v
;
106 F_rep
[u
] = F_rep
[u
] - f_rep_u_on_v
;
111 void FruchtermanReingold::calculate_approx_repulsive_forces(
113 NodeArray
<NodeAttributes
> &A
,
114 NodeArray
<DPoint
>& F_rep
)
116 //GRID algorithm by Fruchterman & Reingold
118 List
<IPoint
> neighbour_boxes
;
119 List
<node
> neighbour_box
;
120 IPoint act_neighbour_box
;
123 DPoint vector_v_minus_u
;
124 DPoint
nullpoint (0,0);
126 double norm_v_minus_u
;
129 int i
,j
,act_i
,act_j
,k
,l
,length
;
131 double x
,y
,gridboxlength
;//length of a box in the GRID
138 //init max_gridindex and set contained_nodes;
140 max_gridindex
= static_cast<int> (sqrt(double(G
.numberOfNodes()))/grid_quotient())-1;
141 max_gridindex
= ((max_gridindex
> 0)? max_gridindex
: 0);
142 Array2D
<List
<node
> > contained_nodes (0,max_gridindex
, 0, max_gridindex
);
144 for(i
=0;i
<= max_gridindex
;i
++)
145 for(j
=0;j
<= max_gridindex
;j
++)
147 contained_nodes(i
,j
).clear();
150 gridboxlength
= boxlength
/(max_gridindex
+1);
153 x
= A
[v
].get_x()-down_left_corner
.m_x
;//shift comput. box to nullpoint
154 y
= A
[v
].get_y()-down_left_corner
.m_y
;
155 x_index
= static_cast<int>(x
/gridboxlength
);
156 y_index
= static_cast<int>(y
/gridboxlength
);
157 contained_nodes(x_index
,y_index
).pushBack(v
);
162 for(i
=0;i
<= max_gridindex
;i
++)
163 for(j
=0;j
<= max_gridindex
;j
++)
165 //step1: calculate forces inside contained_nodes(i,j)
167 length
= contained_nodes(i
,j
).size();
168 Array
<node
> nodearray_i_j (length
+1);
170 forall_listiterators(node
, v_it
,contained_nodes(i
,j
))
172 nodearray_i_j
[k
]= *v_it
;
176 for(k
= 1; k
<length
;k
++)
177 for(l
= k
+1;l
<=length
;l
++)
179 u
= nodearray_i_j
[k
];
180 v
= nodearray_i_j
[l
];
181 pos_u
= A
[u
].get_position();
182 pos_v
= A
[v
].get_position();
184 {//if2 (Exception handling if two nodes have the same position)
185 pos_u
= N
.choose_distinct_random_point_in_radius_epsilon(pos_u
);
187 vector_v_minus_u
= pos_v
- pos_u
;
188 norm_v_minus_u
= vector_v_minus_u
.norm();
190 if(!N
.f_rep_near_machine_precision(norm_v_minus_u
,f_rep_u_on_v
))
192 scalar
= f_rep_scalar(norm_v_minus_u
)/norm_v_minus_u
;
193 f_rep_u_on_v
.m_x
= scalar
* vector_v_minus_u
.m_x
;
194 f_rep_u_on_v
.m_y
= scalar
* vector_v_minus_u
.m_y
;
196 F_rep
[v
] = F_rep
[v
] + f_rep_u_on_v
;
197 F_rep
[u
] = F_rep
[u
] - f_rep_u_on_v
;
200 //step 2: calculated forces to nodes in neighbour boxes
202 //find_neighbour_boxes
204 neighbour_boxes
.clear();
205 for(k
= i
-1;k
<= i
+1;k
++)
206 for(l
= j
-1;l
<= j
+1;l
++)
207 if ( (k
>=0) && (l
>=0) && (k
<=max_gridindex
) && (l
<=max_gridindex
))
211 if ((k
!= i
) || (l
!= j
) )
212 neighbour_boxes
.pushBack(neighbour
);
216 //forget neighbour_boxes that already had access to this box
217 forall_listiterators(IPoint
, act_neighbour_box_it
,neighbour_boxes
)
219 act_i
= (*act_neighbour_box_it
).m_x
;
220 act_j
= (*act_neighbour_box_it
).m_y
;
221 if((act_j
== j
+1)||((act_j
== j
)&&(act_i
== i
+1)))
223 forall_listiterators(node
,v_it
,contained_nodes(i
,j
))
224 forall_listiterators(node
,u_it
,contained_nodes(act_i
,act_j
))
226 pos_u
= A
[*u_it
].get_position();
227 pos_v
= A
[*v_it
].get_position();
229 {//if2 (Exception handling if two nodes have the same position)
230 pos_u
= N
.choose_distinct_random_point_in_radius_epsilon(pos_u
);
232 vector_v_minus_u
= pos_v
- pos_u
;
233 norm_v_minus_u
= vector_v_minus_u
.norm();
235 if(!N
.f_rep_near_machine_precision(norm_v_minus_u
,f_rep_u_on_v
))
237 scalar
= f_rep_scalar(norm_v_minus_u
)/norm_v_minus_u
;
238 f_rep_u_on_v
.m_x
= scalar
* vector_v_minus_u
.m_x
;
239 f_rep_u_on_v
.m_y
= scalar
* vector_v_minus_u
.m_y
;
241 F_rep
[*v_it
] = F_rep
[*v_it
] + f_rep_u_on_v
;
242 F_rep
[*u_it
] = F_rep
[*u_it
] - f_rep_u_on_v
;
250 void FruchtermanReingold::make_initialisations(double bl
, DPoint d_l_c
, int grid_quot
)
252 grid_quotient(grid_quot
);
253 down_left_corner
= d_l_c
; //export this two values from FMMM
258 inline double FruchtermanReingold::f_rep_scalar(double d
)
264 cout
<<"Error FruchtermanReingold:: f_rep_scalar nodes at same position"<<endl
;