1 /*
2  */
3 
4 /*
5 
6     Copyright (C) 2014 Ferrero Andrea
7 
8     This program is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21 
22  */
23 
24 /*
25 
26     These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27 
28  */
29 
30 #ifndef PF_ARRAY_2D_H
31 #define PF_ARRAY_2D_H
32 
33 #include <stdlib.h>
34 #include <string>
35 #include <iostream>
36 
37 //#define ARRAY2D_DEBUG 1
38 //#include "pixelmatrix.hh"
39 
40 namespace PF {
41 
42 
43   template<class T>
44   class Array2D
45   {
46     unsigned int width, height;
47     // Offset of the start of the image data
48     unsigned int r_offset, c_offset;
49 
50     unsigned int size_allocated;
51 
52   public:
53     T* buf;
54     T** matrix;
55     // The matrix shifted according to the configured offset
56     // The () operator uses this one to return the pixel values
57     T** matrix_shifted;
58 
59   public:
60     Array2D();
61     ~Array2D();
62 
GetWidth()63     unsigned int GetWidth() { return width; }
GetHeight()64     unsigned int GetHeight() { return height; }
GetRowOffset()65     unsigned int GetRowOffset() { return r_offset; }
GetColOffset()66     unsigned int GetColOffset() { return c_offset; }
67 
SetWidth(unsigned int w)68     void SetWidth(unsigned int w) { width = w; }
SetHeight(unsigned int h)69     void SetHeight(unsigned int h) { height = h; }
SetRowOffset(unsigned int offs)70     void SetRowOffset(unsigned int offs) { r_offset = offs; }
SetColOffset(unsigned int offs)71     void SetColOffset(unsigned int offs) { c_offset = offs; }
72 
73     bool Init(unsigned int w, unsigned int h, unsigned int r_offset, unsigned int c_offset);
74     void Resize(unsigned int width, unsigned int height);
75     void SetRowColOffset(unsigned int roffs, unsigned int coffs);
76     void SetXYOffset(unsigned int xoffs, unsigned int yoffs);
77     void Reset();
78 
GetBuffer()79     T* GetBuffer() { return buf; }
80     T& Get(unsigned int r, unsigned int c);
81     T& GetLocal(unsigned int r, unsigned int c);
82 
83     // use with indices
operator [](int r)84     T* operator[](int r) {
85       T* ptr = matrix_shifted[r] + c_offset;
86       T* ptr2 = matrix[r-r_offset];
87       //std::cout<<"r="<<r<<"  r_offset="<<r_offset<<"  ptr="<<ptr<<"  ptr2="<<ptr2<<std::endl;
88       return matrix_shifted[r];
89     }
90 
91 
92     // use as pointer to data
operator T*()93     operator T*()
94     {
95         // only if owner this will return a valid pointer
96         return buf;
97     }
98 
99 
100   };
101 
102 
103   template<class T>
Array2D()104   Array2D<T>::Array2D()
105   {
106     buf = 0;
107     matrix = 0;
108     size_allocated = 0;
109     width = height = r_offset = c_offset = 0;
110   }
111 
112 
113   template<class T>
~Array2D()114   Array2D<T>::~Array2D()
115   {
116 #ifdef ARRAY2D_DEBUG
117     std::cout<<"Array2D<T>::~Array2D(): matrix="<<(void*)matrix<<"  buf="<<(void*)buf<<std::endl;
118 #endif
119     if( matrix ) {
120       free( matrix );
121 #ifdef ARRAY2D_DEBUG
122       std::cout<<"Array2D<T>::~Array2D(): matrix deallocated"<<std::endl;
123 #endif
124     }
125     if( buf ) {
126       free( buf );
127 #ifdef ARRAY2D_DEBUG
128       std::cout<<"Array2D<T>::~Array2D(): buffer deallocated"<<std::endl;
129 #endif
130     }
131   }
132 
133 
134   template<class T>
Reset()135   void Array2D<T>::Reset()
136   {
137 #ifdef ARRAY2D_DEBUG
138     std::cout<<"Array2D<T>::~Array2D(): matrix="<<(void*)matrix<<"  buf="<<(void*)buf<<std::endl;
139 #endif
140     if( matrix ) {
141       free( matrix );
142       matrix = NULL;
143 #ifdef ARRAY2D_DEBUG
144       std::cout<<"Array2D<T>::~Array2D(): matrix deallocated"<<std::endl;
145 #endif
146     }
147     if( buf ) {
148       free( buf );
149       buf = NULL;
150 #ifdef ARRAY2D_DEBUG
151       std::cout<<"Array2D<T>::~Array2D(): buffer deallocated"<<std::endl;
152 #endif
153     }
154   }
155 
156 
157   template<class T>
Init(unsigned int w,unsigned int h,unsigned int r_offset,unsigned int c_offset)158   bool Array2D<T>::Init(unsigned int w, unsigned int h, unsigned int r_offset, unsigned int c_offset)
159   {
160     if(buf && GetWidth()==w && GetHeight()==h &&
161        r_offset == GetRowOffset() && c_offset == GetColOffset())
162       return false;
163 
164     /*
165       Main buffer initialization
166     */
167     // Step 1: check if global buffer needs to be (re)allocated
168     unsigned int offs = c_offset;
169     unsigned int size_new = sizeof(T)*w*h;
170 #ifdef ARRAY2D_DEBUG
171     std::cout<<"Array2D<T>::Init("<<w<<","<<h<<","<<r_offset<<","<<c_offset<<"): size_allocated="
172 	     <<size_allocated<<"  size_new="<<size_new<<std::endl;
173 #endif
174     if(size_new > size_allocated) {
175 #ifdef ARRAY2D_DEBUG
176       std::cout<<"Array2D<T>::Init("<<w<<","<<h<<","<<r_offset<<","<<c_offset<<"): old buf="<<buf;
177 #endif
178       //Array2DManager::Ref().Allocate(size_new);
179       buf = (T*)realloc(buf,size_new);
180       size_allocated = size_new;
181 #ifdef ARRAY2D_DEBUG
182       std::cout<<"  new buf="<<buf<<std::endl;
183 #endif
184 #ifdef ARRAY2D_DEBUG
185       std::cout<<"  reallocated buffer"<<std::endl;
186 #endif
187     }
188 
189     /*
190       Array2D initialization
191     */
192     // Step 2: check if the row vector of the pixel matrix needs to be (re)allocated
193     if(GetHeight() != h) {
194       matrix = (T**)realloc(matrix, sizeof(T*)*h*2);
195 #ifdef ARRAY2D_DEBUG
196       std::cout<<"  matrix reallocated."<<std::endl;
197 #endif
198     }
199 
200     // Step 3: check if the row pointers need to be (re)assigned
201     if(GetWidth() != w || GetHeight() != h) {
202       for(int j = 0; j < (int)h; j++) {
203 	matrix[j] = &(buf[j*w]);
204 #ifdef ARRAY2D_DEBUG
205 	//std::cout<<"  matrix["<<j<<"] = &(buf["<<j<<"*"<<w<<"])"
206 	//	       <<std::endl;
207 #endif
208       }
209     }
210 
211 
212 #ifdef ARRAY2D_DEBUG
213     std::cout<<"  r_offset="<<r_offset<<"  c_offset="<<c_offset<<std::endl;
214     std::cout<<"  GetRowOffset()="<<GetRowOffset()<<"  GetColOffset()="<<GetColOffset()<<std::endl;
215 #endif
216     // Step 4: check if the shifted matrix needs to be (re)initialized
217     if(GetHeight() != h || r_offset != GetRowOffset()) {
218       matrix_shifted = (&(matrix[h])) - r_offset;
219       //matrix_shifted = matrix - r_offset;
220 #ifdef ARRAY2D_DEBUG
221       std::cout<<"  matrix_shifted updated"<<std::endl;
222 #endif
223     }
224     if(GetHeight() != h || c_offset != GetColOffset()) {
225       for(int j = 0; j < (int)h; j++) {
226 	matrix_shifted[j+r_offset] = matrix[j] - c_offset;
227 #ifdef ARRAY2D_DEBUG
228 	//std::cout<<"  matrix_shifted["<<j+r_offset<<"] = matrix["<<j<<"-"<<c_offset<<std::endl;
229 #endif
230       }
231 #ifdef ARRAY2D_DEBUG
232       std::cout<<"  matrix_shifted rows updated"<<std::endl;
233 #endif
234     }
235 
236 
237     SetWidth(w);
238     SetHeight(h);
239     SetRowOffset(r_offset);
240     SetColOffset(c_offset);
241 #ifdef ARRAY2D_DEBUG
242     std::cout<<"Array2D initialization ended."
243 	     <<std::endl;
244 #endif
245     return true;
246   }
247 
248 
249   template<class T>
Resize(unsigned int w,unsigned int h)250   void Array2D<T>::Resize(unsigned int w, unsigned int h)
251   {
252     Init(w,h,GetRowOffset(),GetColOffset());
253   }
254 
255 
256   template<class T>
SetRowColOffset(unsigned int roffs,unsigned int coffs)257   void Array2D<T>::SetRowColOffset(unsigned int roffs, unsigned int coffs)
258   {
259     Init(GetWidth(),GetHeight(),roffs,coffs);
260   }
261 
262 
263   template<class T>
SetXYOffset(unsigned int xoffs,unsigned int yoffs)264   void Array2D<T>::SetXYOffset(unsigned int xoffs, unsigned int yoffs)
265   {
266     Init(GetWidth(),GetHeight(),yoffs,xoffs);
267   }
268 
269 
270   template<class T>
Get(unsigned int r,unsigned int c)271   T& Array2D<T>::Get(unsigned int r, unsigned int c)
272   {
273     return matrix_shifted[r][c];
274   }
275 
276 
277   template<class T>
GetLocal(unsigned int r,unsigned int c)278   T& Array2D<T>::GetLocal(unsigned int r, unsigned int c)
279   {
280     return matrix[r][c];
281   }
282 
283 
284 }
285 
286 #endif
287