1 /******************************************************************************
2  *
3  * Purpose:  Implementation of the CPCIDSKPolyModelSegment class.
4  *
5  ******************************************************************************
6  * Copyright (c) 2009
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_poly.h"
29 #include "segment/cpcidsksegment.h"
30 #include "core/pcidsk_utils.h"
31 #include "pcidsk_exception.h"
32 #include "segment/cpcidskpolymodel.h"
33 
34 #include <vector>
35 #include <string>
36 #include <cassert>
37 #include <cstring>
38 
39 using namespace PCIDSK;
40 
41 // Struct to store details of the RPC model
42 struct CPCIDSKPolyModelSegment::PCIDSKPolyInfo
43 {
44     // number of coefficients
45     unsigned int nNumCoeffs;
46 
47     // pixels in the image
48     unsigned int nPixels;
49     // lines in the image
50     unsigned int nLines;
51 
52     // Forward Coefficients (Geo2Img)
53     std::vector<double> vdfX1;
54     // Forward Coefficients (Geo2Img)
55     std::vector<double> vdfY1;
56     // Backward Coefficients Img2Geo
57     std::vector<double> vdfX2;
58     // Backward Coefficients Img2Geo
59     std::vector<double> vdfY2;
60 
61     //map units of required projection
62     std::string oMapUnit;
63     //proj param info of required projection
64     std::vector<double> oProjectionInfo;
65 
66     // The raw segment data
67     PCIDSKBuffer seg_data;
68 };
69 
70 CPCIDSKPolyModelSegment::CPCIDSKPolyModelSegment(PCIDSKFile *fileIn,
71                                                  int segmentIn,
72                                                  const char *segment_pointer) :
73     CPCIDSKSegment(fileIn, segmentIn, segment_pointer),
74     pimpl_(new CPCIDSKPolyModelSegment::PCIDSKPolyInfo),
75     loaded_(false),mbModified(false)
76 {
77     Load();
78 }
79 
80 
81 CPCIDSKPolyModelSegment::~CPCIDSKPolyModelSegment()
82 {
83     delete pimpl_;
84 }
85 
86 // Load the contents of the segment
87 void CPCIDSKPolyModelSegment::Load()
88 {
89     // Check if we've already loaded the segment into memory
90     if (loaded_) {
91         return;
92     }
93 
94     if (data_size - 1024 != 7 * 512)
95         return ThrowPCIDSKException("Corrupted poly model?");
96 
97     pimpl_->seg_data.SetSize((int)(data_size - 1024)); // should be 7 * 512
98 
99     ReadFromFile(pimpl_->seg_data.buffer, 0, data_size - 1024);
100 
101     // The Polynomial Model Segment is defined as follows:
102     // Polynomial Segment: 7 512-byte blocks
103 
104     // Block 1:
105     // Bytes   0-7: 'POLYMDL '
106     if (std::strncmp(pimpl_->seg_data.buffer, "POLYMDL ", 8))
107     {
108         pimpl_->seg_data.Put("POLYMDL ",0,8);
109         return;
110         // Something has gone terribly wrong!
111         /*throw PCIDSKException("A segment that was previously identified as an RFMODEL "
112             "segment does not contain the appropriate data. Found: [%s]",
113             std::string(pimpl_->seg_data.buffer, 8).c_str());*/
114     }
115 
116     // Block 2: number of coefficient and size
117     // Bytes   0-21: number of coefficients
118     // Bytes  22-41: number of pixels
119     // Bytes  42-61: number of lines
120     pimpl_->nNumCoeffs = pimpl_->seg_data.GetInt(512, 22);
121     pimpl_->nPixels = pimpl_->seg_data.GetInt(512 + 22, 22);
122     pimpl_->nLines = pimpl_->seg_data.GetInt(512 + 44, 22);
123 
124     int i=0;
125     // Block 3: Forward Coefficients (Geo2Img)
126     // Each coefficient take 22 Bytes
127     for(i=0 ; i < (int)pimpl_->nNumCoeffs ; i++)
128     {
129         pimpl_->vdfX1.push_back(pimpl_->seg_data.GetDouble(2*512 + (i*22), 22));
130     }
131 
132     // Block 4: Forward Coefficients (Geo2Img)
133     // Each coefficient take 22 Bytes
134     for(i=0 ; i < (int)pimpl_->nNumCoeffs ; i++)
135     {
136         pimpl_->vdfY1.push_back(pimpl_->seg_data.GetDouble(3*512 + (i*22), 22));
137     }
138 
139     // Block 5: Backward Coefficients Img2Geo
140     // Each coefficient take 22 Bytes
141     for(i=0 ; i < (int)pimpl_->nNumCoeffs ; i++)
142     {
143         pimpl_->vdfX2.push_back(pimpl_->seg_data.GetDouble(4*512 + (i*22), 22));
144     }
145 
146     // Block 6: Backward Coefficients Img2Geo
147     // Each coefficient take 22 Bytes
148     for(i=0 ; i < (int)pimpl_->nNumCoeffs ; i++)
149     {
150         pimpl_->vdfY2.push_back(pimpl_->seg_data.GetDouble(5*512 + (i*22), 22));
151     }
152 
153     // Block 7: Required projection
154     // Bytes 0-16: The map units
155     // Bytes 17-511: the proj param info.
156     pimpl_->oMapUnit = pimpl_->seg_data.Get(6*512,17);
157     for(i=0 ; i < 19 ; i++)
158     {
159         pimpl_->oProjectionInfo.push_back(pimpl_->seg_data.GetDouble(6*512+17+i*26,26));
160     }
161 
162     // We've now loaded the structure up with data. Mark it as being loaded
163     // properly.
164     loaded_ = true;
165 }
166 
167 void CPCIDSKPolyModelSegment::Write(void)
168 {
169     //We are not writing if nothing was loaded.
170     if (!loaded_) {
171         return;
172     }
173 
174     // Block 1:
175     // Bytes   0-7: 'POLYMDL  '
176     pimpl_->seg_data.Put("POLYMDL ",0,8);
177 
178     // Block 2: number of coefficient and size
179     // Bytes   0-21: number of coefficients
180     // Bytes  22-41: number of pixels
181     // Bytes  42-61: number of lines
182     pimpl_->seg_data.Put(pimpl_->nNumCoeffs,512, 22);
183     pimpl_->seg_data.Put(pimpl_->nPixels,512 + 22, 22);
184     pimpl_->seg_data.Put(pimpl_->nLines,512 + 44, 22);
185 
186     int i=0;
187     assert(pimpl_->vdfX1.size() == pimpl_->nNumCoeffs);
188     assert(pimpl_->vdfX2.size() == pimpl_->nNumCoeffs);
189     assert(pimpl_->vdfY1.size() == pimpl_->nNumCoeffs);
190     assert(pimpl_->vdfY2.size() == pimpl_->nNumCoeffs);
191     // Block 3: Forward Coefficients (Geo2Img)
192     // Each coefficient take 22 Bytes
193     for(i=0 ; i < (int)pimpl_->nNumCoeffs ; i++)
194     {
195         pimpl_->seg_data.Put(pimpl_->vdfX1[i],2*512 + (i*22), 22,"%20.14f");
196     }
197 
198     // Block 4: Forward Coefficients (Geo2Img)
199     // Each coefficient take 22 Bytes
200     for(i=0 ; i < (int)pimpl_->nNumCoeffs ; i++)
201     {
202         pimpl_->seg_data.Put(pimpl_->vdfY1[i],3*512 + (i*22), 22,"%20.14f");
203     }
204 
205     // Block 5: Forward Coefficients (Geo2Img)
206     // Each coefficient take 22 Bytes
207     for(i=0 ; i < (int)pimpl_->nNumCoeffs ; i++)
208     {
209         pimpl_->seg_data.Put(pimpl_->vdfX2[i],4*512 + (i*22), 22,"%20.14f");
210     }
211 
212     // Block 6: Forward Coefficients (Geo2Img)
213     // Each coefficient take 22 Bytes
214     for(i=0 ; i < (int)pimpl_->nNumCoeffs ; i++)
215     {
216         pimpl_->seg_data.Put(pimpl_->vdfY2[i],5*512 + (i*22), 22,"%20.14f");
217     }
218 
219     assert(pimpl_->oMapUnit.size() <= 17);
220     assert(pimpl_->oProjectionInfo.size() <= 512-17-1);
221     // Block 7: Required projection
222     // Bytes 0-16: The map units
223     // Bytes 17-511: the proj param info.
224     pimpl_->seg_data.Put("                 \0",6*512,17);
225     pimpl_->seg_data.Put(pimpl_->oMapUnit.c_str(),6*512,(int)pimpl_->oMapUnit.size());
226     //19 because (511-17)/26 = 19 (26 is the size of one value)
227     for(i=0 ; i < 19 ; i++)
228     {
229         pimpl_->seg_data.Put(pimpl_->oProjectionInfo[i],6*512+17+(i*26),26,"%20.14f");
230     }
231 
232     WriteToFile(pimpl_->seg_data.buffer,0,data_size-1024);
233     mbModified = false;
234 }
235 
236 std::vector<double> CPCIDSKPolyModelSegment::GetXForwardCoefficients() const
237 {
238     return pimpl_->vdfX1;
239 }
240 
241 std::vector<double> CPCIDSKPolyModelSegment::GetYForwardCoefficients() const
242 {
243     return pimpl_->vdfY1;
244 }
245 
246 std::vector<double> CPCIDSKPolyModelSegment::GetXBackwardCoefficients() const
247 {
248     return pimpl_->vdfX2;
249 }
250 
251 std::vector<double> CPCIDSKPolyModelSegment::GetYBackwardCoefficients() const
252 {
253     return pimpl_->vdfY2;
254 }
255 
256 void CPCIDSKPolyModelSegment::SetCoefficients(const std::vector<double>& oXForward,
257                                               const std::vector<double>& oYForward,
258                                               const std::vector<double>& oXBackward,
259                                               const std::vector<double>& oYBackward)
260 {
261     assert(oXForward.size() == oYForward.size());
262     assert(oYForward.size() == oXBackward.size());
263     assert(oXBackward.size() == oYBackward.size());
264     pimpl_->vdfX1 = oXForward;
265     pimpl_->vdfY1 = oYForward;
266     pimpl_->vdfX2 = oXBackward;
267     pimpl_->vdfY2 = oYBackward;
268     pimpl_->nNumCoeffs = (unsigned int)oXForward.size();
269 }
270 
271 unsigned int CPCIDSKPolyModelSegment::GetPixels() const
272 {
273     return pimpl_->nPixels;
274 }
275 
276 unsigned int CPCIDSKPolyModelSegment::GetLines() const
277 {
278     return pimpl_->nLines;
279 }
280 
281 void CPCIDSKPolyModelSegment::SetRasterSize(unsigned int nLines,unsigned int nPixels)
282 {
283     pimpl_->nPixels = nPixels;
284     pimpl_->nLines = nLines;
285 }
286 
287 std::string CPCIDSKPolyModelSegment::GetGeosysString() const
288 {
289     return pimpl_->oMapUnit;
290 }
291 
292 void CPCIDSKPolyModelSegment::SetGeosysString(const std::string& oGeosys)
293 {
294     pimpl_->oMapUnit = oGeosys;
295 }
296 
297 std::vector<double> CPCIDSKPolyModelSegment::GetProjParamInfo() const
298 {
299     return pimpl_->oProjectionInfo;
300 }
301 
302 void CPCIDSKPolyModelSegment::SetProjParamInfo(const std::vector<double>& oInfo)
303 {
304     pimpl_->oProjectionInfo = oInfo;
305     while(pimpl_->oProjectionInfo.size() < 19)
306     {
307         pimpl_->oProjectionInfo.push_back(0.0);
308     }
309 }
310 
311 void CPCIDSKPolyModelSegment::Synchronize()
312 {
313     if(mbModified)
314     {
315         this->Write();
316     }
317 }
318 
319