zones.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. #include <grass/config.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <math.h>
  6. #include <grass/lidar.h>
  7. /*----------------------------------------------------------------------------------------*/
  8. void P_zero_dim(struct Reg_dimens *dim)
  9. {
  10. dim->edge_h = 0.0;
  11. dim->edge_v = 0.0;
  12. dim->overlap = 0.0;
  13. dim->sn_size = 0.0;
  14. dim->ew_size = 0.0;
  15. return;
  16. }
  17. /*----------------------------------------------------------------------------------------*/
  18. /*
  19. --------------------------------------------
  20. | Elaboration region |
  21. | ------------------------------------ |
  22. | | General region | |
  23. | | ---------------------------- | |
  24. | | | | | |
  25. | | | | | |
  26. | | | | | |
  27. | | | Overlap region | | |
  28. | | | | | |
  29. | | | | | |
  30. | | | | | |
  31. | | ---------------------------- | |
  32. | | | |
  33. | ------------------------------------ |
  34. | |
  35. --------------------------------------------
  36. The terminology is misleading:
  37. The Overlap region does NOT overlap with neighbouring segments,
  38. but the Elaboration and General region do overlap
  39. Elaboration is used for interpolation
  40. Interpolated points in Elaboration but outside General are discarded
  41. Interpolated points in General but outside Overlap are weighed by
  42. their distance to Overlap and summed up
  43. Interpolated points in Overlap are taken as they are
  44. The buffer zones Elaboration - General and General - Overlap must be
  45. large enough to avoid artifacts
  46. */
  47. int
  48. P_set_regions(struct Cell_head *Elaboration, struct bound_box * General,
  49. struct bound_box * Overlap, struct Reg_dimens dim, int type)
  50. {
  51. /* Set the Elaboration, General, and Overlap region limits
  52. * Returns 0 on success; -1 on failure*/
  53. struct Cell_head orig;
  54. G_get_window(&orig);
  55. switch (type) {
  56. case GENERAL_ROW: /* General case N-S direction */
  57. Elaboration->north =
  58. Elaboration->south + dim.overlap + (2 * dim.edge_h);
  59. Elaboration->south = Elaboration->north - dim.sn_size;
  60. General->N = Elaboration->north - dim.edge_h;
  61. General->S = Elaboration->south + dim.edge_h;
  62. Overlap->N = General->N - dim.overlap;
  63. Overlap->S = General->S + dim.overlap;
  64. return 0;
  65. case GENERAL_COLUMN: /* General case E-W direction */
  66. Elaboration->west =
  67. Elaboration->east - dim.overlap - (2 * dim.edge_v);
  68. Elaboration->east = Elaboration->west + dim.ew_size;
  69. General->W = Elaboration->west + dim.edge_v;
  70. General->E = Elaboration->east - dim.edge_v;
  71. Overlap->W = General->W + dim.overlap;
  72. Overlap->E = General->E - dim.overlap;
  73. return 0;
  74. case FIRST_ROW: /* Just started with first row */
  75. Elaboration->north = orig.north + 2 * dim.edge_h;
  76. Elaboration->south = Elaboration->north - dim.sn_size;
  77. General->N = orig.north;
  78. General->S = Elaboration->south + dim.edge_h;
  79. Overlap->N = General->N;
  80. Overlap->S = General->S + dim.overlap;
  81. return 0;
  82. case LAST_ROW: /* Reached last row */
  83. Elaboration->south = orig.south - 2 * dim.edge_h;
  84. General->S = orig.south;
  85. Overlap->S = General->S;
  86. return 0;
  87. case FIRST_COLUMN: /* Just started with first column */
  88. Elaboration->west = orig.west - 2 * dim.edge_v;
  89. Elaboration->east = Elaboration->west + dim.ew_size;
  90. General->W = orig.west;
  91. General->E = Elaboration->east - dim.edge_v;
  92. Overlap->W = General->W;
  93. Overlap->E = General->E - dim.overlap;
  94. return 0;
  95. case LAST_COLUMN: /* Reached last column */
  96. Elaboration->east = orig.east + 2 * dim.edge_v;
  97. General->E = orig.east;
  98. Overlap->E = General->E;
  99. return 0;
  100. }
  101. return -1;
  102. }
  103. /*----------------------------------------------------------------------------------------*/
  104. int P_set_dim(struct Reg_dimens *dim, double pe, double pn, int *nsplx, int *nsply)
  105. {
  106. int total_splines, edge_splines, n_windows;
  107. int lastsplines, lastsplines_min, lastsplines_max;
  108. double E_extension, N_extension, edgeE, edgeN;
  109. struct Cell_head orig;
  110. int ret = 0;
  111. G_get_window(&orig);
  112. E_extension = orig.east - orig.west;
  113. N_extension = orig.north - orig.south;
  114. dim->ew_size = *nsplx * pe;
  115. dim->sn_size = *nsply * pn;
  116. edgeE = dim->ew_size - dim->overlap - 2 * dim->edge_v;
  117. edgeN = dim->sn_size - dim->overlap - 2 * dim->edge_h;
  118. /* number of moving windows: E_extension / edgeE */
  119. /* remaining steps: total steps - (floor(E_extension / edgeE) * E_extension) / passoE */
  120. /* remaining steps must be larger than edge_v + overlap + half of overlap window */
  121. total_splines = ceil(E_extension / pe);
  122. edge_splines = edgeE / pe;
  123. n_windows = E_extension / edgeE; /* without last one */
  124. if (n_windows > 0) {
  125. /* min size of the last overlap window = half of current overlap window */
  126. /* max size of the last overlap window = elaboration - 3 * edge - overlap */
  127. lastsplines_min = ceil((dim->ew_size / 2.0 - (dim->edge_v + dim->overlap)) / pe);
  128. lastsplines_max = ceil((dim->ew_size - 3 * dim->edge_v - dim->overlap) / pe);
  129. lastsplines = total_splines - edge_splines * n_windows;
  130. while (lastsplines > lastsplines_max || lastsplines < lastsplines_min) {
  131. *nsplx -= 1;
  132. dim->ew_size = *nsplx * pe;
  133. edgeE = dim->ew_size - dim->overlap - 2 * dim->edge_v;
  134. edge_splines = edgeE / pe;
  135. n_windows = E_extension / edgeE; /* without last one */
  136. lastsplines = total_splines - edge_splines * n_windows;
  137. if (ret == 0)
  138. ret = 1;
  139. }
  140. }
  141. total_splines = ceil(N_extension / pn);
  142. edge_splines = edgeN / pn;
  143. n_windows = N_extension / edgeN; /* without last one */
  144. if (n_windows > 0) {
  145. /* min size of the last overlap window = half of current overlap window */
  146. /* max size of the last overlap window = elaboration - 3 * edge - overlap */
  147. lastsplines_min = ceil((dim->sn_size / 2.0 - (dim->edge_h + dim->overlap)) / pn);
  148. lastsplines_max = ceil((dim->sn_size - 3 * dim->edge_h - dim->overlap) / pn);
  149. lastsplines = total_splines - edge_splines * n_windows;
  150. while (lastsplines > lastsplines_max || lastsplines < lastsplines_min) {
  151. *nsply -= 1;
  152. dim->sn_size = *nsply * pn;
  153. edgeN = dim->sn_size - dim->overlap - 2 * dim->edge_h;
  154. edge_splines = edgeN / pn;
  155. n_windows = N_extension / edgeN; /* without last one */
  156. lastsplines = total_splines - edge_splines * n_windows;
  157. if (ret < 2)
  158. ret += 2;
  159. }
  160. }
  161. return ret;
  162. }
  163. /*----------------------------------------------------------------------------------------*/
  164. int P_get_edge(int interpolator, struct Reg_dimens *dim, double pe, double pn)
  165. {
  166. /* Set the edge regions dimension
  167. * Returns 1 on success of bilinear; 2 on success of bicubic, 0 on failure */
  168. if (interpolator == P_BILINEAR) {
  169. /* in case of edge artifacts, increase as multiples of 3 */
  170. dim->edge_v = 9 * pe;
  171. dim->edge_h = 9 * pn;
  172. return 1;
  173. }
  174. else if (interpolator == P_BICUBIC) {
  175. /* in case of edge artifacts, increase as multiples of 4 */
  176. dim->edge_v = 12 * pe; /*3 */
  177. dim->edge_h = 12 * pn;
  178. return 2;
  179. }
  180. else
  181. return 0; /* The interpolator is neither bilinear nor bicubic!! */
  182. }
  183. /*----------------------------------------------------------------------------------------*/
  184. int P_get_BandWidth(int interpolator, int nsplines)
  185. {
  186. /* Returns the interpolation matrixes BandWidth dimension */
  187. if (interpolator == P_BILINEAR) {
  188. return (2 * nsplines + 1);
  189. }
  190. else {
  191. return (4 * nsplines + 3);
  192. }
  193. }
  194. /*----------------------------------------------------------------------------------------*/
  195. double
  196. P_Mean_Calc(struct Cell_head *Elaboration, struct Point *obs, int npoints)
  197. {
  198. int i, mean_count = 0;
  199. double mean = 0.0;
  200. struct bound_box mean_box;
  201. Vect_region_box(Elaboration, &mean_box);
  202. mean_box.W -= CONTOUR;
  203. mean_box.E += CONTOUR;
  204. mean_box.N += CONTOUR;
  205. mean_box.S -= CONTOUR;
  206. for (i = 0; i < npoints; i++) { /* */
  207. if (Vect_point_in_box
  208. (obs[i].coordX, obs[i].coordY, obs[i].coordZ, &mean_box)) {
  209. mean_count++;
  210. mean += obs[i].coordZ;
  211. }
  212. }
  213. if (mean_count == 0)
  214. mean = .0;
  215. else
  216. mean /= (double)mean_count;
  217. return mean;
  218. }
  219. double P_estimate_splinestep(struct Map_info *Map, double *dens, double *dist)
  220. {
  221. int type, npoints = 0;
  222. double xmin = 0, xmax = 0, ymin = 0, ymax = 0;
  223. double x, y, z;
  224. struct line_pnts *points;
  225. struct line_cats *categories;
  226. struct bound_box region_box;
  227. struct Cell_head orig;
  228. G_get_set_window(&orig);
  229. Vect_region_box(&orig, &region_box);
  230. points = Vect_new_line_struct();
  231. categories = Vect_new_cats_struct();
  232. Vect_rewind(Map);
  233. while ((type = Vect_read_next_line(Map, points, categories)) > 0) {
  234. if (!(type & GV_POINT))
  235. continue;
  236. x = points->x[0];
  237. y = points->y[0];
  238. if (points->z != NULL)
  239. z = points->z[0];
  240. else
  241. z = 0.0;
  242. /* only use points in current region */
  243. if (Vect_point_in_box(x, y, z, &region_box)) {
  244. npoints++;
  245. if (npoints > 1) {
  246. if (xmin > x)
  247. xmin = x;
  248. else if (xmax < x)
  249. xmax = x;
  250. if (ymin > y)
  251. ymin = y;
  252. else if (ymax < y)
  253. ymax = y;
  254. }
  255. else {
  256. xmin = xmax = x;
  257. ymin = ymax = y;
  258. }
  259. }
  260. }
  261. Vect_destroy_cats_struct(categories);
  262. Vect_destroy_line_struct(points);
  263. if (npoints > 0) {
  264. /* estimated average distance between points in map units */
  265. *dist = sqrt(((xmax - xmin) * (ymax - ymin)) / npoints);
  266. /* estimated point density as number of points per square map unit */
  267. *dens = npoints / ((xmax - xmin) * (ymax - ymin));
  268. return 0;
  269. }
  270. else {
  271. return -1;
  272. }
  273. }
  274. struct Point *P_Read_Vector_Region_Map(struct Map_info *Map,
  275. struct Cell_head *Elaboration,
  276. int *num_points, int dim_vect,
  277. int layer)
  278. {
  279. int line_num, pippo, npoints, cat, type;
  280. double x, y, z;
  281. struct Point *obs;
  282. struct line_pnts *points;
  283. struct line_cats *categories;
  284. struct bound_box elaboration_box;
  285. pippo = dim_vect;
  286. obs = (struct Point *)G_calloc(pippo, sizeof(struct Point));
  287. points = Vect_new_line_struct();
  288. categories = Vect_new_cats_struct();
  289. /* Reading points inside elaboration zone */
  290. Vect_region_box(Elaboration, &elaboration_box);
  291. npoints = 0;
  292. line_num = 0;
  293. Vect_rewind(Map);
  294. while ((type = Vect_read_next_line(Map, points, categories)) > 0) {
  295. if (!(type & GV_POINT))
  296. continue;
  297. line_num++;
  298. x = points->x[0];
  299. y = points->y[0];
  300. if (points->z != NULL)
  301. z = points->z[0];
  302. else
  303. z = 0.0;
  304. /* Reading and storing points only if in elaboration_reg */
  305. if (Vect_point_in_box(x, y, z, &elaboration_box)) {
  306. npoints++;
  307. if (npoints >= pippo) {
  308. pippo += dim_vect;
  309. obs =
  310. (struct Point *)G_realloc((void *)obs,
  311. (signed int)pippo *
  312. sizeof(struct Point));
  313. }
  314. /* Storing observation vector */
  315. obs[npoints - 1].coordX = x;
  316. obs[npoints - 1].coordY = y;
  317. obs[npoints - 1].coordZ = z;
  318. obs[npoints - 1].lineID = line_num; /* Storing also the line's number */
  319. Vect_cat_get(categories, layer, &cat);
  320. obs[npoints - 1].cat = cat;
  321. }
  322. }
  323. Vect_destroy_line_struct(points);
  324. Vect_destroy_cats_struct(categories);
  325. *num_points = npoints;
  326. return obs;
  327. }
  328. struct Point *P_Read_Raster_Region_Map(SEGMENT *in_seg,
  329. struct Cell_head *Elaboration,
  330. struct Cell_head *Original,
  331. int *num_points, int dim_vect)
  332. {
  333. int col, row, startcol, endcol, startrow, endrow, nrows, ncols;
  334. int pippo, npoints;
  335. double x, y, z;
  336. struct Point *obs;
  337. struct bound_box elaboration_box;
  338. pippo = dim_vect;
  339. obs = (struct Point *)G_calloc(pippo, sizeof(struct Point));
  340. /* Reading points inside elaboration zone */
  341. Vect_region_box(Elaboration, &elaboration_box);
  342. npoints = 0;
  343. nrows = Original->rows;
  344. ncols = Original->cols;
  345. if (Original->north > Elaboration->north)
  346. startrow = (Original->north - Elaboration->north) / Original->ns_res - 1;
  347. else
  348. startrow = 0;
  349. if (Original->north > Elaboration->south) {
  350. endrow = (Original->north - Elaboration->south) / Original->ns_res + 1;
  351. if (endrow > nrows)
  352. endrow = nrows;
  353. }
  354. else
  355. endrow = nrows;
  356. if (Elaboration->west > Original->west)
  357. startcol = (Elaboration->west - Original->west) / Original->ew_res - 1;
  358. else
  359. startcol = 0;
  360. if (Elaboration->east > Original->west) {
  361. endcol = (Elaboration->east - Original->west) / Original->ew_res + 1;
  362. if (endcol > ncols)
  363. endcol = ncols;
  364. }
  365. else
  366. endcol = ncols;
  367. for (row = startrow; row < endrow; row++) {
  368. for (col = startcol; col < endcol; col++) {
  369. Segment_get(in_seg, &z, row, col);
  370. if (!Rast_is_d_null_value(&z)) {
  371. x = Rast_col_to_easting((double)(col) + 0.5, Original);
  372. y = Rast_row_to_northing((double)(row) + 0.5, Original);
  373. if (Vect_point_in_box(x, y, 0, &elaboration_box)) {
  374. npoints++;
  375. if (npoints >= pippo) {
  376. pippo += dim_vect;
  377. obs =
  378. (struct Point *)G_realloc((void *)obs,
  379. (signed int)pippo *
  380. sizeof(struct Point));
  381. }
  382. /* Storing observation vector */
  383. obs[npoints - 1].coordX = x;
  384. obs[npoints - 1].coordY = y;
  385. obs[npoints - 1].coordZ = z;
  386. }
  387. }
  388. }
  389. }
  390. *num_points = npoints;
  391. return obs;
  392. }
  393. /*------------------------------------------------------------------------------------------------*/
  394. int P_Create_Aux2_Table(dbDriver * driver, char *tab_name)
  395. {
  396. dbTable *auxiliar_tab;
  397. dbColumn *column;
  398. auxiliar_tab = db_alloc_table(2);
  399. db_set_table_name(auxiliar_tab, tab_name);
  400. db_set_table_description(auxiliar_tab,
  401. "Intermediate interpolated values");
  402. column = db_get_table_column(auxiliar_tab, 0);
  403. db_set_column_name(column, "ID");
  404. db_set_column_sqltype(column, DB_SQL_TYPE_INTEGER);
  405. column = db_get_table_column(auxiliar_tab, 1);
  406. db_set_column_name(column, "Interp");
  407. db_set_column_sqltype(column, DB_SQL_TYPE_REAL);
  408. if (db_create_table(driver, auxiliar_tab) == DB_OK) {
  409. G_debug(1, _("<%s> created in database."), tab_name);
  410. return TRUE;
  411. }
  412. else
  413. G_warning(_("<%s> has not been created in database."), tab_name);
  414. return FALSE;
  415. }
  416. /*------------------------------------------------------------------------------------------------*/
  417. int P_Create_Aux4_Table(dbDriver * driver, char *tab_name)
  418. {
  419. dbTable *auxiliar_tab;
  420. dbColumn *column;
  421. auxiliar_tab = db_alloc_table(4);
  422. db_set_table_name(auxiliar_tab, tab_name);
  423. db_set_table_description(auxiliar_tab,
  424. "Intermediate interpolated values");
  425. column = db_get_table_column(auxiliar_tab, 0);
  426. db_set_column_name(column, "ID");
  427. db_set_column_sqltype(column, DB_SQL_TYPE_INTEGER);
  428. column = db_get_table_column(auxiliar_tab, 1);
  429. db_set_column_name(column, "Interp");
  430. db_set_column_sqltype(column, DB_SQL_TYPE_REAL);
  431. column = db_get_table_column(auxiliar_tab, 2);
  432. db_set_column_name(column, "X");
  433. db_set_column_sqltype(column, DB_SQL_TYPE_DOUBLE_PRECISION);
  434. column = db_get_table_column(auxiliar_tab, 3);
  435. db_set_column_name(column, "Y");
  436. db_set_column_sqltype(column, DB_SQL_TYPE_DOUBLE_PRECISION);
  437. if (db_create_table(driver, auxiliar_tab) == DB_OK) {
  438. G_debug(1, _("<%s> created in database."), tab_name);
  439. return TRUE;
  440. }
  441. else
  442. G_warning(_("<%s> has not been created in database."), tab_name);
  443. return FALSE;
  444. }
  445. /*------------------------------------------------------------------------------------------------*/
  446. int P_Drop_Aux_Table(dbDriver * driver, char *tab_name)
  447. {
  448. dbString drop;
  449. db_init_string(&drop);
  450. db_append_string(&drop, "drop table ");
  451. db_append_string(&drop, tab_name);
  452. return db_execute_immediate(driver, &drop);
  453. }
  454. /*---------------------------------------------------------------------------------------*/
  455. void P_Aux_to_Raster(double **matrix, int fd)
  456. {
  457. int ncols, col, nrows, row;
  458. void *ptr, *raster;
  459. nrows = Rast_window_rows();
  460. ncols = Rast_window_cols();
  461. raster = Rast_allocate_buf(DCELL_TYPE);
  462. for (row = 0; row < nrows; row++) {
  463. G_percent(row, nrows, 2);
  464. Rast_set_d_null_value(raster, ncols);
  465. for (col = 0, ptr = raster; col < ncols;
  466. col++, ptr = G_incr_void_ptr(ptr, Rast_cell_size(DCELL_TYPE))) {
  467. Rast_set_d_value(ptr, (DCELL) (matrix[row][col]), DCELL_TYPE);
  468. }
  469. Rast_put_d_row(fd, raster);
  470. }
  471. G_percent(row, nrows, 2);
  472. }
  473. /*------------------------------------------------------------------------------------------------*/
  474. void
  475. P_Aux_to_Vector(struct Map_info *Map, struct Map_info *Out, dbDriver * driver,
  476. char *tab_name)
  477. {
  478. int more, line_num, type, count = 0;
  479. double coordX, coordY, coordZ;
  480. struct line_pnts *point;
  481. struct line_cats *cat;
  482. dbTable *table;
  483. dbColumn *column;
  484. dbValue *value;
  485. dbCursor cursor;
  486. dbString sql;
  487. char buf[1024];
  488. point = Vect_new_line_struct();
  489. cat = Vect_new_cats_struct();
  490. db_init_string(&sql);
  491. db_zero_string(&sql);
  492. sprintf(buf, "select ID, X, Y, sum(Interp) from %s group by ID, X, Y",
  493. tab_name);
  494. db_append_string(&sql, buf);
  495. db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL);
  496. while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) {
  497. count++;
  498. table = db_get_cursor_table(&cursor);
  499. column = db_get_table_column(table, 0);
  500. type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  501. if (type == DB_C_TYPE_INT)
  502. value = db_get_column_value(column);
  503. else
  504. continue;
  505. line_num = db_get_value_int(value);
  506. column = db_get_table_column(table, 1);
  507. type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  508. if (type == DB_C_TYPE_DOUBLE)
  509. value = db_get_column_value(column);
  510. else
  511. continue;
  512. coordZ = db_get_value_double(value);
  513. column = db_get_table_column(table, 2);
  514. type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  515. if (type == DB_C_TYPE_DOUBLE)
  516. value = db_get_column_value(column);
  517. else
  518. continue;
  519. coordX = db_get_value_double(value);
  520. column = db_get_table_column(table, 3);
  521. type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  522. if (type == DB_C_TYPE_DOUBLE)
  523. value = db_get_column_value(column);
  524. else
  525. continue;
  526. coordY = db_get_value_double(value);
  527. Vect_copy_xyz_to_pnts(point, &coordX, &coordY, &coordZ, 1);
  528. Vect_reset_cats(cat);
  529. Vect_cat_set(cat, 1, 1);
  530. Vect_write_line(Out, GV_POINT, point, cat);
  531. }
  532. return;
  533. }
  534. /*! DEFINITION OF THE SUBZONES
  535. 5: inside Overlap region
  536. all others: inside General region but outside Overlap region
  537. ---------------------------------
  538. | | | | | | | |
  539. ---------------------------------
  540. | | | | | | | |
  541. | | | | | | | |
  542. | | | | | | | |
  543. ---------------------------------
  544. | | |4| 3 |3| | |
  545. ---------------------------------
  546. | | | | | | | |
  547. | | |2| 5 |1| | |
  548. | | | | | | | |
  549. ---------------------------------
  550. | | |2| 1 |1| | |
  551. ---------------------------------
  552. | | | | | | | |
  553. | | | | | | | |
  554. | | | | | | | |
  555. ---------------------------------
  556. | | | | | | | |
  557. ---------------------------------
  558. */