@@ -1835,6 +1835,184 @@ float* euclidean_distance_field3d(
18351835 );
18361836}
18371837
1838+
1839+ class HeapFeatureNode {
1840+ public:
1841+ float key;
1842+ uint64_t value;
1843+ uint64_t source;
1844+
1845+ HeapFeatureNode () {
1846+ key = 0 ;
1847+ value = 0 ;
1848+ }
1849+
1850+ HeapFeatureNode (float k, uint64_t val, uint64_t src) {
1851+ key = k;
1852+ value = val;
1853+ source = src;
1854+ }
1855+
1856+ HeapFeatureNode (const HeapFeatureNode &h) {
1857+ key = h.key ;
1858+ value = h.value ;
1859+ source = h.source ;
1860+ }
1861+ };
1862+
1863+ struct HeapFeatureNodeCompare {
1864+ bool operator ()(const HeapFeatureNode &t1, const HeapFeatureNode &t2) const {
1865+ return t1.key >= t2.key ;
1866+ }
1867+ };
1868+
1869+ // returns a map of the nearest source vertex
1870+ template <typename OUT = uint64_t >
1871+ OUT* edf_with_feature_map (
1872+ uint8_t * field, // really a boolean field
1873+ const uint64_t sx, const uint64_t sy, const uint64_t sz,
1874+ const float wx, const float wy, const float wz,
1875+ const std::vector<uint64_t > &sources,
1876+ float * dist = NULL , OUT* feature_map = NULL ,
1877+ size_t &max_loc = _dummy_max_loc
1878+ ) {
1879+
1880+ const uint64_t voxels = sx * sy * sz;
1881+ const uint64_t sxy = sx * sy;
1882+
1883+ const libdivide::divider<uint64_t > fast_sx (sx);
1884+ const libdivide::divider<uint64_t > fast_sxy (sxy);
1885+
1886+ const bool power_of_two = !((sx & (sx - 1 )) || (sy & (sy - 1 )));
1887+ const int xshift = std::log2 (sx); // must use log2 here, not lg/lg2 to avoid fp errors
1888+ const int yshift = std::log2 (sy);
1889+
1890+ bool clear_dist = false ;
1891+ if (dist == NULL ) {
1892+ dist = new float [voxels]();
1893+ clear_dist = true ;
1894+ }
1895+ if (feature_map == NULL ) {
1896+ feature_map = new OUT[voxels]();
1897+ }
1898+
1899+ fill (dist, +INFINITY, voxels);
1900+
1901+ int neighborhood[NHOOD_SIZE] = {};
1902+
1903+ float neighbor_multiplier[NHOOD_SIZE] = {
1904+ wx, wx, wy, wy, wz, wz, // axial directions (6)
1905+
1906+ // square diagonals (12)
1907+ _s (wx, wy), _s (wx, wy), _s (wx, wy), _s (wx, wy),
1908+ _s (wy, wz), _s (wy, wz), _s (wy, wz), _s (wy, wz),
1909+ _s (wx, wz), _s (wx, wz), _s (wx, wz), _s (wx, wz),
1910+
1911+ // cube diagonals (8)
1912+ _c (wx, wy, wz), _c (wx, wy, wz), _c (wx, wy, wz), _c (wx, wy, wz),
1913+ _c (wx, wy, wz), _c (wx, wy, wz), _c (wx, wy, wz), _c (wx, wy, wz)
1914+ };
1915+
1916+ std::priority_queue<
1917+ HeapFeatureNode, std::vector<HeapFeatureNode>, HeapFeatureNodeCompare
1918+ > queue;
1919+
1920+ uint64_t src = 1 ;
1921+ for (uint64_t source : sources) {
1922+ dist[source] = -0 ;
1923+ feature_map[source] = src;
1924+ queue.emplace (0.0 , source, src);
1925+ src++;
1926+ }
1927+
1928+ uint64_t loc, next_loc;
1929+ float new_dist;
1930+ uint64_t neighboridx;
1931+
1932+ uint64_t x, y, z;
1933+
1934+ float max_dist = -1 ;
1935+ max_loc = voxels + 1 ;
1936+
1937+ while (!queue.empty ()) {
1938+ src = queue.top ().source ;
1939+ loc = queue.top ().value ;
1940+ queue.pop ();
1941+
1942+ if (max_dist < std::abs (dist[loc])) {
1943+ max_dist = std::abs (dist[loc]);
1944+ max_loc = loc;
1945+ }
1946+
1947+ if (std::signbit (dist[loc])) {
1948+ continue ;
1949+ }
1950+
1951+ if (!queue.empty ()) {
1952+ next_loc = queue.top ().value ;
1953+ if (!std::signbit (dist[next_loc])) {
1954+
1955+ // As early as possible, start fetching the
1956+ // data from RAM b/c the annotated lines below
1957+ // have 30-50% cache miss.
1958+ DIJKSTRA_3D_PREFETCH_26WAY (field, next_loc)
1959+ DIJKSTRA_3D_PREFETCH_26WAY (dist, next_loc)
1960+ }
1961+ }
1962+
1963+ if (power_of_two) {
1964+ z = loc >> (xshift + yshift);
1965+ y = (loc - (z << (xshift + yshift))) >> xshift;
1966+ x = loc - ((y + (z << yshift)) << xshift);
1967+ }
1968+ else {
1969+ z = loc / fast_sxy;
1970+ y = (loc - (z * sxy)) / fast_sx;
1971+ x = loc - sx * (y + z * sy);
1972+ }
1973+
1974+ compute_neighborhood (neighborhood, x, y, z, sx, sy, sz, NHOOD_SIZE, NULL );
1975+
1976+ for (int i = 0 ; i < NHOOD_SIZE; i++) {
1977+ if (neighborhood[i] == 0 ) {
1978+ continue ;
1979+ }
1980+
1981+ neighboridx = loc + neighborhood[i];
1982+ if (field[neighboridx] == 0 ) {
1983+ continue ;
1984+ }
1985+
1986+ new_dist = dist[loc] + neighbor_multiplier[i];
1987+
1988+ // Visited nodes are negative and thus the current node
1989+ // will always be less than as field is filled with non-negative
1990+ // integers.
1991+ if (new_dist < dist[neighboridx]) {
1992+ dist[neighboridx] = new_dist;
1993+ feature_map[neighboridx] = src;
1994+ queue.emplace (new_dist, neighboridx, src);
1995+ }
1996+ else if (new_dist == dist[neighboridx] && src > feature_map[neighboridx]) {
1997+ feature_map[neighboridx] = src;
1998+ }
1999+ }
2000+
2001+ dist[loc] = -dist[loc];
2002+ }
2003+
2004+ if (clear_dist) {
2005+ delete[] dist;
2006+ }
2007+ else {
2008+ for (size_t i = 0 ; i < voxels; i++) {
2009+ dist[i] = std::fabs (dist[i]);
2010+ }
2011+ }
2012+
2013+ return feature_map;
2014+ }
2015+
18382016#undef sq
18392017#undef NHOOD_SIZE
18402018#undef DIJKSTRA_3D_PREFETCH_26WAY
0 commit comments