distribute.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  1. /****************************************************************************
  2. *
  3. * MODULE: r.viewshed
  4. *
  5. * AUTHOR(S): Laura Toma, Bowdoin College - ltoma@bowdoin.edu
  6. * Yi Zhuang - yzhuang@bowdoin.edu
  7. * Ported to GRASS by William Richard -
  8. * wkrichar@bowdoin.edu or willster3021@gmail.com
  9. * Markus Metz: surface interpolation
  10. *
  11. * Date: april 2011
  12. *
  13. * PURPOSE: To calculate the viewshed (the visible cells in the
  14. * raster) for the given viewpoint (observer) location. The
  15. * visibility model is the following: Two points in the raster are
  16. * considered visible to each other if the cells where they belong are
  17. * visible to each other. Two cells are visible to each other if the
  18. * line-of-sight that connects their centers does not intersect the
  19. * terrain. The terrain is NOT viewed as a tesselation of flat cells,
  20. * i.e. if the line-of-sight does not pass through the cell center,
  21. * elevation is determined using bilinear interpolation.
  22. * The viewshed algorithm is efficient both in
  23. * terms of CPU operations and I/O operations. It has worst-case
  24. * complexity O(n lg n) in the RAM model and O(sort(n)) in the
  25. * I/O-model. For the algorithm and all the other details see the
  26. * paper: "Computing Visibility on * Terrains in External Memory" by
  27. * Herman Haverkort, Laura Toma and Yi Zhuang.
  28. *
  29. * COPYRIGHT: (C) 2008 by the GRASS Development Team
  30. *
  31. * This program is free software under the GNU General Public License
  32. * (>=v2). Read the file COPYING that comes with GRASS for details.
  33. *
  34. *****************************************************************************/
  35. #include <assert.h>
  36. #include <stdlib.h>
  37. #include <stdio.h>
  38. #include <math.h>
  39. extern "C"
  40. {
  41. #include <grass/config.h>
  42. #include <grass/gis.h>
  43. #include <grass/glocale.h>
  44. }
  45. /* include IOSTREAM header */
  46. #include <grass/iostream/ami.h>
  47. /*note: MAX_STREAMS_OPEN defined in include/iostream/ami_stream.h
  48. which is included by ami.h */
  49. #include "distribute.h"
  50. #include "viewshed.h"
  51. #include "visibility.h"
  52. #include "eventlist.h"
  53. #include "statusstructure.h"
  54. #include "grass.h"
  55. #define DISTRIBDEBUG if(0)
  56. #define SOLVEINMEMDEBUG if(0)
  57. #define DEBUGINIT if(0)
  58. #define PRINTWARNING if(0)
  59. #define BND_DEBUG if(0)
  60. #define ANGLE_FACTOR 1
  61. #define EPSILON GRASS_EPSILON
  62. #define PRINT_DISTRIBUTE if(0)
  63. ////////////////////////////////////////////////////////////////////////
  64. /* distribution sweep: write results to visgrid.
  65. */
  66. IOVisibilityGrid *distribute_and_sweep(char *inputfname,
  67. GridHeader * hd,
  68. Viewpoint * vp,
  69. ViewOptions viewOptions)
  70. {
  71. assert(inputfname && hd && vp);
  72. G_message(_("Start distributed sweeping."));
  73. /* ------------------------------ */
  74. /*initialize the visibility grid */
  75. IOVisibilityGrid *visgrid;
  76. visgrid = init_io_visibilitygrid(*hd, *vp);
  77. G_debug(1, "distribute_and_sweep: visgrid=%s", visgrid->visStr->name());
  78. /* ------------------------------ */
  79. /*construct event list corresp to the input file and viewpoint */
  80. Rtimer initEventTime;
  81. rt_start(initEventTime);
  82. AMI_STREAM < AEvent > *eventList;
  83. eventList = init_event_list(inputfname, vp, hd,
  84. viewOptions, NULL, visgrid);
  85. assert(eventList);
  86. eventList->seek(0);
  87. rt_stop(initEventTime);
  88. G_debug(1, "distribute_and_sweep: eventlist=%s", eventList->sprint());
  89. /* ------------------------------ */
  90. /*sort the events concentrically */
  91. Rtimer sortEventTime;
  92. rt_start(sortEventTime);
  93. G_debug(1, "Sorting events by distance from viewpoint..");
  94. sort_event_list_by_distance(&eventList, *vp);
  95. G_debug(1, "..sorting done.");
  96. /* debugging */
  97. /*sortCheck(eventList, *vp); */
  98. eventList->seek(0); /*this does not seem to be ensured by sort */
  99. rt_stop(sortEventTime);
  100. G_debug(1, "distribute_and_sweep: eventlist=%s", eventList->sprint());
  101. /* ------------------------------ */
  102. /* start distribution */
  103. long nvis; /*number of cells visible. Returned by distribute_sector */
  104. Rtimer sweepTime;
  105. rt_start(sweepTime);
  106. /*distribute recursively the events and write results to visgrid.
  107. invariant: distribute_sector deletes its eventlist */
  108. nvis = distribute_sector(eventList, NULL, 0, ANGLE_FACTOR * 2 * M_PI,
  109. visgrid, vp, hd, viewOptions);
  110. rt_stop(sweepTime);
  111. /* ------------------------------ */
  112. /*cleanup */
  113. G_message(_("Distribution sweeping done."));
  114. G_verbose_message("Total cells %ld, visible cells %ld (%.1f percent).",
  115. (long)visgrid->hd->nrows * visgrid->hd->ncols,
  116. nvis,
  117. (float)((float)nvis * 100 /
  118. (float)(visgrid->hd->nrows * visgrid->hd->ncols)));
  119. print_viewshed_timings(initEventTime, sortEventTime, sweepTime);
  120. return visgrid;
  121. }
  122. //***********************************************************************
  123. /* distribute recursively the events and write results to
  124. visgrid. eventList is a list of events sorted by distance that fall
  125. within angle boundaries start_angle and end_angle; enterBndEvents
  126. is a stream that contains all the ENTER events that are not in this
  127. sector, but their corresponding Q or X events are in this sector.
  128. When problem is small enough, solve it in memory and write results to
  129. visgrid.
  130. invariant: distribute_sector deletes eventList and enterBndEvents
  131. */
  132. unsigned long distribute_sector(AMI_STREAM < AEvent > *eventList,
  133. AMI_STREAM < AEvent > *enterBndEvents,
  134. double start_angle, double end_angle,
  135. IOVisibilityGrid * visgrid, Viewpoint * vp,
  136. GridHeader *hd, ViewOptions viewOptions)
  137. {
  138. assert(eventList && visgrid && vp);
  139. /*enterBndEvents may be NULL first time */
  140. G_debug(2, "*** DISTRIBUTE sector [%.4f, %.4f] ***",
  141. start_angle, end_angle);
  142. G_debug(2, "initial_gradient: %f", SMALLEST_GRADIENT);
  143. G_debug(2, "eventlist: %s", eventList->sprint());
  144. if (enterBndEvents)
  145. G_debug(2, "BndEvents: %s", enterBndEvents->sprint());
  146. PRINT_DISTRIBUTE LOG_avail_memo();
  147. unsigned long nvis = 0;
  148. /*******************************************************
  149. BASE CASE
  150. *******************************************************/
  151. if (eventList->stream_len() * sizeof(AEvent) <
  152. MM_manager.memory_available()) {
  153. if (enterBndEvents) {
  154. nvis += solve_in_memory(eventList, enterBndEvents,
  155. start_angle, end_angle, visgrid, hd,
  156. vp, viewOptions);
  157. return nvis;
  158. }
  159. else {
  160. /*we are here if the problem fits in memory, and
  161. //enterBNdEvents==NULL---this only happens the very first time;
  162. //technically at this point we should do one pass though the
  163. //data and collect the events that cross the 1st and 4th
  164. //quadrant; instead we force recursion, nect= 2 */
  165. }
  166. }
  167. /*else, must recurse */
  168. PRINT_DISTRIBUTE G_debug(2, "In EXTERNAL memory");
  169. /*compute number of sectors */
  170. int nsect = compute_n_sectors();
  171. assert(nsect > 1);
  172. /*an array of streams, one for each sector; sector[i] will keep all
  173. the cells that are completely inside sector i */
  174. AMI_STREAM < AEvent > *sector = new AMI_STREAM < AEvent >[nsect];
  175. /*the array of gradient values, one for each sector; the gradient is
  176. the gradient of the center of a cell that spans the sector
  177. completely */
  178. double *high = new double[nsect];
  179. for (int i = 0; i < nsect; i++)
  180. high[i] = SMALLEST_GRADIENT;
  181. /*an array of streams, one for each stream boundary; sectorBnd[0]
  182. will keep all the cells crossing into sector 0 from below; and so on. */
  183. AMI_STREAM < AEvent > *sectorBnd = new AMI_STREAM < AEvent >[nsect];
  184. /*keeps stats for each sector */
  185. long *total = new long[nsect];
  186. long *insert = new long[nsect];
  187. long *drop = new long[nsect];
  188. long *bndInsert = new long[nsect];
  189. long *bndDrop = new long[nsect];
  190. for (int i = 0; i < nsect; i++)
  191. total[i] = insert[i] = drop[i] = bndInsert[i] = bndDrop[i] = 0;
  192. long longEvents = 0;
  193. /*******************************************************
  194. CONCENTRIC SWEEP
  195. *******************************************************/
  196. AEvent *e;
  197. AMI_err ae;
  198. double exit_angle, enter_angle;
  199. int exit_s, s, enter_s;
  200. long boundaryEvents = 0;
  201. off_t nbEvents = eventList->stream_len();
  202. eventList->seek(0);
  203. for (off_t i = 0; i < nbEvents; i++) {
  204. /*get out one event at a time and process it according to its type */
  205. ae = eventList->read_item(&e);
  206. assert(ae == AMI_ERROR_NO_ERROR);
  207. assert(is_inside(e, start_angle, end_angle));
  208. /*compute its sector */
  209. s = get_event_sector(e->angle, start_angle, end_angle, nsect);
  210. /*detect boundary cases ==> precision issues */
  211. if (is_almost_on_boundary(e->angle, s, start_angle, end_angle, nsect)) {
  212. double ssize = (end_angle - start_angle) / nsect;
  213. boundaryEvents++;
  214. G_debug(2, "WARNING! event ");
  215. print_event(*e, 3);
  216. G_debug(2, "close to boundary");
  217. G_debug(2, "angle=%f close to sector boundaries=[%f, %f]",
  218. e->angle, s * ssize, (s + 1) * ssize);
  219. }
  220. G_debug(2, "event %7lu: ", (unsigned long)i);
  221. print_event(*e, 2);
  222. G_debug(2, "d=%8.1f, ",
  223. get_square_distance_from_viewpoint(*e, *vp));
  224. G_debug(2, "s=%3d ", s);
  225. assert(is_inside(s, nsect));
  226. total[s]++;
  227. /*insert event in sector if not occluded */
  228. insert_event_in_sector(e, s, &sector[s], high[s], vp, insert, drop);
  229. switch (e->eventType) {
  230. case CENTER_EVENT:
  231. break;
  232. case ENTERING_EVENT:
  233. /*find its corresponding exit event and its sector */
  234. exit_angle = calculate_exit_angle(e->row, e->col, vp);
  235. exit_s =
  236. get_event_sector(exit_angle, start_angle, end_angle, nsect);
  237. G_debug(2, " ENTER (a=%.2f,s=%3d)---> EXIT (a=%.2f,s=%3d) ",
  238. e->angle, s, exit_angle, exit_s);
  239. /*note: exit_s can be -1 (outside) */
  240. if (exit_s == s) {
  241. /*short event, fit in sector s */
  242. }
  243. else if (exit_s == (s + 1) % nsect || (exit_s + 1) % nsect == s) {
  244. /*semi-short event; insert in sector s, and in sector boundary s+1
  245. NOTE: to avoid precision issues, the events are inserted
  246. when processing the EXIT_EVENT
  247. insertEventInSector(e, (s+1)%nsect, &sectorBnd[(s+1)%nsect],
  248. high[(s+1)%nsect], vp,bndInsert, bndDrop); */
  249. }
  250. else {
  251. /*long event; insert in sector s, and in sector boundary exit_s */
  252. process_long_cell(s, exit_s, nsect, vp, e, high);
  253. longEvents++;
  254. /*insertEventInSector(e, exit_s, &sectorBnd[exit_s], high[exit_s],
  255. // vp, bndInsert, bndDrop); */
  256. }
  257. break;
  258. case EXITING_EVENT:
  259. /*find its corresponding enter event and its sector */
  260. enter_angle = calculate_enter_angle(e->row, e->col, vp);
  261. enter_s =
  262. get_event_sector(enter_angle, start_angle, end_angle, nsect);
  263. G_debug(2, " EXIT (a=%.2f,s=%3d)--->ENTER (a=%.2f,s=%3d) ",
  264. e->angle, s, enter_angle, enter_s);
  265. /*don't need to check spanned sectors because it is done on its
  266. //ENTER event; actually...you do, because its enter event may
  267. //not be in this sector==> enter_s = -1 (outside) */
  268. if (enter_s == s) {
  269. /*short event, fit in sector */
  270. }
  271. else if (enter_s == (s + 1) % nsect || (enter_s + 1) % nsect == s) {
  272. /*semi-short event
  273. //the corresponding ENTER event must insert itself in sectorBnd[s] */
  274. e->eventType = ENTERING_EVENT;
  275. G_debug(2, "BND event ");
  276. print_event(*e, 2);
  277. G_debug(2, "in bndSector %d", s);
  278. insert_event_in_sector(e, s, &sectorBnd[s], high[s],
  279. vp, bndInsert, bndDrop);
  280. }
  281. else {
  282. /*long event */
  283. process_long_cell(enter_s, s, nsect, vp, e, high);
  284. longEvents++;
  285. /*the corresponding ENTER event must insert itself in sectorBnd[s] */
  286. e->eventType = ENTERING_EVENT;
  287. G_debug(2, "BND event ");
  288. print_event(*e, 2);
  289. G_debug(2, "in bndSector %d", s);
  290. insert_event_in_sector(e, s, &sectorBnd[s], high[s],
  291. vp, bndInsert, bndDrop);
  292. }
  293. break;
  294. } /*switch event-type */
  295. G_debug(2, "\n");
  296. } /*for event i */
  297. /*distribute the enterBnd events to the boundary streams of the
  298. //sectors; note: the boundary streams are not sorted by distance. */
  299. if (enterBndEvents)
  300. distribute_bnd_events(enterBndEvents, sectorBnd, nsect, vp,
  301. start_angle, end_angle, high, bndInsert,
  302. bndDrop);
  303. /*sanity checks */
  304. G_debug(2, "boundary events in distribution: %ld",
  305. boundaryEvents);
  306. print_sector_stats(nbEvents, nsect, high, total, insert, drop, sector,
  307. sectorBnd, bndInsert,
  308. longEvents, start_angle, end_angle);
  309. /*cleanup after sector stats */
  310. delete[]total;
  311. delete[]insert;
  312. delete[]drop;
  313. delete[]high;
  314. delete[]bndInsert;
  315. delete[]bndDrop;
  316. /*we finished processing this sector, delete the event list */
  317. delete eventList;
  318. if (enterBndEvents)
  319. delete enterBndEvents;
  320. /*save stream names of new sectors */
  321. char **sectorName = (char **)G_malloc(nsect * sizeof(char *));
  322. char **sectorBndName = (char **)G_malloc(nsect * sizeof(char *));
  323. assert(sectorName && sectorBndName);
  324. for (int i = 0; i < nsect; i++) {
  325. sector[i].name(&sectorName[i]);
  326. G_debug(2, "saving stream %d: %s\t", i, sectorName[i]);
  327. sector[i].persist(PERSIST_PERSISTENT);
  328. sectorBnd[i].name(&sectorBndName[i]);
  329. G_debug(2, "saving BndStr %d: %s", i,
  330. sectorBndName[i]);
  331. sectorBnd[i].persist(PERSIST_PERSISTENT);
  332. }
  333. /*delete [] sector;
  334. //does this call delete on every single stream?
  335. //for (int i=0; i< nsect; i++ ) delete sector[i]; */
  336. delete[]sector;
  337. delete[]sectorBnd;
  338. /*LOG_avail_memo(); */
  339. /*solve recursively each sector */
  340. for (int i = 0; i < nsect; i++) {
  341. /*recover stream */
  342. G_debug(3, "opening sector stream %s ", sectorName[i]);
  343. AMI_STREAM < AEvent > *str =
  344. new AMI_STREAM < AEvent > (sectorName[i]);
  345. assert(str);
  346. G_debug(3, " len=%lu",
  347. (unsigned long)str->stream_len());
  348. /*recover boundary stream */
  349. G_debug(3, "opening boundary sector stream %s ",
  350. sectorBndName[i]);
  351. AMI_STREAM < AEvent > *bndStr =
  352. new AMI_STREAM < AEvent > (sectorBndName[i]);
  353. assert(str);
  354. G_debug(3, " len=%lu",
  355. (unsigned long)bndStr->stream_len());
  356. nvis += distribute_sector(str, bndStr,
  357. start_angle +
  358. i * ((end_angle - start_angle) / nsect),
  359. start_angle + (i +
  360. 1) * ((end_angle -
  361. start_angle) / nsect),
  362. visgrid, vp, hd, viewOptions);
  363. }
  364. /*cleanup */
  365. G_free(sectorName);
  366. G_free(sectorBndName);
  367. G_debug(2, "Distribute sector [ %.4f, %.4f] done.",
  368. start_angle, end_angle);
  369. return nvis;
  370. }
  371. /***********************************************************************
  372. enterBndEvents is a stream of events that cross into the sector's
  373. (first) boundary; they must be distributed to the boundary streams
  374. of the sub-sectors of this sector. Note: the boundary streams of
  375. the sub-sectors may not be empty; as a result, events get appended
  376. at the end, and they will not be sorted by distance from the
  377. vp.
  378. */
  379. void
  380. distribute_bnd_events(AMI_STREAM < AEvent > *bndEvents,
  381. AMI_STREAM < AEvent > *sectorBnd, int nsect,
  382. Viewpoint * vp, double start_angle, double end_angle,
  383. double *high, long *insert, long *drop)
  384. {
  385. G_debug(3, "Distribute boundary of sector [ %.4f, %.4f] ",
  386. start_angle, end_angle);
  387. assert(bndEvents && sectorBnd && vp && high && insert && drop);
  388. AEvent *e;
  389. AMI_err ae;
  390. double exit_angle;
  391. int exit_s;
  392. off_t nbEvents = bndEvents->stream_len();
  393. bndEvents->seek(0);
  394. for (off_t i = 0; i < nbEvents; i++) {
  395. /*get out one event at a time */
  396. ae = bndEvents->read_item(&e);
  397. assert(ae == AMI_ERROR_NO_ERROR);
  398. /*must be outside, but better not check to avoid precision issues
  399. //assert(!is_inside(e, start_angle, end_angle));
  400. //each event must be an ENTER event that falls in a diff sector
  401. //than its EXIT */
  402. assert(e->eventType == ENTERING_EVENT);
  403. /*find its corresponding exit event and its sector */
  404. exit_angle = calculate_exit_angle(e->row, e->col, vp);
  405. exit_s = get_event_sector(exit_angle, start_angle, end_angle, nsect);
  406. /*exit_s cannot be outside sector; though we have to be careful
  407. //with precision */
  408. assert(is_inside(exit_s, nsect));
  409. /*insert this event in the boundary stream of this sub-sector */
  410. insert_event_in_sector(e, exit_s, &sectorBnd[exit_s], high[exit_s],
  411. vp, insert, drop);
  412. } /*for i */
  413. G_debug(3, "Distribute boundary of sector [ %.4f, %.4f] done.",
  414. start_angle, end_angle);
  415. return;
  416. }
  417. //***********************************************************************
  418. /* Solves a segment in memory. it is called by distribute() when
  419. sector fits in memory. eventList is the list of events in
  420. increasing order of distance from the viewpoint; enterBndEvents is
  421. the list of ENTER events that are outside the sector, whose
  422. corresponding EXIT events are inside the sector. start_angle and
  423. end_angle are the boundaries of the sector, and visgrid is the grid
  424. to which the visible/invisible cells must be written. The sector is
  425. solved by switching to radial sweep. */
  426. unsigned long solve_in_memory(AMI_STREAM < AEvent > *eventList,
  427. AMI_STREAM < AEvent > *enterBndEvents,
  428. double start_angle, double end_angle,
  429. IOVisibilityGrid * visgrid, GridHeader *hd,
  430. Viewpoint * vp, ViewOptions viewOptions)
  431. {
  432. assert(eventList && visgrid && vp);
  433. G_debug(2, "solve INTERNAL memory");
  434. unsigned long nvis = 0; /*number of visible cells */
  435. G_debug(2, "solve_in_memory: eventlist: %s", eventList->sprint());
  436. if (enterBndEvents)
  437. G_debug(2, "BndEvents: %s", enterBndEvents->sprint());
  438. if (eventList->stream_len() == 0) {
  439. delete eventList;
  440. if (enterBndEvents)
  441. delete enterBndEvents;
  442. return nvis;
  443. }
  444. /*sort the events radially */
  445. sort_event_list(&eventList);
  446. /*create the status structure */
  447. StatusList *status_struct = create_status_struct();
  448. /*initialize status structure with all ENTER events whose EXIT
  449. //events is inside the sector */
  450. AEvent *e;
  451. AMI_err ae;
  452. StatusNode sn;
  453. int inevents = 0;
  454. /*
  455. eventList->seek(0);
  456. double enter_angle;
  457. ae = eventList->read_item(&e);
  458. while (ae == AMI_ERROR_NO_ERROR) {
  459. if (e->eventType == EXITING_EVENT) {
  460. enter_angle = calculateEnterAngle(e->row, e->col, vp);
  461. //to get around precision problems, insert cell in active
  462. //structure when close to the boundary --- these may cause a
  463. //double insert, but subsequent ENTER events close to the
  464. //boundary will be careful not to insert
  465. if (!is_inside(enter_angle, start_angle, end_angle) ||
  466. is_almost_on_boundary(enter_angle, start_angle)) {
  467. DEBUGINIT {printf("inserting "); print_event(*e); printf("\n");}
  468. //this must span the first boundary of this sector; insert it
  469. //in status structure
  470. sn.col = e->col;
  471. sn.row = e->row;
  472. sn.elev = e->elev;
  473. calculateDistNGradient(&sn, vp);
  474. insertIntoStatusStruct(sn, status_struct);
  475. inevents++;
  476. }
  477. }
  478. ae = eventList->read_item(&e);
  479. }
  480. assert(ae == AMI_ERROR_END_OF_STREAM);
  481. */
  482. if (enterBndEvents) {
  483. double ax, ay;
  484. enterBndEvents->seek(0);
  485. inevents = enterBndEvents->stream_len();
  486. for (off_t i = 0; i < inevents; i++) {
  487. ae = enterBndEvents->read_item(&e);
  488. assert(ae == AMI_ERROR_NO_ERROR);
  489. G_debug(3, "INMEM init: initializing boundary ");
  490. print_event(*e, 3);
  491. G_debug(3, "\n");
  492. /*this must span the first boundary of this sector; insert it
  493. //in status structure */
  494. sn.col = e->col;
  495. sn.row = e->row;
  496. e->eventType = ENTERING_EVENT;
  497. calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
  498. sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
  499. calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
  500. e->eventType = CENTER_EVENT;
  501. calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
  502. sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
  503. calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
  504. e->eventType = EXITING_EVENT;
  505. calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
  506. sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
  507. calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
  508. if (sn.angle[0] > sn.angle[1])
  509. sn.angle[0] -= 2 * M_PI;
  510. //calculate_dist_n_gradient(&sn, vp);
  511. insert_into_status_struct(sn, status_struct);
  512. }
  513. }
  514. G_debug(2, "initialized active structure with %d events", inevents);
  515. /*sweep the event list */
  516. VisCell viscell;
  517. off_t nbEvents = eventList->stream_len();
  518. /*printf("nbEvents = %ld\n", (long) nbEvents); */
  519. eventList->seek(0);
  520. for (off_t i = 0; i < nbEvents; i++) {
  521. /*get out one event at a time and process it according to its type */
  522. ae = eventList->read_item(&e);
  523. assert(ae == AMI_ERROR_NO_ERROR);
  524. G_debug(3, "INMEM sweep: next event: ");
  525. print_event(*e, 3);
  526. sn.col = e->col;
  527. sn.row = e->row;
  528. //sn.elev = e->elev;
  529. /*calculate Distance to VP and Gradient */
  530. calculate_dist_n_gradient(&sn, e->elev[1] + vp->target_offset, vp, *hd);
  531. switch (e->eventType) {
  532. case ENTERING_EVENT:
  533. double ax, ay;
  534. /*insert node into structure */
  535. G_debug(3, "..ENTER-EVENT: insert");
  536. /*don't insert if its close to the boundary---the segment was
  537. //already inserted in initialization above
  538. //if (!is_almost_on_boundary(e->angle, start_angle))
  539. //insertIntoStatusStruct(sn,status_struct); */
  540. sn.angle[0] = calculate_enter_angle(sn.row, sn.col, vp);
  541. sn.angle[1] = calculate_angle(sn.col, sn.row, vp->col, vp->row);
  542. sn.angle[2] = calculate_exit_angle(sn.row, sn.col, vp);
  543. calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
  544. //sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
  545. sn.angle[0] = e->angle;
  546. calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
  547. e->eventType = CENTER_EVENT;
  548. calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
  549. sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
  550. calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
  551. e->eventType = EXITING_EVENT;
  552. calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
  553. sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
  554. calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
  555. e->eventType = ENTERING_EVENT;
  556. if (e->angle < M_PI) {
  557. if (sn.angle[0] > sn.angle[1])
  558. sn.angle[0] -= 2 * M_PI;
  559. }
  560. else {
  561. if (sn.angle[0] > sn.angle[1]) {
  562. sn.angle[1] += 2 * M_PI;
  563. sn.angle[2] += 2 * M_PI;
  564. }
  565. }
  566. insert_into_status_struct(sn, status_struct);
  567. break;
  568. case EXITING_EVENT:
  569. /*delete node out of status structure */
  570. SOLVEINMEMDEBUG {
  571. G_debug(3, "..EXIT-EVENT: delete");
  572. /*find its corresponding enter event and its sector */
  573. double enter_angle =
  574. calculate_enter_angle(e->row, e->col, vp);
  575. G_debug(3, " EXIT (a=%f)--->ENTER (a=%f) ", e->angle,
  576. enter_angle);
  577. }
  578. delete_from_status_struct(status_struct, sn.dist2vp);
  579. break;
  580. case CENTER_EVENT:
  581. SOLVEINMEMDEBUG {
  582. G_debug(3, "..QUERY-EVENT: query");
  583. }
  584. /*calculate visibility
  585. //note: if there is nothing in the status structure, it means
  586. //there is no prior event to occlude it, so this cell is
  587. //VISIBLE. this is taken care of in the status structure --- if
  588. //a query event comes when the structure is empty, the query
  589. //returns minimum gradient */
  590. double max;
  591. max =
  592. find_max_gradient_in_status_struct(status_struct, sn.dist2vp,
  593. e->angle, sn.gradient[1]);
  594. viscell.row = sn.row;
  595. viscell.col = sn.col;
  596. if (max <= sn.gradient[1]) {
  597. /*the point is visible */
  598. viscell.angle =
  599. get_vertical_angle(*vp, sn, e->elev[1] + vp->target_offset, viewOptions.doCurv);
  600. assert(viscell.angle > 0);
  601. /* viscell.vis = VISIBLE; */
  602. add_result_to_io_visibilitygrid(visgrid, &viscell);
  603. /*make sure nvis is correct */
  604. nvis++;
  605. }
  606. else {
  607. /* else the point is invisible; we do not write it to the
  608. //visibility stream, because we only record visible and nodata
  609. //values to the stream */
  610. /* viscell.vis = INVISIBLE; */
  611. /* add_result_to_io_visibilitygrid(visgrid, &viscell); */
  612. }
  613. break;
  614. }
  615. } /* for each event */
  616. G_debug(2, "in memory sweeping done.");
  617. G_debug(2, "Total cells %lu, visible cells %lu (%.1f percent).",
  618. (unsigned long)eventList->stream_len(), nvis,
  619. (float)((float)nvis * 100 / (float)(eventList->stream_len())));
  620. /*cleanup */
  621. delete_status_structure(status_struct);
  622. /*invariant: must delete its eventList */
  623. delete eventList;
  624. if (enterBndEvents)
  625. delete enterBndEvents;
  626. return nvis;
  627. }
  628. /***********************************************************************
  629. //returns 1 if enter angle is within epsilon from boundary angle*/
  630. int is_almost_on_boundary(double angle, double boundary_angle)
  631. {
  632. /*printf("is_almost_on_boundary: %f (%f) %f\n", angle, angle-2*M_PI, boundary_angle); */
  633. return (fabs(angle - boundary_angle) < EPSILON) ||
  634. (fabs(angle - 2 * M_PI - boundary_angle) < EPSILON);
  635. }
  636. /***********************************************************************
  637. // returns 1 if angle is within epsilon the boundaries of sector s*/
  638. int
  639. is_almost_on_boundary(double angle, int s, double start_angle,
  640. double end_angle, int nsect)
  641. {
  642. /*the boundaries of sector s */
  643. double ssize = (end_angle - start_angle) / nsect;
  644. return is_almost_on_boundary(angle, s * ssize) ||
  645. is_almost_on_boundary(angle, (s + 1) * ssize);
  646. }
  647. /***********************************************************************
  648. returns true if the event is inside the given sector */
  649. int is_inside(AEvent * e, double start_angle, double end_angle)
  650. {
  651. assert(e);
  652. return (e->angle >= (start_angle - EPSILON) &&
  653. e->angle <= (end_angle + EPSILON));
  654. }
  655. /***********************************************************************
  656. returns true if this angle is inside the given sector */
  657. int is_inside(double angle, double start_angle, double end_angle)
  658. {
  659. return (angle >= (start_angle - EPSILON) &&
  660. angle <= (end_angle + EPSILON));
  661. }
  662. /***********************************************************************
  663. return the start angle of the i-th sector. Assuming that
  664. [start..end] is split into nsectors */
  665. double
  666. get_sector_start(int i, double start_angle, double end_angle, int nsect)
  667. {
  668. assert(is_inside(i, nsect));
  669. return start_angle + i * ((end_angle - start_angle) / nsect);
  670. }
  671. /***********************************************************************
  672. return the start angle of the i-th sector. Assuming that
  673. [start..end] is split into nsectors */
  674. double get_sector_end(int i, double start_angle, double end_angle, int nsect)
  675. {
  676. assert(is_inside(i, nsect));
  677. return start_angle + (i + 1) * ((end_angle - start_angle) / nsect);
  678. }
  679. /***********************************************************************
  680. return 1 is s is inside sector; that is, if it is not -1 */
  681. int is_inside(int s, int nsect)
  682. {
  683. return (s >= 0 && s < nsect);
  684. }
  685. /***********************************************************************
  686. the event e spans sectors from start_s to end_s; Action: update
  687. high[] for each spanned sector. start_s and both_s can be -1, which
  688. means outside given sector---in that case long cell spans to the
  689. boundary of the sector.
  690. */
  691. void
  692. process_long_cell(int start_s, int end_s, int nsect,
  693. Viewpoint * vp, AEvent * e, double *high)
  694. {
  695. G_debug(4, "LONG CELL: spans [%3d, %3d] ", start_s, end_s);
  696. double ctrgrad = calculate_center_gradient(e, vp);
  697. /*ENTER event is outside */
  698. if (start_s == -1) {
  699. assert(e->eventType == EXITING_EVENT);
  700. assert(is_inside(end_s, nsect));
  701. /*span from 0 to end_s */
  702. for (int j = 0; j < end_s; j++) {
  703. if (high[j] < ctrgrad) {
  704. /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
  705. high[j] = ctrgrad;
  706. }
  707. }
  708. return;
  709. }
  710. /*EXIT event is outside */
  711. if (end_s == -1) {
  712. assert(e->eventType == ENTERING_EVENT);
  713. assert(is_inside(start_s, nsect));
  714. /*span from start_s to nsect */
  715. for (int j = start_s + 1; j < nsect; j++) {
  716. if (high[j] < ctrgrad) {
  717. /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
  718. high[j] = ctrgrad;
  719. }
  720. }
  721. return;
  722. }
  723. /*the usual scenario, both inside sector */
  724. if (start_s < end_s) {
  725. /*we must update high[] in start_s+1..end_s-1 */
  726. for (int j = start_s + 1; j < end_s; j++) {
  727. if (high[j] < ctrgrad) {
  728. /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
  729. high[j] = ctrgrad;
  730. }
  731. }
  732. return;
  733. }
  734. else {
  735. /*start_s > end_s: we must insert in [start_s..nsect] and [0, end_s] */
  736. for (int j = start_s + 1; j < nsect; j++) {
  737. if (high[j] < ctrgrad) {
  738. /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
  739. high[j] = ctrgrad;
  740. }
  741. }
  742. for (int j = 0; j < end_s; j++) {
  743. if (high[j] < ctrgrad) {
  744. /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
  745. high[j] = ctrgrad;
  746. }
  747. }
  748. }
  749. return;
  750. }
  751. /***********************************************************************
  752. prints how many events were inserted and dropped in each sector */
  753. void
  754. print_sector_stats(off_t nevents, int nsect, double *high,
  755. long *total,
  756. long *insert, long *drop, AMI_STREAM < AEvent > *sector,
  757. AMI_STREAM < AEvent > *bndSector, long *bndInsert,
  758. long longEvents, double start_angle, double end_angle)
  759. {
  760. unsigned long totalSector = 0, totalDrop = 0, totalInsert = 0;
  761. for (int i = 0; i < nsect; i++) {
  762. assert(total[i] == insert[i] + drop[i]);
  763. assert(insert[i] == sector[i].stream_len());
  764. assert(bndInsert[i] == bndSector[i].stream_len());
  765. totalSector += total[i];
  766. totalDrop += drop[i];
  767. totalInsert += insert[i];
  768. }
  769. assert(totalSector == nevents);
  770. PRINT_DISTRIBUTE {
  771. G_debug(3, "-----nsectors=%d", nsect);
  772. for (int i = 0; i < nsect; i++) {
  773. G_debug(3, "\ts=%3d ", i);
  774. G_debug(3, "[%.4f, %.4f] ",
  775. get_sector_start(i, start_angle, end_angle, nsect),
  776. get_sector_end(i, start_angle, end_angle, nsect));
  777. G_debug(3, "high = %9.1f, ", high[i]);
  778. G_debug(3, "total = %10ld, ", total[i]);
  779. G_debug(3, "inserted = %10ld, ", insert[i]);
  780. G_debug(3, "dropped = %10ld, ", drop[i]);
  781. G_debug(3, "BOUNDARY = %5ld", bndInsert[i]);
  782. G_debug(3, "\n");
  783. }
  784. }
  785. G_debug(3, "Distribute [%.4f, %.4f]: nsect=%d, ",
  786. start_angle, end_angle, nsect);
  787. G_debug(3,
  788. "total events %lu, inserted %lu, dropped %lu, long events=%ld",
  789. totalSector, totalInsert, totalDrop, longEvents);
  790. return;
  791. }
  792. /***********************************************************************
  793. computes the number of sector for the distribution sweep; technically
  794. M/2B because you need 2 streams per sector */
  795. int compute_n_sectors()
  796. {
  797. long memSizeBytes = MM_manager.memory_available();
  798. unsigned int blockSizeBytes = UntypedStream::get_block_length();
  799. /*printf("computeNSect: block=%d, mem=%d\n", blockSizeBytes, (int)memSizeBytes); */
  800. int nsect = (int)(memSizeBytes / (2 * blockSizeBytes));
  801. /*be safe */
  802. if (nsect > 4)
  803. nsect = nsect / 2;
  804. /*if it happens that we are at the end of memory, set nsect=2;
  805. //technically, if there is not enough memory to hold two
  806. //blocks, the function should enter solve_in_memory; so there
  807. //is not enough memory to solve in memory nor to
  808. //distribute...this shoudl happen only under tests with very
  809. //very little memory. just set nsect=2 and hope that it
  810. //works */
  811. if (nsect == 0 || nsect == 1)
  812. nsect = 2;
  813. else {
  814. /*we'll have 2 streams for each sector open; subtract 10 to be safe */
  815. if (2 * nsect > MAX_STREAMS_OPEN - 10)
  816. nsect = (MAX_STREAMS_OPEN - 10) / 2;
  817. }
  818. G_debug(1, "nsectors set to %d", nsect);
  819. return nsect;
  820. }
  821. /***********************************************************************
  822. compute the sector that contains this angle; there are nsect
  823. sectors that span the angle interval [sstartAngle, sendAngle]. if
  824. angle falls outside, return -1*/
  825. int
  826. get_event_sector(double angle, double sstartAngle, double sendAngle,
  827. int nsect)
  828. {
  829. int s = -1;
  830. /*first protect against rounding errors
  831. //in the last sector */
  832. if (fabs(angle - sendAngle) < EPSILON)
  833. return nsect - 1;
  834. /*in the first sector */
  835. if (fabs(angle - sstartAngle) < EPSILON)
  836. return 0;
  837. double ssize = fabs(sstartAngle - sendAngle) / nsect;
  838. s = (int)((angle - sstartAngle) / ssize);
  839. /*printf("getsector: fit %.2f in (%.2f. %.2f)", angle, sstartAngle, sendAngle);
  840. //printf("ssize = %.2f, s=%d", ssize, s);
  841. //assert (s >= 0 && s < nsect); */
  842. if (s < 0 || s >= nsect) {
  843. /*falls outside --- this can happen when finding sector of pair
  844. //event; e.g. ENTER is inside sector, and its pair EXIT event
  845. //falls outside sector. */
  846. s = -1;
  847. }
  848. return s;
  849. }
  850. /***********************************************************************
  851. insert event in this sector */
  852. void insert_event_in_sector(AMI_STREAM < AEvent > *str, AEvent * e)
  853. {
  854. assert(str && e);
  855. AMI_err ae;
  856. ae = str->write_item(*e);
  857. assert(ae == AMI_ERROR_NO_ERROR);
  858. return;
  859. }
  860. /**********************************************************************
  861. insert event e into sector */
  862. void
  863. insert_event_in_sector_no_drop(AEvent * e, int s, AMI_STREAM < AEvent > *str,
  864. long *insert)
  865. {
  866. /*note: if on boundary, PRECISION ISSUES?? should insert both sectors? */
  867. DISTRIBDEBUG {
  868. print_event(*e, 2);
  869. G_debug(2, " insert in sector %3d", s);
  870. }
  871. AMI_err ae;
  872. ae = str->write_item(*e);
  873. assert(ae == AMI_ERROR_NO_ERROR);
  874. insert[s]++;
  875. return;
  876. }
  877. /**********************************************************************
  878. insert event e into sector if it is not occluded by high_s */
  879. void
  880. insert_event_in_sector(AEvent * e, int s, AMI_STREAM < AEvent > *str,
  881. double high_s, Viewpoint * vp, long *insert,
  882. long *drop)
  883. {
  884. /*note: if on boundary, PRECISION ISSUES?? should insert both sectors?
  885. //if not occluded by high_s insert it in its sector */
  886. if (!is_center_gradient_occluded(e, high_s, vp)) {
  887. insert[s]++;
  888. DISTRIBDEBUG {
  889. print_event(*e, 2);
  890. G_debug(2, " insert in sector %3d", s);
  891. }
  892. AMI_err ae;
  893. ae = str->write_item(*e);
  894. assert(ae == AMI_ERROR_NO_ERROR);
  895. }
  896. else {
  897. /*assert(calculateCenterGradient(e, vp) <= high[s]);
  898. //technically, if its a QUERY we should write it as invisible in
  899. //vis stream; but as an optimization, our vis stream only
  900. //records visible stuff. */
  901. DISTRIBDEBUG print_dropped(e, vp, high_s);
  902. drop[s]++;
  903. }
  904. return;
  905. }
  906. /***********************************************************************
  907. returns 1 if the center of event is occluded by the gradient, which
  908. is assumed to be in line with the event */
  909. int is_center_gradient_occluded(AEvent * e, double gradient, Viewpoint * vp)
  910. {
  911. assert(e && vp);
  912. double eg = calculate_center_gradient(e, vp);
  913. return (eg < gradient);
  914. }
  915. /***********************************************************************
  916. called when dropping an event e, high is the highest gradiant value
  917. //in its sector*/
  918. void print_dropped(AEvent * e, Viewpoint * vp, double high)
  919. {
  920. assert(e && vp);
  921. double eg = calculate_center_gradient(e, vp);
  922. G_debug(3, " dropping grad=%.2f, high=%.2f", eg, high);
  923. return;
  924. }