1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CPCIDSKRPCModelSegment class.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2009
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_rpc.h"
29 : #include "segment/cpcidsksegment.h"
30 : #include "core/pcidsk_utils.h"
31 : #include "pcidsk_exception.h"
32 : #include "segment/cpcidskrpcmodel.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 CPCIDSKRPCModelSegment::PCIDSKRPCInfo
43 0 : {
44 : bool userrpc; // whether or not the RPC was generated from GCPs
45 : bool adjusted; // Whether or not the RPC has been adjusted
46 : int downsample; // Epipolar Downsample factor
47 :
48 : unsigned int pixels; // pixels in the image
49 : unsigned int lines; // lines in the image
50 :
51 : unsigned int num_coeffs; // number of coefficientsg
52 :
53 : std::vector<double> pixel_num; // numerator, pixel direction
54 : std::vector<double> pixel_denom; // denominator, pixel direction
55 : std::vector<double> line_num; // numerator, line direction
56 : std::vector<double> line_denom; // denominator, line direction
57 :
58 : // Scale/offset coefficients in the ground domain
59 : double x_off;
60 : double x_scale;
61 :
62 : double y_off;
63 : double y_scale;
64 :
65 : double z_off;
66 : double z_scale;
67 :
68 : // Scale/offset coefficients in the raster domain
69 : double pix_off;
70 : double pix_scale;
71 :
72 : double line_off;
73 : double line_scale;
74 :
75 : std::vector<double> x_adj; // adjusted X values
76 : std::vector<double> y_adj; // adjusted Y values
77 :
78 : std::string sensor_name; // the name of the sensor
79 :
80 : std::string map_units; // the map units string
81 :
82 : // TODO: Projection Info
83 :
84 : // The raw segment data
85 : PCIDSKBuffer seg_data;
86 : };
87 :
88 0 : CPCIDSKRPCModelSegment::CPCIDSKRPCModelSegment(PCIDSKFile *file, int segment,const char *segment_pointer) :
89 : CPCIDSKSegment(file, segment, segment_pointer), pimpl_(new CPCIDSKRPCModelSegment::PCIDSKRPCInfo),
90 0 : loaded_(false)
91 : {
92 0 : Load();
93 0 : }
94 :
95 :
96 0 : CPCIDSKRPCModelSegment::~CPCIDSKRPCModelSegment()
97 : {
98 0 : delete pimpl_;
99 0 : }
100 :
101 : // Load the contents of the segment
102 0 : void CPCIDSKRPCModelSegment::Load()
103 : {
104 : // Check if we've already loaded the segment into memory
105 0 : if (loaded_) {
106 0 : return;
107 : }
108 :
109 0 : assert(data_size - 1024 == 7 * 512);
110 :
111 0 : pimpl_->seg_data.SetSize(data_size - 1024); // should be 7 * 512
112 :
113 0 : ReadFromFile(pimpl_->seg_data.buffer, 0, data_size - 1024);
114 :
115 : // The RPC Model Segment is defined as follows:
116 : // RFMODEL Segment: 7 512-byte blocks
117 :
118 : // Block 1:
119 : // Bytes 0-7: 'RFMODEL '
120 : // Byte 8: User Provided RPC (1: user-provided, 0: computed from GCPs)
121 : // Bytes 22-23: 'DS'
122 : // Bytes 24-26: Downsample factor used during Epipolar Generation
123 : // Bytes 27-29: '2ND' -- no clue what this means
124 : // Bytes 30-35: 'SENSOR'
125 : // Bytes 36: Sensor Name (NULL terminated)
126 :
127 0 : if (std::strncmp(pimpl_->seg_data.buffer, "RFMODEL ", 8)) {
128 : // Something has gone terribly wrong!
129 : throw PCIDSKException("A segment that was previously identified as an RFMODEL "
130 : "segment does not contain the appropriate data. Found: [%s]",
131 0 : std::string(pimpl_->seg_data.buffer, 8).c_str());
132 : }
133 :
134 : // Determine if this is user-provided
135 0 : pimpl_->userrpc = pimpl_->seg_data.buffer[8] == 0 ? true : false;
136 :
137 : // Check for the DS characters
138 0 : pimpl_->downsample = 1;
139 0 : if (!std::strncmp(&pimpl_->seg_data.buffer[22], "DS", 2)) {
140 : // Read the downsample factor
141 0 : pimpl_->downsample = pimpl_->seg_data.GetInt(24, 3);
142 : }
143 :
144 : // I don't know what 2ND means yet.
145 :
146 : // Sensor name:
147 0 : if (!std::strncmp(&pimpl_->seg_data.buffer[30], "SENSOR", 6)) {
148 0 : pimpl_->sensor_name = std::string(&pimpl_->seg_data.buffer[36]);
149 : } else {
150 0 : pimpl_->sensor_name = "";
151 : }
152 :
153 : // Block 2:
154 : // Bytes 0-3: Number of coefficients
155 : // Bytes 4-13: Number of pixels
156 : // Bytes 14-23: Number of lines
157 : // Bytes 24-45: Longitude offset
158 : // Bytes 46-67: Longitude scale
159 : // Bytes 68-89: Latitude Offset
160 : // Bytes 90-111: Latitude Scale
161 : // Bytes 112-133: Height offset
162 : // Bytes 134-155: Height scale
163 : // Bytes 156-177: Sample offset
164 : // Bytes 178-199: Sample scale
165 : // Bytes 200-221: Line offset
166 : // Bytes 222-243: line scale
167 : // Bytes 244-375: Adjusted X coefficients (5 * 22 bytes)
168 : // Bytes 376-507: Adjusted Y coefficients (5 * 22 bytes)
169 :
170 0 : pimpl_->num_coeffs = pimpl_->seg_data.GetInt(512, 4);
171 :
172 0 : if (pimpl_->num_coeffs * 22 > 512) {
173 : // this segment is malformed. Throw an exception.
174 : throw PCIDSKException("RFMODEL segment coefficient count requires more "
175 : "than one block to store. There is an error in this segment. The "
176 0 : "number of coefficients according to the segment is %d.", pimpl_->num_coeffs);
177 : }
178 :
179 0 : pimpl_->lines = pimpl_->seg_data.GetInt(512 + 4, 10);
180 0 : pimpl_->pixels = pimpl_->seg_data.GetInt(512 + 14, 10);
181 0 : pimpl_->x_off = pimpl_->seg_data.GetDouble(512 + 24, 22);
182 0 : pimpl_->x_scale = pimpl_->seg_data.GetDouble(512 + 46, 22);
183 0 : pimpl_->y_off = pimpl_->seg_data.GetDouble(512 + 68, 22);
184 0 : pimpl_->y_scale = pimpl_->seg_data.GetDouble(512 + 90, 22);
185 0 : pimpl_->z_off = pimpl_->seg_data.GetDouble(512 + 112, 22);
186 0 : pimpl_->z_scale = pimpl_->seg_data.GetDouble(512 + 134, 22);
187 0 : pimpl_->pix_off = pimpl_->seg_data.GetDouble(512 + 156, 22);
188 0 : pimpl_->pix_scale = pimpl_->seg_data.GetDouble(512 + 178, 22);
189 0 : pimpl_->line_off = pimpl_->seg_data.GetDouble(512 + 200, 22);
190 0 : pimpl_->line_scale = pimpl_->seg_data.GetDouble(512 + 222, 22);
191 :
192 : // Read in adjusted X coefficients
193 0 : for (unsigned int i = 0; i <= 5; i++) {
194 0 : double tmp = pimpl_->seg_data.GetDouble(512 + 244 + (i * 22), 22);
195 0 : pimpl_->x_adj.push_back(tmp);
196 : }
197 :
198 : // Read in adjusted Y coefficients
199 0 : for (unsigned int i = 0; i <= 5; i++) {
200 0 : double tmp = pimpl_->seg_data.GetDouble(512 + 376 + (i * 22), 22);
201 0 : pimpl_->y_adj.push_back(tmp);
202 : }
203 :
204 : // Block 3:
205 : // Block 3 contains the numerator coefficients for the pixel rational polynomial
206 : // Number of Coefficients * 22 bytes
207 0 : for (unsigned int i = 0; i < pimpl_->num_coeffs; i++) {
208 0 : pimpl_->pixel_num.push_back(pimpl_->seg_data.GetDouble(2 * 512 + (i * 22), 22));
209 : }
210 :
211 : // Block 4:
212 : // Block 4 contains the denominator coefficients for the pixel rational polynomial
213 : // Number of Coefficients * 22 bytes
214 0 : for (unsigned int i = 0; i < pimpl_->num_coeffs; i++) {
215 0 : pimpl_->pixel_denom.push_back(pimpl_->seg_data.GetDouble(3 * 512 + (i * 22), 22));
216 : }
217 :
218 : // Block 5:
219 : // Block 5 contains the numerator coefficients for the line rational polynomial
220 : // Number of Coefficients * 22 bytes
221 0 : for (unsigned int i = 0; i < pimpl_->num_coeffs; i++) {
222 0 : pimpl_->line_num.push_back(pimpl_->seg_data.GetDouble(4 * 512 + (i * 22), 22));
223 : }
224 :
225 : // Block 6:
226 : // Block 6 contains the denominator coefficients for the line rational polynomial
227 : // Number of Coefficients * 22 bytes
228 0 : for (unsigned int i = 0; i < pimpl_->num_coeffs; i++) {
229 0 : pimpl_->line_denom.push_back(pimpl_->seg_data.GetDouble(5 * 512 + (i * 22), 22));
230 : }
231 :
232 : // Block 7:
233 : // Bytes 0-15: MapUnits string
234 : // Bytes 256-511: ProjInfo_t, serialized
235 0 : pimpl_->map_units = std::string(&pimpl_->seg_data.buffer[6 * 512], 16);
236 :
237 : // We've now loaded the structure up with data. Mark it as being loaded
238 : // properly.
239 0 : loaded_ = true;
240 :
241 : }
242 :
243 0 : void CPCIDSKRPCModelSegment::Write(void)
244 : {
245 :
246 0 : }
247 :
248 0 : std::vector<double> CPCIDSKRPCModelSegment::GetXNumerator(void) const
249 : {
250 0 : return pimpl_->pixel_num;
251 : }
252 :
253 0 : std::vector<double> CPCIDSKRPCModelSegment::GetXDenominator(void) const
254 : {
255 0 : return pimpl_->pixel_denom;
256 : }
257 :
258 0 : std::vector<double> CPCIDSKRPCModelSegment::GetYNumerator(void) const
259 : {
260 0 : return pimpl_->line_num;
261 : }
262 :
263 0 : std::vector<double> CPCIDSKRPCModelSegment::GetYDenominator(void) const
264 : {
265 0 : return pimpl_->line_denom;
266 : }
267 :
268 : // Set the RPC Coefficients
269 : void CPCIDSKRPCModelSegment::SetCoefficients(
270 : const std::vector<double>& xnum, const std::vector<double>& xdenom,
271 0 : const std::vector<double>& ynum, const std::vector<double>& ydenom)
272 : {
273 0 : if (xnum.size() != xdenom.size() || ynum.size() != ydenom.size() ||
274 : xnum.size() != ynum.size() || xdenom.size() != ydenom.size()) {
275 : throw PCIDSKException("All RPC coefficient vectors must be the "
276 0 : "same size.");
277 : }
278 :
279 0 : pimpl_->pixel_num = xnum;
280 0 : pimpl_->pixel_denom = xdenom;
281 0 : pimpl_->line_num = ynum;
282 0 : pimpl_->line_denom = ydenom;
283 0 : }
284 :
285 : // Get the RPC offset/scale Coefficients
286 : void CPCIDSKRPCModelSegment::GetRPCTranslationCoeffs(double& xoffset, double& xscale,
287 : double& yoffset, double& yscale, double& zoffset, double& zscale,
288 0 : double& pixoffset, double& pixscale, double& lineoffset, double& linescale) const
289 : {
290 0 : xoffset = pimpl_->x_off;
291 0 : xscale = pimpl_->x_scale;
292 :
293 0 : yoffset = pimpl_->y_off;
294 0 : yscale = pimpl_->y_scale;
295 :
296 0 : zoffset = pimpl_->z_off;
297 0 : zscale = pimpl_->z_scale;
298 :
299 0 : pixoffset = pimpl_->pix_off;
300 0 : pixscale = pimpl_->pix_scale;
301 :
302 0 : lineoffset = pimpl_->line_off;
303 0 : linescale = pimpl_->line_scale;
304 0 : }
305 :
306 : // Set the RPC offset/scale Coefficients
307 : void CPCIDSKRPCModelSegment::SetRPCTranslationCoeffs(
308 : const double xoffset, const double xscale,
309 : const double yoffset, const double yscale,
310 : const double zoffset, const double zscale,
311 : const double pixoffset, const double pixscale,
312 0 : const double lineoffset, const double linescale)
313 : {
314 0 : pimpl_->x_off = xoffset;
315 0 : pimpl_->x_scale = xscale;
316 :
317 0 : pimpl_->y_off = yoffset;
318 0 : pimpl_->y_scale = yscale;
319 :
320 0 : pimpl_->z_off = zoffset;
321 0 : pimpl_->z_scale = zscale;
322 :
323 0 : pimpl_->pix_off = pixoffset;
324 0 : pimpl_->pix_scale = pixscale;
325 :
326 0 : pimpl_->line_off = lineoffset;
327 0 : pimpl_->line_scale = linescale;
328 :
329 0 : }
330 :
331 : // Get the adjusted X values
332 0 : std::vector<double> CPCIDSKRPCModelSegment::GetAdjXValues(void) const
333 : {
334 0 : return pimpl_->x_adj;
335 : }
336 :
337 : // Get the adjusted Y values
338 0 : std::vector<double> CPCIDSKRPCModelSegment::GetAdjYValues(void) const
339 : {
340 0 : return pimpl_->y_adj;
341 : }
342 :
343 : // Set the adjusted X/Y values
344 : void CPCIDSKRPCModelSegment::SetAdjCoordValues(const std::vector<double>& xcoord,
345 0 : const std::vector<double>& ycoord)
346 : {
347 0 : if (xcoord.size() != 6 || ycoord.size() != 6) {
348 : throw PCIDSKException("X and Y adjusted coordinates must have "
349 0 : "length 5.");
350 : }
351 :
352 0 : pimpl_->x_adj = xcoord;
353 0 : pimpl_->y_adj = ycoord;
354 0 : }
355 :
356 : // Get whether or not this is a user-generated RPC model
357 0 : bool CPCIDSKRPCModelSegment::IsUserGenerated(void) const
358 : {
359 0 : return pimpl_->userrpc;
360 : }
361 :
362 : // Set whether or not this is a user-generated RPC model
363 0 : void CPCIDSKRPCModelSegment::SetUserGenerated(bool usergen)
364 : {
365 0 : pimpl_->userrpc = usergen;
366 0 : }
367 :
368 : // Get whether the model has been adjusted
369 0 : bool CPCIDSKRPCModelSegment::IsNominalModel(void) const
370 : {
371 0 : return !pimpl_->adjusted;
372 : }
373 :
374 : // Set whether the model has been adjusted
375 0 : void CPCIDSKRPCModelSegment::SetIsNominalModel(bool nominal)
376 : {
377 0 : pimpl_->adjusted = !nominal;
378 0 : }
379 :
380 : // Get sensor name
381 0 : std::string CPCIDSKRPCModelSegment::GetSensorName(void) const
382 : {
383 0 : return pimpl_->sensor_name;
384 : }
385 :
386 : // Set sensor name
387 0 : void CPCIDSKRPCModelSegment::SetSensorName(const std::string& name)
388 : {
389 0 : pimpl_->sensor_name = name;
390 0 : }
391 :
392 : // Output projection information of RPC Model
393 : // Get the Geosys String
394 0 : std::string CPCIDSKRPCModelSegment::GetGeosysString(void) const
395 : {
396 0 : return pimpl_->map_units;
397 : }
398 :
399 : // Set the Geosys string
400 0 : void CPCIDSKRPCModelSegment::SetGeosysString(const std::string& geosys)
401 : {
402 0 : if (geosys.size() > 16) {
403 : throw PCIDSKException("GeoSys/MapUnits string must be no more than "
404 0 : "16 characters to be valid.");
405 : }
406 0 : pimpl_->map_units = geosys;
407 0 : }
408 :
409 : // Get number of lines
410 0 : unsigned int CPCIDSKRPCModelSegment::GetLines(void) const
411 : {
412 0 : return pimpl_->lines;
413 : }
414 :
415 0 : unsigned int CPCIDSKRPCModelSegment::GetPixels(void) const
416 : {
417 0 : return pimpl_->pixels;
418 : }
419 :
420 0 : void CPCIDSKRPCModelSegment::SetRasterSize(const unsigned int lines, const unsigned int pixels)
421 : {
422 0 : if (lines == 0 || pixels == 0) {
423 0 : throw PCIDSKException("Non-sensical raster dimensions provided: %ux%u", lines, pixels);
424 : }
425 :
426 0 : pimpl_->lines = lines;
427 0 : pimpl_->pixels = pixels;
428 0 : }
|