43 double x, y, dx, dy, z;
48 std::vector<int> connected;
49 double topology_error;
50 double relative_position_error;
51 double relative_position_neighborhood_error;
59 mbb_node(
const double& strKey = 0,
const int& intId = 0)
63 bool operator<(
const mbb_node& rhs)
const {
73 std::multiset<mbb_node> x;
74 std::multiset<mbb_node> y;
77 typedef std::vector<map_region> recmapvector;
83 double alpha = std::atan2(b.x - a.x, b.y - a.y);
90 if (a.x + a.dx < b.x - b.dx)
return false;
91 else if (a.x - a.dx > b.x + b.dx)
return false;
92 else if (a.y + a.dy < b.y - b.dy)
return false;
93 else if (a.y - a.dy > b.y + b.dy)
return false;
108 double dy = a.dy + c.dy + eps;
109 double dx = a.dx + c.dx + eps;
111 if (std::sin(alpha) >= 0 && std::cos(alpha) >= 0) {
113 tanx = a.x + (dx * std::tan(alpha));
114 tany = a.y + (dy * std::tan(PI/2 - alpha));
120 if (tany >= c.y) c.x = tanx;
124 }
else if (std::sin(alpha) >= 0 && std::cos(alpha) < 0) {
126 tanx = a.x + (dx * std::tan(PI - alpha));
127 tany = a.y - (dy * std::tan(alpha - PI/2));
132 if (tanx <= c.x) c.x = tanx;
136 }
else if (std::sin(alpha) < 0 && std::cos(alpha) < 0) {
138 tanx = a.x - (dx * std::tan(alpha - PI));
139 tany = a.y - (dy * std::tan(3 * PI / 2 - alpha));
144 if (tany > c.y) c.y = tany;
148 }
else if (std::sin(alpha) < 0 && std::cos(alpha) > 0) {
150 tanx = a.x - (dy * std::tan(2 * PI - alpha));
151 tany = a.y + (dx * std::tan(alpha - 3 * PI /2));
156 if (tanx < c.x) c.y = tany;
167 template<
typename C,
typename Op1>
168 void each_unique_pair(C& container, Op1 fun1) {
169 for (
auto it = container.begin(); it != container.end() - 1; ++it)
170 for (
auto it2 = std::next(it); it2 != container.end(); ++it2)
171 fun1(*it, *it2, container);
174 template<
typename C0,
typename C1,
typename Op>
175 void each_unique_pair(C0& container0, C1& container1, Op fun) {
176 for (
auto it = container0.begin(); it != container0.end() - 1; ++it)
177 for (
auto it2 = std::next(it); it2 != container0.end(); ++it2)
178 fun(*it, *it2, container0, container1);
187 recmapvector Cartogram;
190 bool map_region_intersect_multiset =
true;
194 std::list<std::string> msg;
195 std::list<std::string> warnings;
206 void push_region(
double x,
double y,
double dx,
double dy,
double z,
210 R.x = x; R.y = y; R.dx = dx; R.dy = dy; R.z = z;
218 R1.x = -1; R1.y = -1; R1.dx = dx; R1.dy = dy; R1.z = z;
220 R1.area_desired = -1;
225 R1.topology_error = -1;
226 R1.relative_position_error = 0.0;
227 R1.relative_position_neighborhood_error = 0.0;
230 Cartogram.push_back(R1);
239 void push_pd_edge(
int u,
int v){
240 Map[u].connected.push_back(v);
241 Map[v].connected.push_back(u);
244 std::string warnings_pop() {
245 std::string s = warnings.front(); warnings.pop_front();
249 bool warnings_empty() {
return warnings.empty();}
251 int get_size() {
return num_regions;}
253 int get_intersect_count() {
return intersect_count; }
254 void set_map_region_intersect_multiset(
bool b) { map_region_intersect_multiset = b; }
256 map_region& get_map_region(
int i) {
return(Cartogram[i]); }
259 void ComputePseudoDual(recmapvector &M) {
264 if (mbb_check(a, b)) {
265 M[a.id].connected.push_back(b.id);
266 M[b.id].connected.push_back(a.id);
272 void ComputeDesiredArea(recmapvector &M, recmapvector &C) {
274 double sum_area = 0.0;
276 std::for_each(M.begin(), M.end(), [&] (
map_region &r) {sum_z += r.z;});
277 std::for_each(M.begin(), M.end(),
278 [&] (
map_region &r) {sum_area += (4 * r.dx * r.dy);});
280 std::for_each(C.begin(), C.end(), [&] (
map_region &r) {
281 double area_desired = r.z * sum_area / sum_z;
282 double ratio = r.dy / r.dx;
283 r.dx = sqrt(area_desired / (4 * ratio));
293 int ComputeCoreRegion(recmapvector &M, recmapvector &C) {
294 int core_region_id = num_regions / 2;
296 C[core_region_id].x = M[core_region_id].x;
297 C[core_region_id].y = M[core_region_id].y;
298 C[core_region_id].placed++;
299 C[core_region_id].topology_error = 0;
302 mn.key = C[core_region_id].x; mn.id = C[core_region_id].id;
305 mn.key = C[core_region_id].y; mn.id = C[core_region_id].id;
308 MBB.max_dx = C[core_region_id].dx;
309 MBB.max_dy = C[core_region_id].dy;
311 return core_region_id;
315 bool map_region_intersect(
const recmapvector &C,
const map_region &a) {
317 if (a.id != b.id && b.placed > 0) {
319 if (mbb_check(a, b)) {
327 bool map_region_intersect_set(recmapvector &C,
const mbb_set &S,
332 auto lower_x = std::lower_bound(S.x.begin(), S.x.end(),
333 a.x - a.dx - S.max_dx - eps,
335 {
return f1.key < f2.key; });
337 auto upper_x = std::upper_bound(S.x.begin(), S.x.end(),
338 a.x + a.dx + S.max_dx + eps,
340 {
return f1.key < f2.key; });
343 for (
auto it_x = lower_x; it_x != upper_x; ++it_x) {
346 if ((*it_x).id != a.id && mbb_check(a, C[(*it_x).id])) {
353 auto lower_y = std::lower_bound(S.y.begin(), S.y.end(),
354 a.y - a.dy - S.max_dy - eps,
356 {
return f1.key < f2.key; });
358 auto upper_y = std::upper_bound(S.y.begin(), S.y.end(),
359 a.y + a.dy + S.max_dy + eps,
361 {
return f1.key < f2.key; });
363 for (
auto it_y = lower_y; it_y != upper_y; ++it_y) {
365 if ((*it_y).id != a.id && mbb_check(a, C[(*it_y).id])) {
374 bool PlaceRectangle(recmapvector &M, recmapvector &C,
int region_id) {
375 double alpha0, alpha;
378 double beta_sign = 1.0;
379 bool intersect =
true;
384 for (
double beta = 0.0; beta <= PI && C[region_id].placed == 0;
387 for (
const int &adj_region_id : M[region_id].connected) {
388 if (C[adj_region_id].placed > 0) {
390 alpha0 = get_angle(M[adj_region_id], M[region_id]);
391 alpha = alpha0 + (beta_sign * beta);
394 place_rectangle(C[adj_region_id], alpha, C[region_id]);
396 if (map_region_intersect_multiset)
397 intersect = map_region_intersect_set(C, MBB, C[region_id]);
399 intersect = map_region_intersect(C, C[region_id]);
402 C[region_id].placed++;
403 C[region_id].topology_error = 0;
405 mn.key = C[region_id].x; mn.id = C[region_id].id;
408 mn.key = C[region_id].y; mn.id = C[region_id].id;
411 if (C[region_id].dx > MBB.max_dx) {MBB.max_dx = C[region_id].dx;}
412 if (C[region_id].dy > MBB.max_dy) {MBB.max_dy = C[region_id].dy;}
415 C[adj_region_id].connected.push_back(region_id);
416 C[region_id].connected.push_back(adj_region_id);
426 C[region_id].topology_error = -1;
428 warnings.push_back(M[region_id].name
429 +
" could not be placed on the first attempt;");
434 void DrawCartogram(recmapvector &M, recmapvector &C,
int core_region_id) {
435 std::list<int> stack;
436 std::vector<int> visited(num_regions, 0);
437 std::vector<int> dfs_num(num_regions, 0);
439 int dfs_num_counter = 0;
440 int current_region_id = core_region_id;
441 stack.push_back(current_region_id);
442 visited[current_region_id]++;
444 while (stack.size() > 0) {
445 current_region_id = stack.back() ; stack.pop_back();
446 dfs_num[current_region_id] = dfs_num_counter++;
447 C[current_region_id].dfs_num = dfs_num[current_region_id];
449 if (current_region_id != core_region_id) {
450 if (!PlaceRectangle(M, C, current_region_id)) {
455 for (
const int & adj_region_id : M[current_region_id].connected) {
456 if (visited[adj_region_id] == 0) {
457 visited[adj_region_id]++;
458 stack.push_back(adj_region_id);
463 std::for_each(C.begin(), C.end(), [&] (
map_region &r) {
465 PlaceRectangle(M, C, r.id);
470 warnings.push_back(r.name +
" was not placed!!");
477 void ComputeError(recmapvector &M, recmapvector &C) {
478 double gammaM, gammaC, delta;
482 for (
const auto & a : M) {
483 for (
const auto & b : M) {
484 gammaM = get_angle(M[a.id], M[b.id]);
485 gammaC = get_angle(C[a.id], C[b.id]);
487 if ((gammaM < 0 && gammaC > 0) || ( gammaM > 0 && gammaC < 0))
488 delta = fabs(gammaC + gammaM) / C.size();
490 delta = fabs(gammaC - gammaM) / C.size();
492 C[a.id].relative_position_error += delta;
496 for (
const auto & idx : a.connected) {
497 gammaM = get_angle(M[a.id], M[idx]);
498 gammaC = get_angle(C[a.id], C[idx]);
499 if ((gammaM < 0 && gammaC > 0) || ( gammaM > 0 && gammaC < 0))
500 delta = fabs(gammaC + gammaM) / a.connected.size();
502 delta = fabs(gammaC - gammaM) / a.connected.size();
504 C[a.id].relative_position_neighborhood_error += delta;
509 std::vector<int> v(M[a.id].connected.size() + C[a.id].connected.size());
510 std::vector<int>::iterator it;
511 std::sort(M[a.id].connected.begin(), M[a.id].connected.end());
512 std::sort(C[a.id].connected.begin(), C[a.id].connected.end());
515 it = std::set_symmetric_difference(M[a.id].connected.begin(),
516 M[a.id].connected.end(),
517 C[a.id].connected.begin(),
518 C[a.id].connected.end(),
520 v.resize(it-v.begin());
522 if (C[a.id].topology_error != -1)
523 C[a.id].topology_error = (v.size());
528 void run(
bool computePseudoDual =
true) {
529 if (computePseudoDual) ComputePseudoDual(Map);
530 ComputeDesiredArea(Map, Cartogram);
531 int core_region_id = ComputeCoreRegion(Map, Cartogram);
532 msg.push_back(
"CORE REGION: " + Map[core_region_id].name);
533 DrawCartogram(Map, Cartogram, core_region_id);
534 ComputeError(Map, Cartogram);
540 #endif // SRC_RECMAP_H_