1 // Copyright 2009-2020 Intel Corporation 2 // SPDX-License-Identifier: Apache-2.0 3 4 #pragma once 5 6 // ospray 7 #include <sstream> 8 #include <vector> 9 #include "../common.h" 10 #include "../math/range.h" 11 #include "for_each.h" 12 13 namespace rkcommon { 14 namespace array3D { 15 16 /*! ABSTRACTION for a 3D array of data */ 17 template <typename value_t> 18 struct Array3D 19 { 20 virtual ~Array3D() = default; 21 22 /*! return size (ie, "dimensions") of volume */ 23 virtual vec3i size() const = 0; 24 25 /*! get cell value at given location, but ensure that location 26 is actually a valid cell ID inside the volume (clamps to 27 nearest cell in volume if 'where' is outside) */ 28 virtual value_t get(const vec3i &where) const = 0; 29 30 /*! get the range/interval of all cell values in the given 31 begin/end region of the volume */ getValueRangeArray3D32 range_t<value_t> getValueRange(const vec3i &begin, const vec3i &end) const 33 { 34 range_t<value_t> v = get(begin); 35 for_each(begin, end, [&](const vec3i &idx) { v.extend(get(idx)); }); 36 return v; 37 } 38 39 /*! get value range over entire volume */ getValueRangeArray3D40 range_t<value_t> getValueRange() const 41 { 42 return getValueRange(vec3i(0), size()); 43 } 44 45 /*! returns number of elements (as 64-bit int) across all dimensions */ 46 virtual size_t numElements() const = 0; 47 }; 48 49 /*! implementation for an actual array3d that stores a 3D array of values */ 50 template <typename value_t> 51 struct ActualArray3D : public Array3D<value_t> 52 { 53 ActualArray3D(const vec3i &dims, void *externalMem = nullptr); ~ActualArray3DActualArray3D54 ~ActualArray3D() override 55 { 56 if (valuesAreMine) 57 delete[] value; 58 } 59 60 /*! return size (ie, "dimensions") of volume */ 61 vec3i size() const override; 62 63 /*! get cell value at location 64 65 \warning 'where' MUST be a valid cell location */ 66 value_t get(const vec3i &where) const override; 67 68 /*! set cell value at location to given value 69 70 \warning 'where' MUST be a valid cell location */ 71 void set(const vec3i &where, const value_t &t); 72 73 void clear(const value_t &t); 74 75 /*! returns number of elements (as 64-bit int) across all dimensions */ 76 size_t numElements() const override; 77 78 /* compute the (1D) linear array index for a (3D) grid coordinate */ indexOfActualArray3D79 size_t indexOf(const vec3i &pos) const 80 { 81 return pos.x + size_t(dims.x) * (pos.y + size_t(dims.y) * pos.z); 82 } 83 84 const vec3i dims; 85 value_t *value; 86 // bool that specified whether it was us that alloc'ed this mem, 87 // and thus, whether we should free it upon termination. 88 bool valuesAreMine; 89 }; 90 91 /*! shifts another array3d by a given amount */ 92 template <typename value_t> 93 struct IndexShiftedArray3D : public Array3D<value_t> 94 { IndexShiftedArray3DIndexShiftedArray3D95 IndexShiftedArray3D(std::shared_ptr<Array3D<value_t>> _actual, 96 const vec3i &_shift) 97 : actual(_actual), shift(_shift) 98 { 99 } 100 101 /*! return size (ie, "dimensions") of volume */ sizeIndexShiftedArray3D102 vec3i size() const override 103 { 104 return actual->size(); 105 } 106 107 /*! get cell value at location 108 109 \warning 'where' MUST be a valid cell location */ getIndexShiftedArray3D110 value_t get(const vec3i &where) const override 111 { 112 return actual->get((where + size() + shift) % size()); 113 } 114 115 /*! set cell value at location to given value 116 117 \warning 'where' MUST be a valid cell location */ setIndexShiftedArray3D118 void set(const vec3i &, const value_t &) 119 { 120 throw std::runtime_error("cannot 'set' in a IndexShiftArray3D"); 121 } 122 123 /*! returns number of elements (as 64-bit int) across all dimensions */ numElementsIndexShiftedArray3D124 size_t numElements() const override 125 { 126 return actual->numElements(); 127 } 128 129 const vec3i shift; 130 const std::shared_ptr<Array3D<value_t>> actual; 131 }; 132 133 /*! implemnetaiton of a wrapper class that makes an actual array3d 134 of one type look like that of another type */ 135 template <typename in_t, typename out_t> 136 struct Array3DAccessor : public Array3D<out_t> 137 { 138 Array3DAccessor(std::shared_ptr<Array3D<in_t>> actual); 139 140 /*! return size (ie, "dimensions") of volume */ 141 vec3i size() const override; 142 143 /*! get cell value at location 144 145 \warning 'where' MUST be a valid cell location */ 146 out_t get(const vec3i &where) const override; 147 148 /*! returns number of elements (as 64-bit int) across all dimensions */ 149 size_t numElements() const override; 150 151 private: 152 //! the actual 3D array we're wrapping around 153 const std::shared_ptr<Array3D<in_t>> actual; 154 }; 155 156 /*! wrapper class that generates an artificially larger data set by 157 simply repeating the given input */ 158 template <typename T> 159 struct Array3DRepeater : public Array3D<T> 160 { 161 Array3DRepeater(const std::shared_ptr<Array3D<T>> &actual, 162 const vec3i &repeatedSize); 163 164 /*! return size (ie, "dimensions") of volume */ 165 vec3i size() const override; 166 167 /*! get cell value at location 168 169 \warning 'where' MUST be a valid cell location */ 170 T get(const vec3i &where) const override; 171 172 /*! returns number of elements (as 64-bit int) across all dimensions */ 173 size_t numElements() const override; 174 175 const vec3i repeatedSize; 176 const std::shared_ptr<Array3D<T>> actual; 177 }; 178 179 /*! implements a sub-set of another array3d */ 180 template <typename value_t> 181 struct SubBoxArray3D : public Array3D<value_t> 182 { SubBoxArray3DSubBoxArray3D183 SubBoxArray3D(const std::shared_ptr<Array3D<value_t>> &actual, 184 const box3i &clipBox) 185 : clipBox(clipBox), actual(actual) 186 { 187 assert(actual); 188 assert(clipBox.upper.x <= actual->size().x); 189 assert(clipBox.upper.y <= actual->size().y); 190 assert(clipBox.upper.z <= actual->size().z); 191 } 192 193 /*! return size (ie, "dimensions") of volume */ sizeSubBoxArray3D194 vec3i size() const override 195 { 196 return clipBox.size(); 197 } 198 199 /*! get cell value at location 200 201 \warning 'where' MUST be a valid cell location */ getSubBoxArray3D202 value_t get(const vec3i &where) const override 203 { 204 return actual->get(where + clipBox.lower); 205 } 206 207 /*! set cell value at location to given value 208 209 \warning 'where' MUST be a valid cell location */ setSubBoxArray3D210 void set(const vec3i &, const value_t &) 211 { 212 throw std::runtime_error("cannot 'set' in a SubBoxArray3D"); 213 } 214 215 /*! returns number of elements (as 64-bit int) across all dimensions */ numElementsSubBoxArray3D216 size_t numElements() const override 217 { 218 vec3i dims = clipBox.size(); 219 return size_t(dims.x) * size_t(dims.y) * size_t(dims.z); 220 } 221 222 const box3i clipBox; 223 const std::shared_ptr<Array3D<value_t>> actual; 224 }; 225 226 /*! implements a array3d that's composed of multiple individual slices */ 227 template <typename value_t> 228 struct MultiSliceArray3D : public Array3D<value_t> 229 { MultiSliceArray3DMultiSliceArray3D230 MultiSliceArray3D( 231 const std::vector<std::shared_ptr<Array3D<value_t>>> &slice) 232 : slice(slice) 233 { 234 } 235 236 /*! return size (ie, "dimensions") of volume */ sizeMultiSliceArray3D237 vec3i size() const override 238 { 239 return vec3i(slice[0]->size().x, slice[0]->size().y, slice.size()); 240 } 241 242 /*! get cell value at location 243 244 \warning 'where' MUST be a valid cell location */ getMultiSliceArray3D245 value_t get(const vec3i &where) const override 246 { 247 return slice[clamp(where.z, 0, (int)slice.size() - 1)]->get( 248 vec3i(where.x, where.y, 0)); 249 } 250 251 /*! set cell value at location to given value 252 253 \warning 'where' MUST be a valid cell location */ setMultiSliceArray3D254 void set(const vec3i &, const value_t &) 255 { 256 throw std::runtime_error("cannot 'set' in a MultiSliceArray3D"); 257 } 258 259 /*! returns number of elements (as 64-bit int) across all dimensions */ numElementsMultiSliceArray3D260 size_t numElements() const override 261 { 262 return slice[0]->numElements() * slice.size(); 263 } 264 265 const std::vector<std::shared_ptr<Array3D<value_t>>> slice; 266 }; 267 268 #ifndef _WIN32 269 /*! load raw file with given dimensions. the 'type' of the raw 270 file (uint8,float,...) is given through the function's 271 template parameter */ 272 template <typename T> 273 std::shared_ptr<Array3D<T>> RKCOMMON_INTERFACE 274 loadRAW(const std::string &fileName, const vec3i &dims); 275 276 /*! load raw file with given dimensions. the 'type' of the raw 277 file (uint8,float,...) is given through the function's 278 template parameter */ 279 template <typename T> 280 std::shared_ptr<Array3D<T>> RKCOMMON_INTERFACE 281 mmapRAW(const std::string &fileName, const vec3i &dims); 282 #endif 283 284 // Inlined definitions //////////////////////////////////////////////////// 285 286 // ActualArray3D // 287 288 template <typename T> size()289 inline vec3i ActualArray3D<T>::size() const 290 { 291 return dims; 292 } 293 294 template <typename T> get(const vec3i & _where)295 inline T ActualArray3D<T>::get(const vec3i &_where) const 296 { 297 assert(value != nullptr); 298 const vec3i where = max(vec3i(0), min(_where, dims - vec3i(1))); 299 size_t index = 300 where.x + size_t(dims.x) * (where.y + size_t(dims.y) * (where.z)); 301 assert(value); 302 assert(index < numElements()); 303 const T v = value[index]; 304 return v; 305 } 306 307 template <typename T> numElements()308 inline size_t ActualArray3D<T>::numElements() const 309 { 310 return size_t(dims.x) * size_t(dims.y) * size_t(dims.z); 311 } 312 313 template <typename T> ActualArray3D(const vec3i & dims,void * externalMem)314 inline ActualArray3D<T>::ActualArray3D(const vec3i &dims, void *externalMem) 315 : dims(dims), 316 value((T *)externalMem), 317 valuesAreMine(externalMem == nullptr) 318 { 319 try { 320 if (!value) { 321 const size_t numVoxels = longProduct(dims); 322 value = new T[numVoxels]; 323 } 324 } catch (const std::bad_alloc &) { 325 std::stringstream ss; 326 ss << "could not allocate memory for Array3D of dimensions " << dims 327 << " (in Array3D::Array3D())"; 328 throw std::runtime_error(ss.str()); 329 } 330 } 331 332 template <typename T> set(const vec3i & where,const T & t)333 inline void ActualArray3D<T>::set(const vec3i &where, const T &t) 334 { 335 value[longIndex(where, size())] = t; 336 } 337 338 template <typename T> clear(const T & t)339 inline void ActualArray3D<T>::clear(const T &t) 340 { 341 for_each(size(), [&](const vec3i &idx) { set(idx, t); }); 342 } 343 344 // Array3DAccessor // 345 346 template <typename in_t, typename out_t> Array3DAccessor(std::shared_ptr<Array3D<in_t>> actual)347 inline Array3DAccessor<in_t, out_t>::Array3DAccessor( 348 std::shared_ptr<Array3D<in_t>> actual) 349 : actual(actual) 350 { 351 } 352 353 template <typename in_t, typename out_t> size()354 inline vec3i Array3DAccessor<in_t, out_t>::size() const 355 { 356 return actual->size(); 357 } 358 359 template <typename in_t, typename out_t> get(const vec3i & where)360 inline out_t Array3DAccessor<in_t, out_t>::get(const vec3i &where) const 361 { 362 return (out_t)actual->get(where); 363 } 364 365 template <typename in_t, typename out_t> numElements()366 inline size_t Array3DAccessor<in_t, out_t>::numElements() const 367 { 368 assert(actual); 369 return actual->numElements(); 370 } 371 372 // Array3DRepeater // 373 374 template <typename T> Array3DRepeater(const std::shared_ptr<Array3D<T>> & actual,const vec3i & repeatedSize)375 inline Array3DRepeater<T>::Array3DRepeater( 376 const std::shared_ptr<Array3D<T>> &actual, const vec3i &repeatedSize) 377 : repeatedSize(repeatedSize), actual(actual) 378 { 379 } 380 381 template <typename T> size()382 inline vec3i Array3DRepeater<T>::size() const 383 { 384 return repeatedSize; 385 } 386 387 template <typename T> get(const vec3i & _where)388 inline T Array3DRepeater<T>::get(const vec3i &_where) const 389 { 390 vec3i where(_where.x % repeatedSize.x, 391 _where.y % repeatedSize.y, 392 _where.z % repeatedSize.z); 393 394 if ((_where.x / repeatedSize.x) % 2) 395 where.x = repeatedSize.x - 1 - where.x; 396 if ((_where.y / repeatedSize.y) % 2) 397 where.y = repeatedSize.y - 1 - where.y; 398 if ((_where.z / repeatedSize.z) % 2) 399 where.z = repeatedSize.z - 1 - where.z; 400 401 return actual->get(where); 402 } 403 404 template <typename T> numElements()405 inline size_t Array3DRepeater<T>::numElements() const 406 { 407 return size_t(repeatedSize.x) * size_t(repeatedSize.y) * 408 size_t(repeatedSize.z); 409 } 410 411 } // namespace array3D 412 } // namespace rkcommon 413