1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CPCIDSK_TEX class.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2010
7 : * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
8 : *
9 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 :
28 : #include "pcidsk_exception.h"
29 : #include "segment/cpcidsk_array.h"
30 : #include "core/cpcidskfile.h"
31 : #include <cstring>
32 : #include <sstream>
33 : #include <cassert>
34 : #include "core/pcidsk_utils.h"
35 :
36 : using namespace PCIDSK;
37 :
38 : /************************************************************************/
39 : /* CPCIDSK_ARRAY() */
40 : /************************************************************************/
41 :
42 0 : CPCIDSK_ARRAY::CPCIDSK_ARRAY( PCIDSKFile *file, int segment,
43 : const char *segment_pointer )
44 : : CPCIDSKSegment( file, segment, segment_pointer ),
45 0 : loaded_(false),mbModified(false)
46 : {
47 0 : MAX_DIMENSIONS = 8;
48 0 : Load();
49 0 : }
50 :
51 : /************************************************************************/
52 : /* ~CPCIDSK_ARRAY */
53 : /************************************************************************/
54 :
55 0 : CPCIDSK_ARRAY::~CPCIDSK_ARRAY()
56 :
57 : {
58 0 : }
59 :
60 : /**
61 : * Load the contents of the segment
62 : */
63 0 : void CPCIDSK_ARRAY::Load()
64 : {
65 : // Check if we've already loaded the segment into memory
66 0 : if (loaded_) {
67 0 : return;
68 : }
69 :
70 0 : PCIDSKBuffer& seg_header = this->GetHeader();
71 0 : seg_data.SetSize(GetContentSize());
72 0 : ReadFromFile(seg_data.buffer, 0, seg_data.buffer_size);
73 :
74 0 : if(std::strncmp(seg_header.buffer+160, "64R ", 8))
75 : {
76 0 : seg_header.Put("64R ",160,8);
77 0 : loaded_ = true;
78 0 : return ;
79 : }
80 :
81 0 : int nDimension = seg_header.GetInt(160+8,8);
82 0 : if(nDimension < 1 || nDimension > MAX_DIMENSIONS)
83 : {
84 0 : std::stringstream oStream;
85 0 : oStream << "Invalid array dimension " << nDimension;
86 0 : oStream << " stored in the segment.";
87 0 : std::string oMsg = oStream.str();
88 0 : throw PCIDSKException(oMsg.c_str());
89 : }
90 0 : mnDimension = static_cast<unsigned char>(nDimension);
91 :
92 0 : moSizes.clear();
93 0 : for( int i = 0; i < mnDimension; i++ )
94 : {
95 0 : int nSize = seg_header.GetInt(160+24 + i*8,8);
96 0 : if(nSize < 1)
97 : {
98 0 : std::stringstream oStream;
99 0 : oStream << "Invalid size " << nSize << " for dimension " << i+1;
100 0 : std::string oMsg = oStream.str();
101 0 : throw PCIDSKException(oMsg.c_str());
102 : }
103 0 : moSizes.push_back( nSize );
104 : }
105 :
106 : //calculate the total number of elements in the array.
107 0 : unsigned int nElements = 1;
108 0 : for(unsigned int i=0 ; i < moSizes.size() ; i++)
109 : {
110 0 : nElements *= moSizes[i];
111 : }
112 :
113 0 : for( unsigned int i = 0; i < nElements; i++ )
114 : {
115 0 : const double* pdValue = (const double*)seg_data.Get(i*8,8);
116 : char uValue[8];
117 0 : std::memcpy(uValue,pdValue,8);
118 0 : SwapData(uValue,8,1);
119 0 : double dValue = *((double*)uValue);
120 0 : moArray.push_back(dValue);
121 : }
122 :
123 : //PCIDSK doesn't have support for headers.
124 :
125 : // We've now loaded the structure up with data. Mark it as being loaded
126 : // properly.
127 0 : loaded_ = true;
128 :
129 : }
130 :
131 : /**
132 : * Write the segment on disk
133 : */
134 0 : void CPCIDSK_ARRAY::Write(void)
135 : {
136 : //We are not writing if nothing was loaded.
137 0 : if (!loaded_) {
138 0 : return;
139 : }
140 :
141 0 : PCIDSKBuffer& seg_header = this->GetHeader();
142 0 : int nBlocks = (moArray.size()*8 + 511)/512 ;
143 0 : unsigned int nSizeBuffer = (nBlocks)*512 ;
144 : //64 values can be put into 512 bytes.
145 0 : unsigned int nRest = nBlocks*64 - moArray.size();
146 :
147 0 : seg_data.SetSize(nSizeBuffer);
148 :
149 0 : seg_header.Put("64R ",160,8);
150 0 : seg_header.Put((int)mnDimension,160+8,8);
151 :
152 0 : for( int i = 0; i < mnDimension; i++ )
153 : {
154 0 : int nSize = static_cast<int>(moSizes[i]);
155 0 : seg_header.Put(nSize,160+24 + i*8,8);
156 : }
157 :
158 0 : for( unsigned int i = 0; i < moArray.size(); i++ )
159 : {
160 0 : double dValue = moArray[i];
161 0 : SwapData(&dValue,8,1);
162 0 : seg_data.PutBin(dValue,i*8);
163 : }
164 :
165 : //set the end of the buffer to 0.
166 0 : for( unsigned int i=0 ; i < nRest ; i++)
167 : {
168 0 : seg_data.Put(0.0,(moArray.size()+i)*8,8,"%22.14f");
169 : }
170 :
171 0 : WriteToFile(seg_data.buffer,0,seg_data.buffer_size);
172 :
173 0 : mbModified = false;
174 : }
175 :
176 : /**
177 : * Synchronize the segement, if it was modified then
178 : * write it into disk.
179 : */
180 0 : void CPCIDSK_ARRAY::Synchronize()
181 : {
182 0 : if(mbModified)
183 : {
184 0 : this->Write();
185 : //write the modified header
186 0 : file->WriteToFile( header.buffer, data_offset, 1024 );
187 : }
188 0 : }
189 :
190 : /**
191 : * This function returns the number of dimension in the array.
192 : * an array segment can have minimum 1 dimension and maximum
193 : * 8 dimension.
194 : *
195 : * @return the dimension of the array in [1,8]
196 : */
197 0 : unsigned char CPCIDSK_ARRAY::GetDimensionCount() const
198 : {
199 0 : return mnDimension;
200 : }
201 :
202 : /**
203 : * This function set the dimension of the array. the dimension
204 : * must be in [1,8] or a pci::Exception is thrown.
205 : *
206 : * @param nDim number of dimension, should be in [1,8]
207 : */
208 0 : void CPCIDSK_ARRAY::SetDimensionCount(unsigned char nDim)
209 : {
210 0 : if(nDim < 1 || nDim > 8)
211 : {
212 : throw PCIDSKException("An array cannot have a "
213 0 : "dimension bigger than 8 or smaller than 1.");
214 : }
215 0 : mnDimension = nDim;
216 0 : mbModified = true;
217 0 : }
218 :
219 : /**
220 : * Get the number of element that can be put in each of the dimension
221 : * of the array. the size of the return vector is GetDimensionCount().
222 : *
223 : * @return the size of each dimension.
224 : */
225 0 : const std::vector<unsigned int>& CPCIDSK_ARRAY::GetSizes() const
226 : {
227 0 : return moSizes;
228 : }
229 :
230 : /**
231 : * Set the size of each dimension. If the size of the array is bigger
232 : * or smaller than GetDimensionCount(), then a pci::Exception is thrown
233 : * if one of the sizes is 0, then a pci::Exception is thrown.
234 : *
235 : * @param oSizes the size of each dimension
236 : */
237 0 : void CPCIDSK_ARRAY::SetSizes(const std::vector<unsigned int>& oSizes)
238 : {
239 0 : if(oSizes.size() != GetDimensionCount())
240 : {
241 : throw PCIDSKException("You need to specify the sizes"
242 0 : " for each dimension of the array");
243 : }
244 :
245 0 : for( unsigned int i=0 ; i < oSizes.size() ; i++)
246 : {
247 0 : if(oSizes[i] == 0)
248 : {
249 0 : throw PCIDSKException("You cannot define the size of a dimension to 0.");
250 : }
251 : }
252 0 : moSizes = oSizes;
253 0 : mbModified = true;
254 0 : }
255 :
256 : /**
257 : * Get the array in a vector. the size of this vector is
258 : * GetSize()[0]*GetSize()[2]*...*GetSize()[GetDimensionCount()-1].
259 : * value are stored in the following order inside this vector:
260 : * ViDj = Value i of Dimension j
261 : * n = size of dimension 1
262 : * p = size of dimension 2
263 : * h = size of dimension k
264 : *
265 : * V1D1 ... VnD1 V1D2 ... VpD2 ... V1Dk ... VhDk
266 : *
267 : * @return the array.
268 : */
269 0 : const std::vector<double>& CPCIDSK_ARRAY::GetArray() const
270 : {
271 0 : return moArray;
272 : }
273 :
274 : /**
275 : * Set the array in the segment. the size of this vector is
276 : * GetSize()[0]*GetSize()[2]*...*GetSize()[GetDimensionCount()-1].
277 : * value are stored in the following order inside this vector:
278 : * ViDj = Value i of Dimension j
279 : * n = size of dimension 1
280 : * p = size of dimension 2
281 : * h = size of dimension k
282 : *
283 : * V1D1 ... VnD1 V1D2 ... VpD2 ... V1Dk ... VhDk
284 : *
285 : * If the size of oArray doesn't match the sizes and dimensions
286 : * then a pci::Exception is thrown.
287 : *
288 : * @param oArray the array.
289 : */
290 0 : void CPCIDSK_ARRAY::SetArray(const std::vector<double>& oArray)
291 : {
292 0 : unsigned int nLength = 1;
293 0 : for( unsigned int i=0 ; i < moSizes.size() ; i++)
294 : {
295 0 : nLength *= moSizes[i];
296 : }
297 :
298 0 : if(nLength != oArray.size())
299 : {
300 : throw PCIDSKException("the size of this array doesn't match "
301 : "the size specified in GetSizes(). See documentation for"
302 0 : " more information.");
303 : }
304 0 : moArray = oArray;
305 0 : mbModified = true;
306 0 : }
307 :
308 : /**
309 : * Get the headers of this array. If no headers has be specified, then
310 : * this function return an empty vector.
311 : * the size of this vector should be equal to the size of the first dimension
312 : * returned by GetSize()[0]
313 : *
314 : * @return the headers.
315 : */
316 0 : const std::vector<std::string>& CPCIDSK_ARRAY::GetHeaders() const
317 : {
318 0 : return moHeaders;
319 : }
320 :
321 : /**
322 : * Set the headers of this array. An empty vector can be specified to clear
323 : * the headers in the segment.
324 : * the size of this vector should be equal to the size of the first dimension
325 : * returned by GetSize()[0]. If it is not the case, a pci::Exception is thrown.
326 : *
327 : * @param oHeaders the headers.
328 : */
329 0 : void CPCIDSK_ARRAY::SetHeaders(const std::vector<std::string>& oHeaders)
330 : {
331 0 : moHeaders = oHeaders;
332 0 : mbModified = true;
333 0 : }
334 :
|