Field3D
SparseField.h
Go to the documentation of this file.
1//----------------------------------------------------------------------------//
2
3/*
4 * Copyright (c) 2009 Sony Pictures Imageworks Inc
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the
17 * distribution. Neither the name of Sony Pictures Imageworks nor the
18 * names of its contributors may be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36//----------------------------------------------------------------------------//
37
42//----------------------------------------------------------------------------//
43
44#ifndef _INCLUDED_Field3D_SparseField_H_
45#define _INCLUDED_Field3D_SparseField_H_
46
47//----------------------------------------------------------------------------//
48
49#include <vector>
50
51#include <boost/thread/mutex.hpp>
52#include <boost/lexical_cast.hpp>
53
54#include "Field.h"
55#include "SparseFile.h"
56
57#define BLOCK_ORDER 4 // 2^BLOCK_ORDER is the block size along each axis
58
59//----------------------------------------------------------------------------//
60
61#include "ns.h"
62
64
65//----------------------------------------------------------------------------//
66// Forward declarations
67//----------------------------------------------------------------------------//
68
69template <class Field_T>
71template <class Field_T>
73
74//----------------------------------------------------------------------------//
75// LinearSparseFieldInterp
76//----------------------------------------------------------------------------//
77
78/* \class LinearSparseFieldInterp
79 \ingroup field
80 \brief Linear interpolator optimized for fields with a fastValue function
81*/
82
83//----------------------------------------------------------------------------//
84
85template <typename Data_T>
87{
88public:
89
90 // Typedefs ------------------------------------------------------------------
91
92 typedef Data_T value_type;
93 typedef boost::intrusive_ptr<LinearSparseFieldInterp> Ptr;
94
95 // RTTI replacement ----------------------------------------------------------
96
99
100 static const char *staticClassName()
101 {
102 return "LinearSparseFieldInterp";
103 }
104
105 static const char* staticClassType()
106 {
107 return ms_classType.name();
108 }
109
110 // Main methods --------------------------------------------------------------
111
112 value_type sample(const SparseField<Data_T> &field, const V3d &vsP) const
113 {
114 // Pixel centers are at .5 coordinates
115 // NOTE: Don't use contToDisc for this, we're looking for sample
116 // point locations, not coordinate shifts.
118
119 // Lower left corner
120 V3i c1(static_cast<int>(floor(p.x)),
121 static_cast<int>(floor(p.y)),
122 static_cast<int>(floor(p.z)));
123 // Upper right corner
124 V3i c2(c1 + V3i(1));
125 // C1 fractions
126 FIELD3D_VEC3_T<double> f1(static_cast<FIELD3D_VEC3_T<double> >(c2) - p);
127 // C2 fraction
128 FIELD3D_VEC3_T<double> f2(static_cast<FIELD3D_VEC3_T<double> >(1.0) - f1);
129
130 const Box3i &dataWindow = field.dataWindow();
131
132 // Clamp the coordinates
133 c1.x = std::min(dataWindow.max.x, std::max(dataWindow.min.x, c1.x));
134 c1.y = std::min(dataWindow.max.y, std::max(dataWindow.min.y, c1.y));
135 c1.z = std::min(dataWindow.max.z, std::max(dataWindow.min.z, c1.z));
136 c2.x = std::min(dataWindow.max.x, std::max(dataWindow.min.x, c2.x));
137 c2.y = std::min(dataWindow.max.y, std::max(dataWindow.min.y, c2.y));
138 c2.z = std::min(dataWindow.max.z, std::max(dataWindow.min.z, c2.z));
139
140 // Determine which block we're in
141 int i = c1.x, j = c1.y, k = c1.z, vi, vj, vk, bi, bj, bk;
142 field.applyDataWindowOffset(i, j, k);
143 field.getVoxelInBlock(i, j, k, vi, vj, vk);
144 field.getBlockCoord(i, j, k, bi, bj, bk);
145 int blockSize = 1 << field.blockOrder();
146
147 // If in the middle of a block, optimize lookup stencil
148 if (vi < blockSize - 1 && vj < blockSize - 1 && vk < blockSize - 1) {
149 if (field.blockIsAllocated(bi, bj, bk)) {
150 // Ensure block data is active and kept alive
151 const int blockId = field.blockId(bi, bj, bk);
152 const bool isDynamicLoad = field.isDynamicLoad();
153 if (isDynamicLoad) {
154 field.incBlockRef(blockId);
155 field.activateBlock(blockId);
156 }
157 // Only do work if the block is allocated
158 const Data_T * const p = field.blockData(bi, bj, bk);
159 const Data_T * const c111 =
160 p + vi + vj * blockSize + vk * blockSize * blockSize;
161 const Data_T * const c121 = c111 + blockSize * (c2.y - c1.y);
162 const Data_T * const
163 c112 = c111 + blockSize * blockSize * (c2.z - c1.z);
164 const Data_T * const c122 = c112 + blockSize * (c2.y - c1.y);
165 int xInc = c2.x - c1.x;
166 Data_T value = static_cast<Data_T>
167 (f1.x * (f1.y * (f1.z * *c111 +
168 f2.z * *c112) +
169 f2.y * (f1.z * *c121 +
170 f2.z * *c122)) +
171 f2.x * (f1.y * (f1.z * *(c111 + xInc) +
172 f2.z * *(c112 + xInc)) +
173 f2.y * (f1.z * *(c121 + xInc) +
174 f2.z * *(c122 + xInc))));
175 // Decrement the block ref count
176 if (isDynamicLoad) {
177 field.decBlockRef(blockId);
178 }
179 // Done.
180 return value;
181 } else {
182 return static_cast<Data_T>(field.getBlockEmptyValue(bi, bj, bk));
183 }
184 } else {
185 return static_cast<Data_T>
186 (f1.x * (f1.y * (f1.z * field.fastValue(c1.x, c1.y, c1.z) +
187 f2.z * field.fastValue(c1.x, c1.y, c2.z)) +
188 f2.y * (f1.z * field.fastValue(c1.x, c2.y, c1.z) +
189 f2.z * field.fastValue(c1.x, c2.y, c2.z))) +
190 f2.x * (f1.y * (f1.z * field.fastValue(c2.x, c1.y, c1.z) +
191 f2.z * field.fastValue(c2.x, c1.y, c2.z)) +
192 f2.y * (f1.z * field.fastValue(c2.x, c2.y, c1.z) +
193 f2.z * field.fastValue(c2.x, c2.y, c2.z))));
194 }
195
196 }
197
198private:
199
200 // Static data members -------------------------------------------------------
201
203
204 // Typedefs ------------------------------------------------------------------
205
207 typedef RefBase base;
208
209};
210
211//----------------------------------------------------------------------------//
212
214
215//----------------------------------------------------------------------------//
216// SparseBlock
217//----------------------------------------------------------------------------//
218
221namespace Sparse {
222
226template <typename Data_T>
227struct SparseBlock : boost::noncopyable
228{
229 // Constructors --------------------------------------------------------------
230
233 : isAllocated(false),
234 emptyValue(static_cast<Data_T>(0)),
235 data(NULL)
236 { /* Empty */ }
237
240 {
241 if (data) {
242 delete[] data;
243 }
244 }
245
246 // Main methods --------------------------------------------------------------
247
249 inline Data_T& value(int i, int j, int k, int blockOrder)
251 { return data[(k << blockOrder << blockOrder) + (j << blockOrder) + i]; }
252
255 inline const Data_T& value(int i, int j, int k, int blockOrder) const
256 { return data[(k << blockOrder << blockOrder) + (j << blockOrder) + i]; }
257
259 void resize(int n)
260 {
261 // First hold lock
262 boost::mutex::scoped_lock lock(ms_resizeMutex);
263 // Perform work
264 if (data) {
265 delete[] data;
266 }
267 data = new Data_T[n];
268 isAllocated = true;
269 std::fill_n(data, n, emptyValue);
270 }
271
273 void clear()
274 {
275 // First hold lock
276 boost::mutex::scoped_lock lock(ms_resizeMutex);
277 // Perform work
278 if (data) {
279 delete[] data;
280 data = NULL;
281 }
282 }
283
285 void copy(const SparseBlock &other, size_t n)
286 {
287 if (other.isAllocated) {
288 if (!data) {
289 resize(n);
290 }
291 Data_T *p = data, *end = data + n, *o = other.data;
292 while (p != end) {
293 *p++ = *o++;
294 }
295 } else {
296 clear();
297 }
298 }
299
300 // Data members --------------------------------------------------------------
301
304
309
311 Data_T *data;
312
313private:
314
319
320 // Data members --------------------------------------------------------------
321
325 static boost::mutex ms_resizeMutex;
326
327};
328
329} // namespace Sparse
330
331//----------------------------------------------------------------------------//
332// SparseField
333//----------------------------------------------------------------------------//
334
347//----------------------------------------------------------------------------//
348
349template <class Data_T>
351 : public ResizableField<Data_T>
352{
353public:
354
355 // Typedefs ------------------------------------------------------------------
356
357 typedef boost::intrusive_ptr<SparseField> Ptr;
358 typedef std::vector<Ptr> Vec;
359
362
363 // RTTI replacement ----------------------------------------------------------
364
367
368 static const char *staticClassName()
369 {
370 return "SparseField";
371 }
372
373 static const char *staticClassType()
374 {
376 }
377
378 // Constructors --------------------------------------------------------------
379
382
384 SparseField();
385
387 SparseField(const SparseField &o);
388
390 ~SparseField();
391
395
396 // \}
397
398 // Main methods --------------------------------------------------------------
399
401 virtual void clear(const Data_T &value);
402
405 void setBlockOrder(int order);
406
408 int blockOrder() const;
409
411 int blockSize() const;
412
414 bool voxelIsInAllocatedBlock(int i, int j, int k) const;
415
417 bool blockIsAllocated(int bi, int bj, int bk) const;
418
421 const Data_T getBlockEmptyValue(int bi, int bj, int bk) const;
422
425 void setBlockEmptyValue(int bi, int bj, int bk, const Data_T &val);
426
428 bool blockIndexIsValid(int bi, int bj, int bk) const;
429
431 V3i blockRes() const;
432
438 template <typename Functor_T>
439 int releaseBlocks(Functor_T func);
440
442 int blockId(int blockI, int blockJ, int blockK) const;
443
447 void getBlockCoord(int i, int j, int k, int &bi, int &bj, int &bk) const;
448
452 void getVoxelInBlock(int i, int j, int k, int &vi, int &vj, int &vk) const;
453
455 void applyDataWindowOffset(int &i, int &j, int &k) const
456 {
457 i -= base::m_dataWindow.min.x;
458 j -= base::m_dataWindow.min.y;
459 k -= base::m_dataWindow.min.z;
460 }
461
463 bool isDynamicLoad() const
464 { return m_fileManager != NULL; }
465
467 void incBlockRef(const int blockId) const;
468
470 void activateBlock(const int blockId) const;
471
473 void decBlockRef(const int blockId) const;
474
475 // Threading-related ---------------------------------------------------------
476
478 size_t numGrains() const;
481 bool getGrainBounds(const size_t idx, Box3i &vsBounds) const;
482
483 // From Field base class -----------------------------------------------------
484
487 virtual Data_T value(int i, int j, int k) const;
488 virtual long long int memSize() const;
489 virtual size_t voxelCount() const;
491
492 // From WritableField base class ---------------------------------------------
493
496 virtual Data_T& lvalue(int i, int j, int k);
498
499 // Concrete voxel access -----------------------------------------------------
500
502 Data_T fastValue(int i, int j, int k) const;
504 Data_T& fastLValue(int i, int j, int k);
505
508 Data_T* blockData(int bi, int bj, int bk) const;
509
510 // From FieldBase ------------------------------------------------------------
511
514
516
517 virtual FieldBase::Ptr clone() const
518 { return Ptr(new SparseField(*this)); }
519
521
522 // Iterators -----------------------------------------------------------------
523
526
528 class const_iterator;
529
531 const_iterator cbegin() const;
533 const_iterator cbegin(const Box3i &subset) const;
535 const_iterator cend() const;
538 const_iterator cend(const Box3i &subset) const;
539
543 class iterator;
544
546 iterator begin();
548 iterator begin(const Box3i &subset);
550 iterator end();
553 iterator end(const Box3i &subset);
554
558 class block_iterator;
559
560 block_iterator blockBegin() const;
562 block_iterator blockEnd() const;
563
565
566 // Internal utility functions ------------------------------------------------
567
570 void addReference(const std::string &filename, const std::string &layerPath,
571 int valuesPerBlock, int numVoxels, int occupiedBlocks);
575
576 protected:
577
578 friend class SparseFieldIO;
579
580 // Typedefs ------------------------------------------------------------------
581
584
585 // From ResizableField class -------------------------------------------------
586
587 virtual void sizeChanged()
588 {
589 // Call base class
591 setupBlocks();
592 }
593
594 // Convenience methods -------------------------------------------------------
595
598
600 void setupBlocks();
601
603 void deallocBlock(Block &block, const Data_T &emptyValue);
604
606
607 // Data members --------------------------------------------------------------
608
619
625
627 Data_T m_dummy;
628
629private:
630
631 // Static data members -------------------------------------------------------
632
634
635 // Utility methods -----------------------------------------------------------
636
639 void copySparseField(const SparseField &o);
640
644
645};
646
647//----------------------------------------------------------------------------//
648// Static member instantiations
649//----------------------------------------------------------------------------//
650
652
653namespace Sparse {
654
655template <typename Data_T>
657
658}
659
660//----------------------------------------------------------------------------//
661// Typedefs
662//----------------------------------------------------------------------------//
663
670
671//------------------------------------------------------------------------------
672// Helper functions
673//------------------------------------------------------------------------------
674
675template <typename Data_T>
676Box3i blockCoords(const Box3i &dvsBounds, const SparseField<Data_T> *f)
677{
678 // Check empty bbox input
679 if (!continuousBounds(dvsBounds).hasVolume()) {
680 return Box3i();
681 }
682 // Discrete offset voxel space
683 Box3i dovsBounds = dvsBounds;
684 f->applyDataWindowOffset(dovsBounds.min.x,
685 dovsBounds.min.y,
686 dovsBounds.min.z);
687 f->applyDataWindowOffset(dovsBounds.max.x,
688 dovsBounds.max.y,
689 dovsBounds.max.z);
690 // Discrete block space bounds
691 Box3i dbsBounds;
692 if (f) {
693 f->getBlockCoord(dovsBounds.min.x, dovsBounds.min.y, dovsBounds.min.z,
694 dbsBounds.min.x, dbsBounds.min.y, dbsBounds.min.z);
695 f->getBlockCoord(dovsBounds.max.x, dovsBounds.max.y, dovsBounds.max.z,
696 dbsBounds.max.x, dbsBounds.max.y, dbsBounds.max.z);
697 }
698 return dbsBounds;
699}
700
701//----------------------------------------------------------------------------//
702// Helper functors
703//----------------------------------------------------------------------------//
704
705namespace Sparse {
706
709template <typename Data_T>
711{
720 bool check(const SparseBlock<Data_T> &block, Data_T &retEmptyValue,
721 const V3i &validSize, const V3i &blockSize)
722 {
723 // Store first value
724 Data_T first = block.data[0];
725 // Iterate over rest
726 bool match = true;
727 size_t len = blockSize.x * blockSize.y * blockSize.z;
728 if (validSize == blockSize) {
729 // interior block so look at all voxels
730 for (size_t i = 0; i < len; i++) {
731 if (block.data[i] != first) {
732 match = false;
733 break;
734 }
735 }
736 } else {
737 // only look at valid voxels
738 int x=0, y=0, z=0;
739 for (size_t i = 0; i < len; i++, x++) {
740 if (x >= blockSize.x) {
741 x = 0;
742 ++y;
743 if (y >= blockSize.y) {
744 y = 0;
745 ++z;
746 }
747 }
748 if (x >= validSize.x || y >= validSize.y || z >= validSize.z) {
749 continue;
750 }
751 if (block.data[i] != first) {
752 match = false;
753 break;
754 }
755 }
756 } // end of interior block test
757
758 if (match) {
759 retEmptyValue = first;
760 return true;
761 } else {
762 return false;
763 }
764 }
765};
766
767//----------------------------------------------------------------------------//
768
769template <typename Data_T>
770inline bool isAnyLess(const Data_T &left, const Data_T &right)
771{
772 return (std::abs(left) < right);
773}
774
775//----------------------------------------------------------------------------//
776
777template <>
778inline bool isAnyLess(const V3h &left, const V3h &right)
779{
780 return (std::abs(left.x) < right.x ||
781 std::abs(left.y) < right.y ||
782 std::abs(left.z) < right.z );
783}
784
785//----------------------------------------------------------------------------//
786
787template <>
788inline bool isAnyLess(const V3f &left, const V3f &right)
789{
790 return (std::abs(left.x) < right.x ||
791 std::abs(left.y) < right.y ||
792 std::abs(left.z) < right.z );
793}
794
795//----------------------------------------------------------------------------//
796
797template <>
798inline bool isAnyLess(const V3d &left, const V3d &right)
799{
800 return (std::abs(left.x) < right.x ||
801 std::abs(left.y) < right.y ||
802 std::abs(left.z) < right.z );
803}
804
805//----------------------------------------------------------------------------//
806
810template <typename Data_T>
812{
814 CheckMaxAbs(Data_T maxValue)
815 : m_maxValue(maxValue)
816 { }
825 bool check(const SparseBlock<Data_T> &block, Data_T &retEmptyValue,
826 const V3i &validSize, const V3i &blockSize)
827 {
828 // Store first value
829 Data_T first = block.data[0];
830 // Iterate over rest
831 bool allGreater = true;
832 size_t len = blockSize.x * blockSize.y * blockSize.z;
833
834 if (validSize == blockSize) {
835 // interior block so look at all voxels
836 for (size_t i = 0; i < len; i++) {
837 if (isAnyLess<Data_T>(block.data[i], m_maxValue)) {
838 allGreater = false;
839 break;
840 }
841 }
842 } else {
843 // only look at valid voxels
844 int x=0, y=0, z=0;
845 for (size_t i = 0; i < len; i++, x++) {
846 if (x >= blockSize.x) {
847 x = 0;
848 ++y;
849 if (y >= blockSize.y) {
850 y = 0;
851 ++z;
852 }
853 }
854 if (x >= validSize.x || y >= validSize.y || z >= validSize.z) {
855 continue;
856 }
857 if (isAnyLess<Data_T>(block.data[i], m_maxValue)) {
858 allGreater = false;
859 break;
860 }
861 }
862 } // end of interior block test
863
864 if (allGreater) {
865 retEmptyValue = first;
866 return true;
867 } else {
868 return false;
869 }
870 }
871private:
873};
874
875//----------------------------------------------------------------------------//
876
877} // namespace Sparse
878
879//----------------------------------------------------------------------------//
880// SparseField::const_iterator
881//----------------------------------------------------------------------------//
882
884template <class Data_T>
886{
887 public:
888#if defined(WIN32) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
889 typedef std::forward_iterator_tag iterator_category;
890 typedef Data_T value_type;
891 typedef ptrdiff_t difference_type;
892 typedef ptrdiff_t distance_type;
893 typedef Data_T *pointer;
894 typedef Data_T& reference;
895#endif
896
899 const Box3i &window,
900 const V3i &currentPos, int blockOrder)
901 : x(currentPos.x), y(currentPos.y), z(currentPos.z),
902 m_p(NULL), m_blockIsActivated(false),
903 m_blockStepsTicker(0), m_blockOrder(blockOrder),
904 m_blockId(-1), m_window(window), m_field(&field)
905 {
906 m_manager = m_field->m_fileManager;
907 setupNextBlock(x, y, z);
908 }
910 if (m_manager && m_blockId >= 0 &&
911 m_blockId < static_cast<int>(m_field->m_numBlocks)) {
912 if (m_field->m_blocks[m_blockId].isAllocated)
913 m_manager->decBlockRef<Data_T>(m_field->m_fileId, m_blockId);
914 }
915 }
916 const const_iterator& operator ++ ()
917 {
918 bool resetPtr = false;
919 // Check against end of data window
920 if (x == m_window.max.x) {
921 if (y == m_window.max.y) {
922 x = m_window.min.x;
923 y = m_window.min.y;
924 ++z;
925 resetPtr = true;
926 } else {
927 x = m_window.min.x;
928 ++y;
929 resetPtr = true;
930 }
931 } else {
932 ++x;
933 }
934 // These can both safely be incremented here
935 ++m_blockStepsTicker;
936 // ... but only step forward if we're in a non-empty block
937 if (!m_isEmptyBlock && (!m_manager || m_blockIsActivated))
938 ++m_p;
939 // Check if we've reached the end of this block
940 if (m_blockStepsTicker == (1 << m_blockOrder))
941 resetPtr = true;
942 if (resetPtr) {
943 // If we have, we need to reset the current block, etc.
944 m_blockStepsTicker = 0;
945 setupNextBlock(x, y, z);
946 }
947 return *this;
948 }
949 template <class Iter_T>
950 inline bool operator == (const Iter_T &rhs) const
951 {
952 return x == rhs.x && y == rhs.y && z == rhs.z;
953 }
954 template <class Iter_T>
955 inline bool operator != (const Iter_T &rhs) const
956 {
957 return x != rhs.x || y != rhs.y || z != rhs.z;
958 }
959 inline const Data_T& operator * () const
960 {
961 if (!m_isEmptyBlock && m_manager && !m_blockIsActivated) {
962 m_manager->activateBlock<Data_T>(m_field->m_fileId, m_blockId);
963 m_blockIsActivated = true;
964 const Block &block = m_field->m_blocks[m_blockId];
965 int vi, vj, vk;
966 m_field->getVoxelInBlock(x, y, z, vi, vj, vk);
967 m_p = &block.value(vi, vj, vk, m_blockOrder);
968 }
969 return *m_p;
970 }
971 inline const Data_T* operator -> () const
972 {
973 if (!m_isEmptyBlock && m_manager && !m_blockIsActivated) {
974 SparseFileManager *manager = m_field->m_fileManager;
975 manager->activateBlock<Data_T>(m_field->m_fileId, m_blockId);
976 m_blockIsActivated = true;
977 const Block &block = m_field->m_blocks[m_blockId];
978 int vi, vj, vk;
979 m_field->getVoxelInBlock(x, y, z, vi, vj, vk);
980 m_p = &block.value(vi, vj, vk, m_blockOrder);
981 }
982 return m_p;
983 }
984
985 // Public data members -------------------------------------------------------
986
988 int x, y, z;
989
990private:
991
992 // Typedefs ------------------------------------------------------------------
993
995
996 // Convenience methods -------------------------------------------------------
997
998 void setupNextBlock(int i, int j, int k)
999 {
1000 m_field->applyDataWindowOffset(i, j, k);
1001 m_field->getBlockCoord(i, j, k, m_blockI, m_blockJ, m_blockK);
1002 int oldBlockId = m_blockId;
1003 m_blockId = m_field->blockId(m_blockI, m_blockJ, m_blockK);
1004 if (m_manager && oldBlockId != m_blockId &&
1005 oldBlockId >= 0 &&
1006 oldBlockId < static_cast<int>(m_field->m_numBlocks) &&
1007 m_field->m_blocks[oldBlockId].isAllocated) {
1008 m_manager->decBlockRef<Data_T>(m_field->m_fileId, oldBlockId);
1009 }
1010 if (m_blockId >= m_field->m_blockXYSize * m_field->m_blockRes.z) {
1011 m_isEmptyBlock = true;
1012 return;
1013 }
1014
1015 const Block &block = m_field->m_blocks[m_blockId];
1016 int vi, vj, vk;
1017 m_field->getVoxelInBlock(i, j, k, vi, vj, vk);
1018 m_blockStepsTicker = vi;
1019 if (block.isAllocated) {
1020 if (m_manager && oldBlockId != m_blockId && m_blockId >= 0) {
1021 m_manager->incBlockRef<Data_T>(m_field->m_fileId, m_blockId);
1022 // this is a managed field, so the block may not be loaded
1023 // yet, so don't bother setting m_p yet (it'll get set in the
1024 // * and -> operators when the block is activated)
1025 } else {
1026 // only set m_p to the voxel's address if this is not a
1027 // managed field, i.e., if the data is already in memory.
1028 m_p = &block.value(vi, vj, vk, m_blockOrder);
1029 }
1030 m_isEmptyBlock = false;
1031 } else {
1032 m_p = &block.emptyValue;
1033 m_isEmptyBlock = true;
1034 }
1035 if (m_field->m_fileManager) {
1036 m_blockIsActivated = false;
1037 }
1038 }
1039
1041 mutable const Data_T *m_p;
1052 int m_blockI, m_blockJ, m_blockK, m_blockId;
1059};
1060
1061//----------------------------------------------------------------------------//
1062// SparseField::iterator
1063//----------------------------------------------------------------------------/
1064
1066template <class Data_T>
1067class SparseField<Data_T>::iterator
1068{
1069 public:
1070#if defined(WIN32) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
1071 typedef std::forward_iterator_tag iterator_category;
1072 typedef Data_T value_type;
1073 typedef ptrdiff_t difference_type;
1074 typedef ptrdiff_t distance_type;
1075 typedef Data_T *pointer;
1076 typedef Data_T& reference;
1077#endif
1078
1081 const Box3i &window,
1082 const V3i &currentPos, int blockOrder)
1083 : x(currentPos.x), y(currentPos.y), z(currentPos.z),
1084 m_p(NULL), m_blockStepsTicker(0), m_blockOrder(blockOrder),
1085 m_blockId(-1), m_window(window), m_field(&field)
1086 {
1087 setupNextBlock(x, y, z);
1088 }
1089 const iterator& operator ++ ()
1090 {
1091 bool resetPtr = false;
1092 // Check against end of data window
1093 if (x == m_window.max.x) {
1094 if (y == m_window.max.y) {
1095 x = m_window.min.x;
1096 y = m_window.min.y;
1097 ++z;
1098 resetPtr = true;
1099 } else {
1100 x = m_window.min.x;
1101 ++y;
1102 resetPtr = true;
1103 }
1104 } else {
1105 ++x;
1106 }
1107 // These can both safely be incremented here
1108 ++m_blockStepsTicker;
1109 // ... but only step forward if we're in a non-empty block
1110 if (!m_isEmptyBlock)
1111 ++m_p;
1112 // Check if we've reached the end of this block
1113 if (m_blockStepsTicker == (1 << m_blockOrder))
1114 resetPtr = true;
1115 if (resetPtr) {
1116 // If we have, we need to reset the current block, etc.
1117 m_blockStepsTicker = 0;
1118 setupNextBlock(x, y, z);
1119 }
1120 return *this;
1121 }
1122 inline bool operator == (const iterator &rhs) const
1123 {
1124 return x == rhs.x && y == rhs.y && z == rhs.z;
1125 }
1126 inline bool operator != (const iterator &rhs) const
1127 {
1128 return x != rhs.x || y != rhs.y || z != rhs.z;
1129 }
1130 inline Data_T& operator * ()
1131 {
1132 if (m_field->m_fileManager) {
1133 assert(false && "Dereferencing iterator on a dynamic-read sparse field");
1134 Msg::print(Msg::SevWarning, "Dereferencing iterator on a dynamic-read "
1135 "sparse field");
1136 return *m_p;
1137 }
1138 // If the block is currently empty, we must allocate it
1139 if (m_isEmptyBlock) {
1140 // Touch the voxel to allocate the block
1141 m_field->lvalue(x, y, z);
1142 // Set up the block again
1143 setupNextBlock(x, y, z);
1144 }
1145 return *m_p;
1146 }
1147 inline Data_T* operator -> ()
1148 {
1149 if (m_field->m_fileManager) {
1150 assert(false && "Dereferencing iterator on a dynamic-read sparse field");
1151 Msg::print(Msg::SevWarning, "Dereferencing iterator on a dynamic-read "
1152 "sparse field");
1153 return m_p;
1154 }
1155 // If the block is currently empty, we must allocate it
1156 if (m_isEmptyBlock) {
1157 // Touch the voxel to allocate the block
1158 m_field->lvalue(x, y, z);
1159 // Set up the block again
1160 setupNextBlock(x, y, z);
1161 }
1162 return m_p;
1163 }
1164 // Public data members
1165 int x, y, z;
1166private:
1169 void setupNextBlock(int i, int j, int k)
1170 {
1171 m_field->applyDataWindowOffset(i, j, k);
1172 m_field->getBlockCoord(i, j, k, m_blockI, m_blockJ, m_blockK);
1173 m_blockId = m_field->blockId(m_blockI, m_blockJ, m_blockK);
1174 if (m_blockId >= m_field->m_blockXYSize * m_field->m_blockRes.z) {
1175 m_isEmptyBlock = true;
1176 return;
1177 }
1178 Block &block = m_field->m_blocks[m_blockId];
1179 int vi, vj, vk;
1180 m_field->getVoxelInBlock(i, j, k, vi, vj, vk);
1181 m_blockStepsTicker = vi;
1182 if (block.isAllocated) {
1183 m_p = &block.value(vi, vj, vk, m_blockOrder);
1184 m_isEmptyBlock = false;
1185 } else {
1186 m_p = &block.emptyValue;
1187 m_isEmptyBlock = true;
1188 }
1189 }
1191 Data_T *m_p;
1199 int m_blockI, m_blockJ, m_blockK, m_blockId;
1204};
1205
1206//----------------------------------------------------------------------------//
1207// SparseField::block_iterator
1208//----------------------------------------------------------------------------/
1209
1212template <class Data_T>
1214{
1215 public:
1219 block_iterator(const class_type &field, const Box3i &window,
1220 const V3i &currentPos)
1221 : x(currentPos.x), y(currentPos.y), z(currentPos.z),
1222 m_window(window), m_field(field)
1223 {
1224 recomputeBlockBoundingBox();
1225 }
1227 const block_iterator& operator ++ ()
1228 {
1229 if (x == m_window.max.x) {
1230 if (y == m_window.max.y) {
1231 x = m_window.min.x;
1232 y = m_window.min.y;
1233 ++z;
1234 } else {
1235 x = m_window.min.x;
1236 ++y;
1237 }
1238 } else {
1239 ++x;
1240 }
1241 recomputeBlockBoundingBox();
1242 return *this;
1243 }
1245 inline bool operator == (const block_iterator &rhs) const
1246 {
1247 return x == rhs.x && y == rhs.y && z == rhs.z;
1248 }
1250 inline bool operator != (const block_iterator &rhs) const
1251 {
1252 return x != rhs.x || y != rhs.y || z != rhs.z;
1253 }
1256 {
1257 return m_currentBlockWindow;
1258 }
1260 int x, y, z;
1261private:
1263 {
1264 Box3i box;
1265 int blockSize = m_field.blockSize();
1266 box.min = V3i(x * blockSize, y * blockSize, z * blockSize);
1267 box.max = box.min + V3i(blockSize - 1, blockSize - 1, blockSize - 1);
1268 // Clamp the box
1269 box.min = FIELD3D_CLIP(box.min, m_field.dataWindow());
1270 box.max = FIELD3D_CLIP(box.max, m_field.dataWindow());
1271 // Set the member variable
1272 m_currentBlockWindow = box;
1273 }
1280};
1281
1282//----------------------------------------------------------------------------//
1283// SparseField implementations
1284//----------------------------------------------------------------------------//
1285
1286template <class Data_T>
1288 : base(),
1289 m_blockOrder(BLOCK_ORDER),
1290 m_blocks(NULL),
1291 m_fileManager(NULL)
1292{
1293 setupBlocks();
1294}
1295
1296//----------------------------------------------------------------------------//
1297
1298template <class Data_T>
1300 : base(o),
1301 m_blockOrder(o.m_blockOrder),
1302 m_blocks(NULL),
1303 m_fileManager(o.m_fileManager)
1304{
1305 copySparseField(o);
1306}
1307
1308//----------------------------------------------------------------------------//
1309
1310template <class Data_T>
1312{
1313 if (m_fileManager) {
1314 // this file is dynamically managed, so we need to ensure the
1315 // cache doesn't point to this field's blocks because they are
1316 // about to be deleted
1317 m_fileManager->removeFieldFromCache<Data_T>(m_fileId);
1318 }
1319 if (m_blocks) {
1320 delete[] m_blocks;
1321 }
1322}
1323
1324//----------------------------------------------------------------------------//
1325
1326template <class Data_T>
1329{
1330 if (this != &o) {
1331 this->base::operator=(o);
1332 copySparseField(o);
1333 }
1334 return *this;
1335}
1336
1337//----------------------------------------------------------------------------//
1338
1339template <class Data_T>
1340void
1342{
1343 m_blockOrder = o.m_blockOrder;
1344 if (o.m_fileManager) {
1345 // allocate m_blocks, sets m_blockRes, m_blockXYSize, m_blocks
1346 setupBlocks();
1347 m_fileManager = o.m_fileManager;
1348 SparseFile::Reference<Data_T> *oldReference =
1349 m_fileManager->reference<Data_T>(o.m_fileId);
1350 addReference(oldReference->filename, oldReference->layerPath,
1351 oldReference->valuesPerBlock,
1352 oldReference->numVoxels,
1353 oldReference->occupiedBlocks);
1354 copyBlockStates(o);
1355 setupReferenceBlocks();
1356 } else {
1357 // directly copy all values and blocks from the source, no extra setup
1358 m_blockRes = o.m_blockRes;
1359 m_blockXYSize = o.m_blockXYSize;
1360 if (m_blocks) {
1361 delete[] m_blocks;
1362 }
1363 m_numBlocks = o.m_numBlocks;
1364 m_blocks = new Block[m_numBlocks];
1365 for (size_t i = 0; i < m_numBlocks; ++i) {
1366 m_blocks[i].isAllocated = o.m_blocks[i].isAllocated;
1367 m_blocks[i].emptyValue = o.m_blocks[i].emptyValue;
1368 m_blocks[i].copy(o.m_blocks[i],
1369 1 << m_blockOrder << m_blockOrder << m_blockOrder);
1370 }
1371 m_fileId = -1;
1372 m_fileManager = NULL;
1373 }
1374}
1375
1376//----------------------------------------------------------------------------//
1377
1378template <class Data_T>
1379void SparseField<Data_T>::addReference(const std::string &filename,
1380 const std::string &layerPath,
1381 int valuesPerBlock,
1382 int numVoxels,
1383 int occupiedBlocks)
1384{
1385 m_fileManager = &SparseFileManager::singleton();
1386 m_fileId = m_fileManager->getNextId<Data_T>(filename, layerPath);
1387 // Set up the manager data
1389 m_fileManager->reference<Data_T>(m_fileId);
1390 reference->valuesPerBlock = valuesPerBlock;
1391 reference->numVoxels = numVoxels;
1392 reference->occupiedBlocks = occupiedBlocks;
1393 reference->setNumBlocks(m_numBlocks);
1394}
1395
1396//----------------------------------------------------------------------------//
1397
1398template <class Data_T>
1400{
1401 if (m_numBlocks != o.m_numBlocks) return;
1402
1403 for (size_t i = 0; i < m_numBlocks; ++i) {
1404 m_blocks[i].isAllocated = o.m_blocks[i].isAllocated;
1405 m_blocks[i].emptyValue = o.m_blocks[i].emptyValue;
1406 m_blocks[i].clear();
1407 }
1408}
1409
1410//----------------------------------------------------------------------------//
1411
1412template <class Data_T>
1414{
1415 if (!m_fileManager || m_fileId < 0) return;
1416
1418 m_fileManager->reference<Data_T>(m_fileId);
1419
1420#if F3D_NO_BLOCKS_ARRAY
1421 std::vector<int>::iterator fb = reference->fileBlockIndices.begin();
1422 reference->blocks = m_blocks;
1423 int nextBlockIdx = 0;
1424 for (size_t i = 0; i < m_numBlocks; ++i, ++fb) {
1425 if (m_blocks[i].isAllocated) {
1426 *fb = nextBlockIdx;
1427 nextBlockIdx++;
1428 } else {
1429 *fb = -1;
1430 }
1431 }
1432#else
1433 std::vector<int>::iterator fb = reference->fileBlockIndices.begin();
1435 reference->blocks.begin();
1436 int nextBlockIdx = 0;
1437 for (size_t i = 0; i < m_numBlocks; ++i, ++fb, ++bp) {
1438 if (m_blocks[i].isAllocated) {
1439 *fb = nextBlockIdx;
1440 *bp = m_blocks + i;
1441 nextBlockIdx++;
1442 } else {
1443 *fb = -1;
1444 }
1445 }
1446#endif
1447}
1448
1449//----------------------------------------------------------------------------//
1450
1451template <class Data_T>
1452void SparseField<Data_T>::clear(const Data_T &value)
1453{
1454 // If we're clearing, we can get rid of all current blocks
1455 setupBlocks();
1456 Block *p = m_blocks, *end = m_blocks + m_numBlocks;
1457 while (p != end) {
1458 p->emptyValue = value;
1459 ++p;
1460 }
1461}
1462
1463//----------------------------------------------------------------------------//
1464
1465template <class Data_T>
1467{
1468 m_blockOrder = order;
1469 setupBlocks();
1470}
1471
1472//----------------------------------------------------------------------------//
1473
1474template <class Data_T>
1476{
1477 return m_blockOrder;
1478}
1479
1480//----------------------------------------------------------------------------//
1481
1482template <class Data_T>
1484{
1485 return 1 << m_blockOrder;
1486}
1487
1488//----------------------------------------------------------------------------//
1489
1490template <class Data_T>
1492{
1493 int bi, bj, bk;
1494 applyDataWindowOffset(i, j, k);
1495 getBlockCoord(i, j, k, bi, bj, bk);
1496 return blockIsAllocated(bi, bj, bk);
1497}
1498
1499//----------------------------------------------------------------------------//
1500
1501template <class Data_T>
1502bool SparseField<Data_T>::blockIsAllocated(int bi, int bj, int bk) const
1503{
1504 const Block &block = m_blocks[blockId(bi, bj, bk)];
1505 return block.isAllocated;
1506}
1507
1508//----------------------------------------------------------------------------//
1509
1510template <class Data_T>
1511const Data_T SparseField<Data_T>::getBlockEmptyValue(int bi, int bj, int bk) const
1512{
1513 return m_blocks[blockId(bi, bj, bk)].emptyValue;
1514}
1515
1516//----------------------------------------------------------------------------//
1517
1518template <class Data_T>
1520 const Data_T &val)
1521{
1522 Block &block = m_blocks[blockId(bi, bj, bk)];
1523 if (block.isAllocated) {
1524 deallocBlock(block, val);
1525 } else {
1526 block.emptyValue = val;
1527 }
1528}
1529
1530//----------------------------------------------------------------------------//
1531
1532template <class Data_T>
1533bool SparseField<Data_T>::blockIndexIsValid(int bi, int bj, int bk) const
1534{
1535 return bi >= 0 && bj >= 0 && bk >= 0 &&
1536 bi < m_blockRes.x && bj < m_blockRes.y && bk < m_blockRes.z;
1537}
1538
1539//----------------------------------------------------------------------------//
1540
1541template <class Data_T>
1543{
1544 return m_blockRes;
1545}
1546
1547//----------------------------------------------------------------------------//
1548
1549template <class Data_T>
1550template <typename Functor_T>
1552{
1553 Data_T emptyValue;
1554 int numDeallocs = 0;
1555
1556 // If the block is on the edge of the field, it may have unused
1557 // voxels, with undefined values. We need to pass the range of
1558 // valid voxels into the check function, so it only looks at valid
1559 // voxels.
1560 V3i dataRes = FieldRes::dataResolution();
1561 V3i validSize;
1562 V3i blockAllocSize(blockSize());
1563
1564 int bx = 0, by = 0, bz = 0;
1565 for (size_t i = 0; i < m_numBlocks; ++i, ++bx) {
1566 if (bx >= m_blockRes.x) {
1567 bx = 0;
1568 ++by;
1569 if (by >= m_blockRes.y) {
1570 by = 0;
1571 ++bz;
1572 }
1573 }
1574 validSize = blockAllocSize;
1575 if (bx == m_blockRes.x-1) {
1576 validSize.x = dataRes.x - bx * blockAllocSize.x;
1577 }
1578 if (by == m_blockRes.y-1) {
1579 validSize.y = dataRes.y - by * blockAllocSize.y;
1580 }
1581 if (bz == m_blockRes.z-1) {
1582 validSize.z = dataRes.z - bz * blockAllocSize.z;
1583 }
1584
1585 if (m_blocks[i].isAllocated) {
1586 if (func.check(m_blocks[i], emptyValue, validSize, blockAllocSize)) {
1587 deallocBlock(m_blocks[i], emptyValue);
1588 numDeallocs++;
1589 }
1590 }
1591 }
1592 return numDeallocs;
1593}
1594
1595//----------------------------------------------------------------------------//
1596
1597template <class Data_T>
1598Data_T SparseField<Data_T>::value(int i, int j, int k) const
1599{
1600 return fastValue(i, j, k);
1601}
1602
1603//----------------------------------------------------------------------------//
1604
1605template <class Data_T>
1606Data_T& SparseField<Data_T>::lvalue(int i, int j, int k)
1607{
1608 return fastLValue(i, j, k);
1609}
1610
1611//----------------------------------------------------------------------------//
1612
1613template <class Data_T>
1614Data_T SparseField<Data_T>::fastValue(int i, int j, int k) const
1615{
1616 assert (i >= base::m_dataWindow.min.x);
1617 assert (i <= base::m_dataWindow.max.x);
1618 assert (j >= base::m_dataWindow.min.y);
1619 assert (j <= base::m_dataWindow.max.y);
1620 assert (k >= base::m_dataWindow.min.z);
1621 assert (k <= base::m_dataWindow.max.z);
1622 // Add crop window offset
1623 applyDataWindowOffset(i, j, k);
1624 // Find block coord
1625 int bi, bj, bk;
1626 getBlockCoord(i, j, k, bi, bj, bk);
1627 // Find coord in block
1628 int vi, vj, vk;
1629 getVoxelInBlock(i, j, k, vi, vj, vk);
1630 // Get the actual block
1631 int id = blockId(bi, bj, bk);
1632 const Block &block = m_blocks[id];
1633 // Check if block data is allocated
1634 if (block.isAllocated) {
1635 if (m_fileManager) {
1636 m_fileManager->incBlockRef<Data_T>(m_fileId, id);
1637 m_fileManager->activateBlock<Data_T>(m_fileId, id);
1638 Data_T tmpValue = block.value(vi, vj, vk, m_blockOrder);
1639 m_fileManager->decBlockRef<Data_T>(m_fileId, id);
1640 return tmpValue;
1641 } else {
1642 return block.value(vi, vj, vk, m_blockOrder);
1643 }
1644 } else {
1645 return block.emptyValue;
1646 }
1647}
1648
1649//----------------------------------------------------------------------------//
1650
1652template <class Data_T>
1653Data_T& SparseField<Data_T>::fastLValue(int i, int j, int k)
1654{
1655 assert (i >= base::m_dataWindow.min.x);
1656 assert (i <= base::m_dataWindow.max.x);
1657 assert (j >= base::m_dataWindow.min.y);
1658 assert (j <= base::m_dataWindow.max.y);
1659 assert (k >= base::m_dataWindow.min.z);
1660 assert (k <= base::m_dataWindow.max.z);
1661
1662 if (m_fileManager) {
1663 assert(false && "Called fastLValue() on a dynamic-read sparse field");
1664 Msg::print(Msg::SevWarning, "Called fastLValue() on a dynamic-read "
1665 "sparse field");
1666 return m_dummy;
1667 }
1668
1669 // Add crop window offset
1670 applyDataWindowOffset(i, j, k);
1671 // Find block coord
1672 int bi, bj, bk;
1673 getBlockCoord(i, j, k, bi, bj, bk);
1674 // Find coord in block
1675 int vi, vj, vk;
1676 getVoxelInBlock(i, j, k, vi, vj, vk);
1677 // Get the actual block
1678 int id = blockId(bi, bj, bk);
1679 Block &block = m_blocks[id];
1680 // If block is allocated, return a reference to the data
1681 if (block.isAllocated) {
1682 return block.value(vi, vj, vk, m_blockOrder);
1683 } else {
1684 // ... Otherwise, allocate block
1685 size_t blockSize = 1 << m_blockOrder << m_blockOrder << m_blockOrder;
1686 block.resize(blockSize);
1687 return block.value(vi, vj, vk, m_blockOrder);
1688 }
1689}
1690
1691//----------------------------------------------------------------------------//
1692
1693template <class Data_T>
1694Data_T* SparseField<Data_T>::blockData(int bi, int bj, int bk) const
1695{
1696 int id = blockId(bi, bj, bk);
1697 const Block &block = m_blocks[id];
1698 if (block.isAllocated) {
1699 return block.data;
1700 } else {
1701 return NULL;
1702 }
1703}
1704
1705//----------------------------------------------------------------------------//
1706
1707template <class Data_T>
1708long long int SparseField<Data_T>::memSize() const
1709{
1710 long long int blockSize = m_numBlocks * sizeof(Block);
1711 long long int dataSize = 0;
1712
1713 for (size_t i = 0; i < m_numBlocks; ++i) {
1714 if (m_blocks[i].data) {
1715 dataSize += (1 << m_blockOrder << m_blockOrder << m_blockOrder) *
1716 sizeof(Data_T);
1717 }
1718 }
1719
1720 return sizeof(*this) + dataSize + blockSize;
1721}
1722
1723//----------------------------------------------------------------------------//
1724
1725template <class Data_T>
1727{
1728 size_t count = 0;
1729 const size_t blockSize = (1 << m_blockOrder << m_blockOrder << m_blockOrder);
1730
1731 for (size_t i = 0; i < m_numBlocks; ++i) {
1732 if (m_blocks[i].isAllocated) {
1733 count += blockSize;
1734 }
1735 }
1736
1737 return count;
1738}
1739
1740//----------------------------------------------------------------------------//
1741
1742template <class Data_T>
1745{
1746 if (FieldRes::dataResolution() == V3i(0))
1747 return cend();
1748 return const_iterator(*this, base::m_dataWindow, base::m_dataWindow.min,
1749 m_blockOrder);
1750}
1751
1752//----------------------------------------------------------------------------//
1753
1754template <class Data_T>
1757{
1758 if (subset.isEmpty())
1759 return cend(subset);
1760 return const_iterator(*this, subset, subset.min, m_blockOrder);
1761}
1762
1763//----------------------------------------------------------------------------//
1764
1765template <class Data_T>
1768{
1769 return const_iterator(*this, base::m_dataWindow,
1770 V3i(base::m_dataWindow.min.x,
1771 base::m_dataWindow.min.y,
1772 base::m_dataWindow.max.z + 1),
1773 m_blockOrder);
1774}
1775
1776//----------------------------------------------------------------------------//
1777
1778template <class Data_T>
1781{
1782 return const_iterator(*this, subset,
1783 V3i(subset.min.x,
1784 subset.min.y,
1785 subset.max.z + 1), m_blockOrder);
1786}
1787
1788//----------------------------------------------------------------------------//
1789
1790template <class Data_T>
1793{
1794 if (FieldRes::dataResolution() == V3i(0))
1795 return end();
1796 return iterator(*this, base::m_dataWindow,
1797 base::m_dataWindow.min, m_blockOrder); }
1798
1799//----------------------------------------------------------------------------//
1800
1801template <class Data_T>
1804{
1805 if (subset.isEmpty())
1806 return end(subset);
1807 return iterator(*this, subset, subset.min, m_blockOrder);
1808}
1809
1810//----------------------------------------------------------------------------//
1811
1812template <class Data_T>
1815{
1816 return iterator(*this, base::m_dataWindow,
1817 V3i(base::m_dataWindow.min.x,
1818 base::m_dataWindow.min.y,
1819 base::m_dataWindow.max.z + 1), m_blockOrder);
1820}
1821
1822//----------------------------------------------------------------------------//
1823
1824template <class Data_T>
1827{
1828 return iterator(*this, subset,
1829 V3i(subset.min.x, subset.min.y, subset.max.z + 1),
1830 m_blockOrder);
1831}
1832
1833//----------------------------------------------------------------------------//
1834
1835template <class Data_T>
1838{
1839 if (FieldRes::dataResolution() == V3i(0))
1840 return blockEnd();
1841 return block_iterator(*this, Box3i(V3i(0), m_blockRes - V3i(1)),
1842 V3i(0));
1843}
1844
1845//----------------------------------------------------------------------------//
1846
1847template <class Data_T>
1850{
1851 return block_iterator(*this, Box3i(V3i(0), m_blockRes - V3i(1)),
1852 V3i(0, 0, m_blockRes.z));
1853}
1854
1855//----------------------------------------------------------------------------//
1856
1857template <class Data_T>
1859{
1860 // Do calculation in floating point so we can round up later
1861 V3f res(base::m_dataWindow.size() + V3i(1));
1862 V3f blockRes(res / (1 << m_blockOrder));
1863 blockRes.x = ceil(blockRes.x);
1864 blockRes.y = ceil(blockRes.y);
1865 blockRes.z = ceil(blockRes.z);
1866 V3i intBlockRes(static_cast<int>(blockRes.x),
1867 static_cast<int>(blockRes.y),
1868 static_cast<int>(blockRes.z));
1869 m_blockRes = intBlockRes;
1870 m_blockXYSize = m_blockRes.x * m_blockRes.y;
1871 if (m_blocks) {
1872 delete[] m_blocks;
1873 }
1874 m_numBlocks = intBlockRes.x * intBlockRes.y * intBlockRes.z;
1875 m_blocks = new Block[m_numBlocks];
1876}
1877
1878//----------------------------------------------------------------------------//
1879
1880template <class Data_T>
1881int SparseField<Data_T>::blockId(int blockI, int blockJ, int blockK) const
1882{
1883 return blockK * m_blockXYSize + blockJ * m_blockRes.x + blockI;
1884}
1885
1886//----------------------------------------------------------------------------//
1887
1889template <class Data_T>
1890void SparseField<Data_T>::getBlockCoord(int i, int j, int k,
1891 int &bi, int &bj, int &bk) const
1892{
1893 assert(i >= 0);
1894 assert(j >= 0);
1895 assert(k >= 0);
1896 bi = i >> m_blockOrder;
1897 bj = j >> m_blockOrder;
1898 bk = k >> m_blockOrder;
1899}
1900
1901//----------------------------------------------------------------------------//
1902
1904template <class Data_T>
1906 int &vi, int &vj, int &vk) const
1907{
1908 assert(i >= 0);
1909 assert(j >= 0);
1910 assert(k >= 0);
1911 vi = i & ((1 << m_blockOrder) - 1);
1912 vj = j & ((1 << m_blockOrder) - 1);
1913 vk = k & ((1 << m_blockOrder) - 1);
1914}
1915
1916//----------------------------------------------------------------------------//
1917
1918template <class Data_T>
1919void SparseField<Data_T>::incBlockRef(const int blockId) const
1920{
1921 m_fileManager->incBlockRef<Data_T>(m_fileId, blockId);
1922}
1923
1924//----------------------------------------------------------------------------//
1925
1926template <class Data_T>
1927void SparseField<Data_T>::activateBlock(const int blockId) const
1928{
1929 m_fileManager->activateBlock<Data_T>(m_fileId, blockId);
1930}
1931
1932//----------------------------------------------------------------------------//
1933
1934template <class Data_T>
1935void SparseField<Data_T>::decBlockRef(const int blockId) const
1936{
1937 m_fileManager->decBlockRef<Data_T>(m_fileId, blockId);
1938}
1939
1940//----------------------------------------------------------------------------//
1941
1942template <class Data_T>
1944{
1945 return m_numBlocks;
1946}
1947
1948//----------------------------------------------------------------------------//
1949
1950template <class Data_T>
1951bool SparseField<Data_T>::getGrainBounds(const size_t idx, Box3i &bounds) const
1952{
1953 // Block size
1954 const size_t blockSide = (1 << m_blockOrder);
1955 // Block coordinate
1956 const V3i bCoord = indexToCoord(idx, m_blockRes);
1957 // Block bbox
1958 const V3i start(bCoord * blockSide + base::m_dataWindow.min);
1959 const V3i end (start + Imath::V3i(blockSide - 1));
1960 // Bounds must be clipped against data window
1961 const Box3i unclipped(start, end);
1962 bounds = clipBounds(unclipped, base::m_dataWindow);
1963 // Whether it's a contiguous block
1964 return bounds == unclipped;
1965}
1966
1967//----------------------------------------------------------------------------//
1968
1969template <class Data_T>
1970void SparseField<Data_T>::deallocBlock(Block &block, const Data_T &emptyValue)
1971{
1972 block.isAllocated = false;
1974 block.clear();
1975 block.emptyValue = emptyValue;
1976}
1977
1978//----------------------------------------------------------------------------//
1979
1981
1982//----------------------------------------------------------------------------//
1983
1984#endif // Include guard
FIELD3D_VEC3_T< T > operator*(S s, const FIELD3D_VEC3_T< T > vec)
Scalar times Vec3 multiplication. Makes the interpolation calls cleaner.
Contains Field, WritableField and ResizableField classes.
Box3d continuousBounds(const Box3i &bbox)
Definition Field.h:1111
Box3i clipBounds(const Box3i &bbox, const Box3i &bounds)
Definition Field.h:1145
#define FIELD3D_CLASSTYPE_TEMPL_INSTANTIATION(field)
Definition Field.h:479
V3i indexToCoord(const size_t idx, const V3i &res)
Definition Field.h:1187
bool match(const std::string &name, const std::string &attribute, const std::vector< std::string > &patterns, const MatchFlags flags=MatchEmptyPattern)
Matches a <name>:<attribute> string against a set of patterns.
SparseField< V3h > SparseField3h
SparseField< V3d > SparseField3d
SparseField< float > SparseFieldf
SparseField< half > SparseFieldh
SparseField< V3f > SparseField3f
Box3i blockCoords(const Box3i &dvsBounds, const SparseField< Data_T > *f)
#define BLOCK_ORDER
Definition SparseField.h:57
SparseField< double > SparseFieldd
Contains functions controlling the loading of sparse fields.
Imath::V3i V3i
Definition SpiMathLib.h:71
Imath::V3d V3d
Definition SpiMathLib.h:74
#define FIELD3D_VEC3_T
Definition SpiMathLib.h:88
Imath::Box3i Box3i
Definition SpiMathLib.h:77
Imath::Vec3< half > V3h
Definition SpiMathLib.h:72
Imath::V3f V3f
Definition SpiMathLib.h:73
#define FIELD3D_CLIP
Definition SpiMathLib.h:90
boost::intrusive_ptr< FieldBase > Ptr
Definition Field.h:97
std::string name
Optional name of the field.
Definition Field.h:171
V3i const dataResolution() const
Definition Field.h:256
Box3i m_dataWindow
Defines the area where data is allocated. This should be treated as a closed (i.e....
Definition Field.h:310
const Box3i & dataWindow() const
Returns the data window. Any coordinate inside this window is safe to pass to value() in the Field su...
Definition Field.h:253
Data_T value_type
Allows us to reference the template class.
Definition Field.h:398
LinearSparseFieldInterp class_type
Definition SparseField.h:97
boost::intrusive_ptr< LinearSparseFieldInterp > Ptr
Definition SparseField.h:93
value_type sample(const SparseField< Data_T > &field, const V3d &vsP) const
static const char * staticClassType()
static TemplatedFieldType< LinearSparseFieldInterp< Data_T > > ms_classType
RefBase base
Convenience typedef for referring to base class.
static const char * staticClassName()
virtual void sizeChanged()
Subclasses should re-implement this if they need to perform memory allocations, etc....
Definition Field.h:901
const class_type & m_field
Pointer to field we're traversing.
SparseField< Data_T > class_type
Convenience typedef.
Box3i m_window
Bounding box for block indices.
int x
Current block index.
const Box3i & blockBoundingBox()
Returns a reference to the bounding box representing the current block.
Box3i m_currentBlockWindow
Bounding box in voxel coordinates for the current block.
block_iterator(const class_type &field, const Box3i &window, const V3i &currentPos)
Constructor.
bool m_blockIsActivated
Used with delayed-load fields. Check if we've already activated the current blocks.
Box3i m_window
Window to traverse.
int m_blockStepsTicker
Ticker for how many more steps to take before resetting the pointer.
void setupNextBlock(int i, int j, int k)
const_iterator(const class_type &field, const Box3i &window, const V3i &currentPos, int blockOrder)
Sparse::SparseBlock< Data_T > Block
SparseFileManager * m_manager
Pointer to the singleton file manager.
bool m_isEmptyBlock
Whether we're at an empty block and we don't increment m_p.
const class_type * m_field
Reference to field we're traversing.
int x
Current x/y/z coord.
int m_blockI
Current block index.
SparseField< Data_T > class_type
const Data_T * m_p
Current pointed-to element.
int m_blockOrder
Block size.
Sparse::SparseBlock< Data_T > Block
int m_blockI
Current block index.
Box3i m_window
Window to traverse.
int m_blockStepsTicker
Ticker for how many more steps to take before resetting the pointer.
void setupNextBlock(int i, int j, int k)
Convenience.
iterator(class_type &field, const Box3i &window, const V3i &currentPos, int blockOrder)
bool m_isEmptyBlock
Whether we're at an empty block and we don't increment m_p.
SparseField< Data_T > class_type
class_type * m_field
Reference to field we're traversing.
Data_T * m_p
Current pointed-to element.
This Field subclass stores voxel data in block-allocated arrays.
bool isDynamicLoad() const
Whether the field is dynamically loaded.
SparseField< Data_T > class_type
size_t numGrains() const
Number of 'grains' to use with threaded access.
void setBlockOrder(int order)
Sets the block order (i.e. the power-of-2 to use as block size.
virtual void sizeChanged()
Subclasses should re-implement this if they need to perform memory allocations, etc....
SparseFileManager * m_fileManager
Pointer to SparseFileManager. Used when doing dynamic reading. NULL if not in use.
bool getGrainBounds(const size_t idx, Box3i &vsBounds) const
Bounding box of the given 'grain'.
iterator end()
Iterator pointing one element past the last valid one.
void setBlockEmptyValue(int bi, int bj, int bk, const Data_T &val)
Sets the constant value of an block. If the block is already allocated, it gets deallocated.
void setupBlocks()
Initializes the block structure. Will clear any existing data.
block_iterator blockEnd() const
Const iterator pointing to element one past the last valid block.
int releaseBlocks(Functor_T func)
Releases any blocks that are deemed empty. This can be used to clean up after algorithms that write "...
void applyDataWindowOffset(int &i, int &j, int &k) const
Applies data window offset.
block_iterator blockBegin() const
static const char * staticClassName()
V3i blockRes() const
Returns the resolution of the block array.
iterator begin()
Iterator to first element.
virtual void clear(const Data_T &value)
Clears all the voxels in the storage.
FIELD3D_CLASSNAME_CLASSTYPE_IMPLEMENTATION
DEFINE_FIELD_RTTI_CONCRETE_CLASS
static TemplatedFieldType< SparseField< Data_T > > ms_classType
Block * m_blocks
Array of blocks. Not using std::vector since SparseBlock is noncopyable.
virtual Data_T & lvalue(int i, int j, int k)
Write access to a voxel. The coordinates are global coordinates.
const Data_T getBlockEmptyValue(int bi, int bj, int bk) const
Returns the constant value of an block, whether it's allocated already or not..
Data_T * blockData(int bi, int bj, int bk) const
Returns a pointer to the data in a block, or null if the given block is unallocated.
LinearSparseFieldInterp< Data_T > LinearInterp
int m_blockXYSize
Block array res.x * res.y.
bool blockIndexIsValid(int bi, int bj, int bk) const
Returns whether a block index is valid.
int m_fileId
File id. Used with m_fileManager if active. Otherwise -1.
void addReference(const std::string &filename, const std::string &layerPath, int valuesPerBlock, int numVoxels, int occupiedBlocks)
Internal function to create a Reference for the current field, for use in dynamic reading.
bool blockIsAllocated(int bi, int bj, int bk) const
Checks if a block is allocated.
void decBlockRef(const int blockId) const
Decrements the block ref count for the given block.
void deallocBlock(Block &block, const Data_T &emptyValue)
Deallocated the data of the given block and sets its empty value.
static const char * staticClassType()
Data_T m_dummy
Dummy value used when needing to return but indicating a failed call.
~SparseField()
Destructor.
SparseField()
Constructs an empty buffer.
size_t m_numBlocks
Number of blocks in field.
Data_T fastValue(int i, int j, int k) const
Read access to voxel. Notice that this is non-virtual.
bool voxelIsInAllocatedBlock(int i, int j, int k) const
Checks if a voxel is in an allocated block.
friend class SparseFieldIO
void activateBlock(const int blockId) const
Activates a given block.
std::vector< Ptr > Vec
Data_T & fastLValue(int i, int j, int k)
Write access to voxel. Notice that this is non-virtual.
int m_blockOrder
Block order (size = 2^blockOrder)
Sparse::SparseBlock< Data_T > Block
const_iterator cend() const
Const iterator pointing one element past the last valid one.
virtual FieldBase::Ptr clone() const
Returns a pointer to a copy of the field, pure virtual so ensure derived classes properly implement i...
virtual long long int memSize() const
Returns the memory usage (in bytes)
SparseField & operator=(const SparseField &o)
Assignment operator. For cache-managed fields, it creates a new file reference, and for non-managed f...
int blockSize() const
Returns the block size.
int blockOrder() const
Returns the block order.
void getVoxelInBlock(int i, int j, int k, int &vi, int &vj, int &vk) const
Calculates the coordinates in a block for the given voxel index.
CubicGenericFieldInterp< SparseField< Data_T > > CubicInterp
void setupReferenceBlocks()
Internal function to setup the Reference's block pointers, for use with dynamic reading.
void getBlockCoord(int i, int j, int k, int &bi, int &bj, int &bk) const
Calculates the block coordinates that a given set of voxel coords are in.
V3i m_blockRes
Block array resolution.
virtual size_t voxelCount() const
Counts the number of voxels. For most fields, this is just the volume of the data window,...
ResizableField< Data_T > base
virtual Data_T value(int i, int j, int k) const
Read access to a voxel. The coordinates are in integer voxel space .
void copyBlockStates(const SparseField< Data_T > &o)
Internal function to copy empty values and allocated flags, without copying data, used when copying a...
void copySparseField(const SparseField &o)
Copies internal data, including blocks, from another SparseField, used by copy constructor and operat...
const_iterator cbegin() const
Const iterator to first element. "cbegin" matches the tr1 c++ standard.
boost::intrusive_ptr< SparseField > Ptr
int blockId(int blockI, int blockJ, int blockK) const
Calculates the block number based on a block i,j,k index.
void incBlockRef(const int blockId) const
Increments the block ref count for the given block.
void activateBlock(int fileId, int blockIdx)
Called by SparseField when it's about to read from a block. This should not be called by the user,...
static SparseFileManager & singleton()
Returns a reference to the singleton instance.
std::string layerPath
Definition SparseFile.h:128
BlockPtrs blocks
Pointers to each block. This is so we can go in and manipulate them as we please.
Definition SparseFile.h:141
std::vector< int > fileBlockIndices
Index in file for each block.
Definition SparseFile.h:135
@ SevWarning
Definition Log.h:68
FIELD3D_API void print(Severity severity, const std::string &message)
Sends the string to the assigned output, prefixing the message with the severity.
Definition Log.cpp:70
Namespace for sparse field specifics.
bool isAnyLess(const Data_T &left, const Data_T &right)
#define FIELD3D_NAMESPACE_HEADER_CLOSE
Definition ns.h:58
Checks if all the values in the SparseBlock are equal. Used by SparseField::releaseBlocks().
bool check(const SparseBlock< Data_T > &block, Data_T &retEmptyValue, const V3i &validSize, const V3i &blockSize)
Checks whether a given block can be released. It's safe to assume that the block is allocated if this...
Checks if all the absolute values in the SparseBlock are greater than some number....
bool check(const SparseBlock< Data_T > &block, Data_T &retEmptyValue, const V3i &validSize, const V3i &blockSize)
Checks whether a given block can be released. It's safe to assume that the block is allocated if this...
CheckMaxAbs(Data_T maxValue)
Constructor. Takes max value.
Storage for one individual block of a SparseField.
Definition SparseFile.h:79
bool isAllocated
Whether the block is allocated or not.
const SparseBlock & operator=(const SparseBlock &)
Non-copyable.
void copy(const SparseBlock &other, size_t n)
Copy data from another block.
SparseBlock(const SparseBlock &)
Non-copyable.
void resize(int n)
Alloc data.
void clear()
Remove data.
const Data_T & value(int i, int j, int k, int blockOrder) const
Gets the const value of a given voxel.
Data_T emptyValue
The value to use if the block isn't allocated. We allow setting this per block so that we for example...
Data_T & value(int i, int j, int k, int blockOrder)
Gets the value of a given voxel.
Data_T * data
Pointer to data. Null if block is unallocated.
static boost::mutex ms_resizeMutex
Prevents concurrent allocation of blocks. There should be little contention, and this prevents multip...
Used to return a string for the name of a templated field.
Definition Traits.h:283
const char * name()
Definition Traits.h:284