@@ -1835,6 +1835,184 @@ float* euclidean_distance_field3d(
1835
1835
);
1836
1836
}
1837
1837
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
+
1838
2016
#undef sq
1839
2017
#undef NHOOD_SIZE
1840
2018
#undef DIJKSTRA_3D_PREFETCH_26WAY
0 commit comments