Line data Source code
1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CPCIDSK_TEX class.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2010
7 : * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, 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 *fileIn, int segmentIn,
43 0 : const char *segment_pointer )
44 : : CPCIDSKSegment( fileIn, segmentIn, 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(!IsContentSizeValid() ? -1 : // will throw exception
72 0 : static_cast<int>(GetContentSize()));
73 0 : ReadFromFile(seg_data.buffer, 0, seg_data.buffer_size);
74 :
75 0 : if(!STARTS_WITH(seg_header.buffer+160, "64R "))
76 : {
77 0 : seg_header.Put("64R ",160,8);
78 0 : loaded_ = true;
79 0 : return ;
80 : }
81 :
82 0 : int nDimension = seg_header.GetInt(160+8,8);
83 0 : if(nDimension < 1 || nDimension > MAX_DIMENSIONS)
84 : {
85 0 : std::stringstream oStream;
86 0 : oStream << "Invalid array dimension " << nDimension;
87 0 : oStream << " stored in the segment.";
88 0 : std::string oMsg = oStream.str();
89 0 : return ThrowPCIDSKException("%s", oMsg.c_str());
90 : }
91 0 : mnDimension = static_cast<unsigned char>(nDimension);
92 :
93 0 : moSizes.clear();
94 0 : for( int i = 0; i < mnDimension; i++ )
95 : {
96 0 : int nSize = seg_header.GetInt(160+24 + i*8,8);
97 0 : if(nSize < 1)
98 : {
99 0 : std::stringstream oStream;
100 0 : oStream << "Invalid size " << nSize << " for dimension " << i+1;
101 0 : std::string oMsg = oStream.str();
102 0 : return ThrowPCIDSKException("%s", oMsg.c_str());
103 : }
104 0 : moSizes.push_back( nSize );
105 : }
106 :
107 : //calculate the total number of elements in the array.
108 0 : unsigned int nElements = 1;
109 0 : for(unsigned int i=0 ; i < moSizes.size() ; i++)
110 : {
111 0 : nElements *= moSizes[i];
112 : }
113 :
114 0 : moArray.resize(nElements);
115 0 : for( unsigned int i = 0; i < nElements; i++ )
116 : {
117 0 : const double* pdValue = (const double*)seg_data.Get(i*8,8);
118 : char uValue[8];
119 0 : std::memcpy(uValue,pdValue,8);
120 0 : SwapData(uValue,8,1);
121 0 : memcpy(&moArray[i], uValue, 8);
122 : }
123 :
124 : //PCIDSK doesn't have support for headers.
125 :
126 : // We've now loaded the structure up with data. Mark it as being loaded
127 : // properly.
128 0 : loaded_ = true;
129 :
130 : }
131 :
132 : /**
133 : * Write the segment on disk
134 : */
135 0 : void CPCIDSK_ARRAY::Write(void)
136 : {
137 : //We are not writing if nothing was loaded.
138 0 : if (!loaded_) {
139 0 : return;
140 : }
141 :
142 0 : PCIDSKBuffer& seg_header = this->GetHeader();
143 0 : int nBlocks = (static_cast<int>(moArray.size())*8 + 511)/512 ;
144 0 : unsigned int nSizeBuffer = (nBlocks)*512 ;
145 : //64 values can be put into 512 bytes.
146 0 : unsigned int nRest = nBlocks*64 - static_cast<unsigned int>(moArray.size());
147 :
148 0 : seg_data.SetSize(nSizeBuffer);
149 :
150 0 : seg_header.Put("64R ",160,8);
151 0 : seg_header.Put((int)mnDimension,160+8,8);
152 :
153 0 : for( int i = 0; i < mnDimension; i++ )
154 : {
155 0 : int nSize = static_cast<int>(moSizes[i]);
156 0 : seg_header.Put(nSize,160+24 + i*8,8);
157 : }
158 :
159 0 : for( unsigned int i = 0; i < moArray.size(); i++ )
160 : {
161 0 : double dValue = moArray[i];
162 0 : SwapData(&dValue,8,1);
163 0 : seg_data.PutBin(dValue,i*8);
164 : }
165 :
166 : //set the end of the buffer to 0.
167 0 : for( unsigned int i=0 ; i < nRest ; i++)
168 : {
169 0 : seg_data.Put(0.0,(static_cast<int>(moArray.size())+i)*8,8,"%22.14f");
170 : }
171 :
172 0 : WriteToFile(seg_data.buffer,0,seg_data.buffer_size);
173 :
174 0 : mbModified = false;
175 : }
176 :
177 : /**
178 : * Synchronize the segment, if it was modified then
179 : * write it into disk.
180 : */
181 0 : void CPCIDSK_ARRAY::Synchronize()
182 : {
183 0 : if(mbModified)
184 : {
185 0 : this->Write();
186 : //write the modified header
187 0 : file->WriteToFile( header.buffer, data_offset, 1024 );
188 : }
189 0 : }
190 :
191 : /**
192 : * This function returns the number of dimension in the array.
193 : * an array segment can have minimum 1 dimension and maximum
194 : * 8 dimension.
195 : *
196 : * @return the dimension of the array in [1,8]
197 : */
198 0 : unsigned char CPCIDSK_ARRAY::GetDimensionCount() const
199 : {
200 0 : return mnDimension;
201 : }
202 :
203 : /**
204 : * This function set the dimension of the array. the dimension
205 : * must be in [1,8] or a pci::Exception is thrown.
206 : *
207 : * @param nDim number of dimension, should be in [1,8]
208 : */
209 0 : void CPCIDSK_ARRAY::SetDimensionCount(unsigned char nDim)
210 : {
211 0 : if( !file->GetUpdatable() )
212 0 : return ThrowPCIDSKException("File not open for update.");
213 0 : if(nDim < 1 || nDim > 8)
214 : {
215 0 : return ThrowPCIDSKException("An array cannot have a "
216 0 : "dimension bigger than 8 or smaller than 1.");
217 : }
218 0 : mnDimension = nDim;
219 0 : mbModified = true;
220 : }
221 :
222 : /**
223 : * Get the number of element that can be put in each of the dimension
224 : * of the array. the size of the return vector is GetDimensionCount().
225 : *
226 : * @return the size of each dimension.
227 : */
228 0 : const std::vector<unsigned int>& CPCIDSK_ARRAY::GetSizes() const
229 : {
230 0 : return moSizes;
231 : }
232 :
233 : /**
234 : * Set the size of each dimension. If the size of the array is bigger
235 : * or smaller than GetDimensionCount(), then a pci::Exception is thrown
236 : * if one of the sizes is 0, then a pci::Exception is thrown.
237 : *
238 : * @param oSizes the size of each dimension
239 : */
240 0 : void CPCIDSK_ARRAY::SetSizes(const std::vector<unsigned int>& oSizes)
241 : {
242 0 : if(oSizes.size() != GetDimensionCount())
243 : {
244 0 : return ThrowPCIDSKException("You need to specify the sizes"
245 0 : " for each dimension of the array");
246 : }
247 :
248 0 : for( unsigned int i=0 ; i < oSizes.size() ; i++)
249 : {
250 0 : if(oSizes[i] == 0)
251 : {
252 0 : return ThrowPCIDSKException("You cannot define the size of a dimension to 0.");
253 : }
254 : }
255 0 : moSizes = oSizes;
256 0 : mbModified = true;
257 : }
258 :
259 : /**
260 : * Get the array in a vector. the size of this vector is
261 : * GetSize()[0]*GetSize()[2]*...*GetSize()[GetDimensionCount()-1].
262 : * value are stored in the following order inside this vector:
263 : * ViDj = Value i of Dimension j
264 : * n = size of dimension 1
265 : * p = size of dimension 2
266 : * h = size of dimension k
267 : *
268 : * V1D1 ... VnD1 V1D2 ... VpD2 ... V1Dk ... VhDk
269 : *
270 : * @return the array.
271 : */
272 0 : const std::vector<double>& CPCIDSK_ARRAY::GetArray() const
273 : {
274 0 : return moArray;
275 : }
276 :
277 : /**
278 : * Set the array in the segment. the size of this vector is
279 : * GetSize()[0]*GetSize()[2]*...*GetSize()[GetDimensionCount()-1].
280 : * value are stored in the following order inside this vector:
281 : * ViDj = Value i of Dimension j
282 : * n = size of dimension 1
283 : * p = size of dimension 2
284 : * h = size of dimension k
285 : *
286 : * V1D1 ... VnD1 V1D2 ... VpD2 ... V1Dk ... VhDk
287 : *
288 : * If the size of oArray doesn't match the sizes and dimensions
289 : * then a pci::Exception is thrown.
290 : *
291 : * @param oArray the array.
292 : */
293 0 : void CPCIDSK_ARRAY::SetArray(const std::vector<double>& oArray)
294 : {
295 0 : if( !file->GetUpdatable() )
296 0 : return ThrowPCIDSKException("File not open for update.");
297 0 : unsigned int nLength = 1;
298 0 : for( unsigned int i=0 ; i < moSizes.size() ; i++)
299 : {
300 0 : nLength *= moSizes[i];
301 : }
302 :
303 0 : if(nLength != oArray.size())
304 : {
305 0 : return ThrowPCIDSKException("the size of this array doesn't match "
306 : "the size specified in GetSizes(). See documentation for"
307 0 : " more information.");
308 : }
309 0 : moArray = oArray;
310 0 : mbModified = true;
311 : }
312 :
313 : /**
314 : * Get the headers of this array. If no headers has be specified, then
315 : * this function return an empty vector.
316 : * the size of this vector should be equal to the size of the first dimension
317 : * returned by GetSize()[0]
318 : *
319 : * @return the headers.
320 : */
321 0 : const std::vector<std::string>& CPCIDSK_ARRAY::GetHeaders() const
322 : {
323 0 : return moHeaders;
324 : }
325 :
326 : /**
327 : * Set the headers of this array. An empty vector can be specified to clear
328 : * the headers in the segment.
329 : * the size of this vector should be equal to the size of the first dimension
330 : * returned by GetSize()[0]. If it is not the case, a pci::Exception is thrown.
331 : *
332 : * @param oHeaders the headers.
333 : */
334 0 : void CPCIDSK_ARRAY::SetHeaders(const std::vector<std::string>& oHeaders)
335 : {
336 0 : moHeaders = oHeaders;
337 0 : mbModified = true;
338 0 : }
|