40 double x, y, dx, dy, z;
45 std::vector<int> connected;
46 double topology_error;
47 double relative_position_error;
48 double relative_position_neighborhood_error;
56 mbb_node(
const double& strKey = 0,
const int& intId = 0)
60 bool operator<(
const mbb_node& rhs)
const {
70 std::multiset<mbb_node> x;
71 std::multiset<mbb_node> y;
74 typedef std::vector<map_region> recmapvector;
78 double alpha = std::atan2(b.x - a.x, b.y - a.y);
83 bool mbb_check(
const map_region &a,
const map_region &b){
85 if (a.x + a.dx < b.x - b.dx)
return false;
86 else if (a.x - a.dx > b.x + b.dx)
return false;
87 else if (a.y + a.dy < b.y - b.dy)
return false;
88 else if (a.y - a.dy > b.y + b.dy)
return false;
98 void place_rectanle(
const map_region &a,
double alpha, map_region &c){
102 double dy = a.dy + c.dy + eps;
103 double dx = a.dx + c.dx + eps;
105 if (std::sin(alpha) >= 0 & std::cos(alpha) >= 0){
107 tanx = a.x + (dx * std::tan(alpha));
108 tany = a.y + (dy * std::tan(PI/2 - alpha));
114 if (tany >= c.y) c.x = tanx;
117 }
else if (std::sin(alpha) >= 0 && std::cos(alpha) < 0) {
119 tanx = a.x + (dx * std::tan(PI - alpha));
120 tany = a.y - (dy * std::tan(alpha - PI/2));
125 if (tanx <= c.x) c.x = tanx;
128 }
else if (std::sin(alpha) < 0 && std::cos(alpha) < 0) {
130 tanx = a.x - (dx * std::tan(alpha - PI));
131 tany = a.y - (dy * std::tan(3 * PI / 2 - alpha));
136 if (tany > c.y) c.y = tany;
139 }
else if (std::sin(alpha) < 0 && std::cos(alpha) > 0) {
141 tanx = a.x - (dy * std::tan(2 * PI - alpha));
142 tany = a.y + (dx * std::tan(alpha - 3 * PI /2));
147 if (tanx < c.x) c.y = tany;
156 template<
typename C,
typename Op1>
157 void each_unique_pair(C& container, Op1 fun1){
158 for(
auto it = container.begin(); it != container.end() - 1; ++it)
159 for(
auto it2 = std::next(it); it2 != container.end(); ++it2)
160 fun1(*it, *it2, container);
163 template<
typename C,
typename C1,
typename Op1>
164 void each_unique_pair2(C& container, C1& container1, Op1 fun2){
165 for(
auto it = container.begin(); it != container.end() - 1; ++it)
166 for(
auto it2 = std::next(it); it2 != container.end(); ++it2)
167 fun2(*it, *it2, container, container1);
172 recmapvector Cartogram;
178 std::list<std::string> msg;
179 std::list<std::string> warnings;
192 void push(
double x,
double y,
double dx,
double dy,
double z, std::string name){
196 R.x=x; R.y=y; R.dx=dx; R.dy = dy; R.z =z;
204 R1.x=-1; R1.y=-1; R1.dx = dx; R1.dy = dy; R1.z =z;
206 R1.area_desired = -1;
211 R1.topology_error = 100;
214 Cartogram.push_back(R1);
217 if (num_regions != Map.size()){
222 std::string warnings_pop(){
223 std::string s =warnings.front(); warnings.pop_front();
227 bool warnings_empty(){
return warnings.empty();}
229 int get_size(){
return num_regions;}
231 int get_intersect_count(){
return intersect_count; }
233 map_region& get_map_region(
int i){
return(Cartogram[i]); }
235 void ComputePseudoDual(recmapvector &M){
238 if ( mbb_check(a,b) ){
239 M[a.id].connected.push_back(b.id);
240 M[b.id].connected.push_back(a.id);
246 void ComputeDesiredArea(recmapvector &M, recmapvector &C){
248 double sum_area = 0.0;
250 std::for_each(M.begin(), M.end(), [&] (
map_region &r) {sum_z += r.z;});
251 std::for_each(M.begin(), M.end(), [&] (
map_region &r) {sum_area += (4 * r.dx * r.dy);});
253 std::for_each(C.begin(), C.end(), [&] (
map_region &r) {
254 double area_desired = r.z * sum_area / sum_z;
255 double ratio = r.dy / r.dx;
256 r.dx = sqrt(area_desired / (4 * ratio));
263 int ComputeCoreRegion(recmapvector &M, recmapvector &C){
265 int core_region_id = num_regions / 2;
267 C[core_region_id].x = M[core_region_id].x;
268 C[core_region_id].y = M[core_region_id].y;
269 C[core_region_id].placed++;
272 mn.key = C[core_region_id].x; mn.id = C[core_region_id].id;
275 mn.key = C[core_region_id].y; mn.id = C[core_region_id].id;
278 MBB.max_dx = C[core_region_id].dx;
279 MBB.max_dy = C[core_region_id].dy;
281 return core_region_id;
284 bool map_region_intersect(
const recmapvector &C,
const map_region &a){
286 if (a.id != b.id && b.placed > 0){
295 bool map_region_intersect_set(recmapvector &C,
const mbb_set &S,
const map_region &a){
297 auto lower_x = std::lower_bound(S.x.begin(), S.x.end(),
298 a.x - a.dx - S.max_dx - eps,
301 auto upper_x = std::upper_bound(S.x.begin(), S.x.end(),
302 a.x + a.dx + S.max_dx + eps,
305 auto lower_y = std::lower_bound(S.y.begin(), S.y.end(),
306 a.y - a.dy - S.max_dy - eps,
309 auto upper_y = std::upper_bound(S.y.begin(), S.y.end(),
310 a.y + a.dy + S.max_dy + eps,
318 for(
auto it_x = lower_x; it_x != upper_x; ++it_x){
320 if ((*it_x).id != a.id && mbb_check(a, C[(*it_x).id])){
325 for(
auto it_y = lower_y; it_y != upper_y; ++it_y){
327 if ((*it_y).id != a.id && mbb_check(a, C[(*it_y).id])){
336 bool PlaceRectangle(recmapvector &M, recmapvector &C,
int region_id){
338 double alpha0, alpha;
341 double beta_sign = 1.0;
344 for (
double beta = 0.0; beta <= PI && C[region_id].placed == 0; beta += PI/180){
347 for (
int adj_region_id : M[region_id].connected){
349 if (C[adj_region_id].placed > 0 ){
351 alpha0 = get_angle(M[adj_region_id], M[region_id]);
353 alpha = alpha0 + (beta_sign * beta);
356 place_rectanle(C[adj_region_id], alpha, C[region_id]);
361 if (!map_region_intersect_set(C, MBB, C[region_id])){
378 C[region_id].placed++;
379 C[region_id].topology_error = 0;
381 mn.key = C[region_id].x; mn.id = C[region_id].id;
384 mn.key = C[region_id].y; mn.id = C[region_id].id;
387 if (C[region_id].dx > MBB.max_dx) {MBB.max_dx = C[region_id].dx;}
388 if (C[region_id].dy > MBB.max_dy) {MBB.max_dy = C[region_id].dy;}
391 C[adj_region_id].connected.push_back(region_id);
392 C[region_id].connected.push_back(adj_region_id);
402 warnings.push_back(M[region_id].name +
" could not be placed on the first attempt;");
408 void DrawCartogram(recmapvector &M, recmapvector &C,
int core_region_id){
409 std::list<int> stack;
410 std::vector<int> visited(num_regions, 0);
411 std::vector<int> dfs_num(num_regions, 0);
413 int dfs_num_counter = 0;
414 int current_region_id = core_region_id;
415 stack.push_back(current_region_id);
416 visited[current_region_id]++;
418 while (stack.size() > 0){
419 current_region_id = stack.back() ; stack.pop_back();
420 dfs_num[current_region_id] = dfs_num_counter++;
421 C[current_region_id].dfs_num = dfs_num[current_region_id];
423 if (current_region_id != core_region_id){
424 if (!PlaceRectangle(M, C, current_region_id)){
429 for(
int adj_region_id : M[current_region_id].connected){
430 if (visited[adj_region_id] == 0) {
431 visited[adj_region_id]++;
432 stack.push_back(adj_region_id);
437 std::for_each(C.begin(), C.end(), [&] (
map_region &r) {
439 PlaceRectangle(M, C, r.id);
441 warnings.push_back(r.name +
" was not placed!!");
447 void ComputeError(
const recmapvector &M, recmapvector &C){
448 double gammaM, gammaC, delta;
452 gammaM = get_angle(M[a.id], M[b.id]);
453 gammaC = get_angle(C[a.id], C[b.id]);
454 delta = fabs (gammaC - gammaM) / C.size();
455 C[a.id].relative_position_error += delta;
458 for (
auto idx : a.connected){
459 gammaM = get_angle(M[a.id], M[idx]);
460 gammaC = get_angle(C[a.id], C[idx]);
461 delta = fabs (gammaC - gammaM) / a.connected.size();
462 C[a.id].relative_position_neighborhood_error += delta;
469 ComputePseudoDual(Map);
471 ComputeDesiredArea(Map, Cartogram);
473 int core_region_id = ComputeCoreRegion(Map, Cartogram);
474 msg.push_back(
"CORE REGION: " + Map[core_region_id].name);
475 DrawCartogram(Map, Cartogram, core_region_id);
477 ComputeError(Map, Cartogram);