1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the APMODEL segment and storage objects.
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 : #include "pcidsk_airphoto.h"
28 : #include "pcidsk_exception.h"
29 : #include "segment/cpcidskapmodel.h"
30 :
31 : #include <utility>
32 : #include <vector>
33 : #include <string>
34 : #include <sstream>
35 : #include <cassert>
36 : #include <cstring>
37 :
38 : using namespace PCIDSK;
39 :
40 : /**
41 : * Construct a new PCIDSK Airphoto Model Interior Orientation
42 : * parameters store.
43 : */
44 0 : PCIDSKAPModelIOParams::PCIDSKAPModelIOParams(std::vector<double> const& imgtofocalx,
45 : std::vector<double> const& imgtofocaly,
46 : std::vector<double> const& focaltocolumn,
47 : std::vector<double> const& focaltorow,
48 : double focal_len,
49 : std::pair<double, double> const& prin_pt,
50 : std::vector<double> const& radial_dist) :
51 : imgtofocalx_(imgtofocalx), imgtofocaly_(imgtofocaly), focaltocolumn_(focaltocolumn),
52 : focaltorow_(focaltorow), focal_len_(focal_len), prin_point_(prin_pt),
53 0 : rad_dist_coeff_(radial_dist)
54 : {
55 0 : }
56 :
57 0 : std::vector<double> const& PCIDSKAPModelIOParams::GetImageToFocalPlaneXCoeffs(void) const
58 : {
59 0 : return imgtofocalx_;
60 : }
61 :
62 0 : std::vector<double> const& PCIDSKAPModelIOParams::GetImageToFocalPlaneYCoeffs(void) const
63 : {
64 0 : return imgtofocaly_;
65 : }
66 :
67 0 : std::vector<double> const& PCIDSKAPModelIOParams::GetFocalPlaneToColumnCoeffs(void) const
68 : {
69 0 : return focaltocolumn_;
70 : }
71 :
72 0 : std::vector<double> const& PCIDSKAPModelIOParams::GetFocalPlaneToRowCoeffs(void) const
73 : {
74 0 : return focaltorow_;
75 : }
76 :
77 0 : double PCIDSKAPModelIOParams::GetFocalLength(void) const
78 : {
79 0 : return focal_len_;
80 : }
81 :
82 0 : std::pair<double, double> const& PCIDSKAPModelIOParams::GetPrincipalPoint(void) const
83 : {
84 0 : return prin_point_;
85 : }
86 :
87 0 : std::vector<double> const& PCIDSKAPModelIOParams::GetRadialDistortionCoeffs(void) const
88 : {
89 0 : return rad_dist_coeff_;
90 : }
91 :
92 : /**
93 : * Construct a new PCIDSK Airphoto Model Exterior Orientation parameters
94 : * storage object.
95 : */
96 0 : PCIDSKAPModelEOParams::PCIDSKAPModelEOParams(std::string const& rotation_type,
97 : std::vector<double> const& earth_to_body,
98 : std::vector<double> const& perspect_cen,
99 : unsigned int epsg_code) :
100 : rot_type_(rotation_type), earth_to_body_(earth_to_body),
101 0 : perspective_centre_pos_(perspect_cen), epsg_code_(epsg_code)
102 : {
103 0 : }
104 :
105 0 : std::string PCIDSKAPModelEOParams::GetEarthToBodyRotationType(void) const
106 : {
107 0 : return rot_type_;
108 : }
109 :
110 0 : std::vector<double> const& PCIDSKAPModelEOParams::GetEarthToBodyRotation(void) const
111 : {
112 0 : return earth_to_body_;
113 : }
114 :
115 0 : std::vector<double> const& PCIDSKAPModelEOParams::GetPerspectiveCentrePosition(void) const
116 : {
117 0 : return perspective_centre_pos_;
118 : }
119 :
120 0 : unsigned int PCIDSKAPModelEOParams::GetEPSGCode(void) const
121 : {
122 0 : return epsg_code_;
123 : }
124 :
125 : /**
126 : * Miscellaneous camera parameters for the AP Model
127 : */
128 0 : PCIDSKAPModelMiscParams::PCIDSKAPModelMiscParams(std::vector<double> const& decentering_coeffs,
129 : std::vector<double> const& x3dcoord,
130 : std::vector<double> const& y3dcoord,
131 : std::vector<double> const& z3dcoord,
132 : double radius,
133 : double rff,
134 : double min_gcp_hgt,
135 : double max_gcp_hgt,
136 : bool is_prin_pt_off,
137 : bool has_dist,
138 : bool has_decent,
139 : bool has_radius) :
140 : decentering_coeffs_(decentering_coeffs), x3dcoord_(x3dcoord), y3dcoord_(y3dcoord),
141 : z3dcoord_(z3dcoord), radius_(radius), rff_(rff), min_gcp_hgt_(min_gcp_hgt),
142 : max_gcp_hgt_(max_gcp_hgt), is_prin_pt_off_(is_prin_pt_off),
143 0 : has_dist_(has_dist), has_decent_(has_decent), has_radius_(has_radius)
144 : {
145 0 : }
146 :
147 0 : std::vector<double> const& PCIDSKAPModelMiscParams::GetDecenteringDistortionCoeffs(void) const
148 : {
149 0 : return decentering_coeffs_;
150 : }
151 :
152 0 : std::vector<double> const& PCIDSKAPModelMiscParams::GetX3DCoord(void) const
153 : {
154 0 : return x3dcoord_;
155 : }
156 :
157 0 : std::vector<double> const& PCIDSKAPModelMiscParams::GetY3DCoord(void) const
158 : {
159 0 : return y3dcoord_;
160 : }
161 :
162 0 : std::vector<double> const& PCIDSKAPModelMiscParams::GetZ3DCoord(void) const
163 : {
164 0 : return z3dcoord_;
165 : }
166 :
167 0 : double PCIDSKAPModelMiscParams::GetRadius(void) const
168 : {
169 0 : return radius_;
170 : }
171 :
172 0 : double PCIDSKAPModelMiscParams::GetRFF(void) const
173 : {
174 0 : return rff_;
175 : }
176 :
177 0 : double PCIDSKAPModelMiscParams::GetGCPMinHeight(void) const
178 : {
179 0 : return min_gcp_hgt_;
180 : }
181 :
182 0 : double PCIDSKAPModelMiscParams::GetGCPMaxHeight(void) const
183 : {
184 0 : return max_gcp_hgt_;
185 : }
186 :
187 0 : bool PCIDSKAPModelMiscParams::IsPrincipalPointOffset(void) const
188 : {
189 0 : return is_prin_pt_off_;
190 : }
191 :
192 0 : bool PCIDSKAPModelMiscParams::HasDistortion(void) const
193 : {
194 0 : return has_dist_;
195 : }
196 :
197 0 : bool PCIDSKAPModelMiscParams::HasDecentering(void) const
198 : {
199 0 : return has_decent_;
200 : }
201 :
202 0 : bool PCIDSKAPModelMiscParams::HasRadius(void) const
203 : {
204 0 : return has_radius_;
205 : }
206 :
207 : /**
208 : * Create a new PCIDSK APMODEL segment
209 : */
210 0 : CPCIDSKAPModelSegment::CPCIDSKAPModelSegment(PCIDSKFile *file, int segment, const char *segment_pointer) :
211 0 : CPCIDSKSegment(file, segment, segment_pointer)
212 : {
213 0 : filled_ = false;
214 0 : io_params_ = NULL;
215 0 : eo_params_ = NULL;
216 0 : misc_params_ = NULL;
217 0 : UpdateFromDisk();
218 0 : }
219 :
220 0 : CPCIDSKAPModelSegment::~CPCIDSKAPModelSegment()
221 : {
222 0 : delete io_params_;
223 0 : delete eo_params_;
224 0 : delete misc_params_;
225 0 : }
226 :
227 0 : unsigned int CPCIDSKAPModelSegment::GetWidth(void) const
228 : {
229 0 : if (!filled_) {
230 0 : ThrowPCIDSKException("Failed to determine width from APModel.");
231 : }
232 0 : return width_;
233 : }
234 :
235 0 : unsigned int CPCIDSKAPModelSegment::GetHeight(void) const
236 : {
237 0 : if (!filled_) {
238 0 : ThrowPCIDSKException("Failed to determine height from APModel.");
239 : }
240 0 : return height_;
241 : }
242 :
243 0 : unsigned int CPCIDSKAPModelSegment::GetDownsampleFactor(void) const
244 : {
245 0 : if (!filled_) {
246 0 : ThrowPCIDSKException("Failed to determine APModel downsample factor.");
247 : }
248 0 : return downsample_;
249 : }
250 :
251 : // Interior Orientation Parameters
252 0 : PCIDSKAPModelIOParams const& CPCIDSKAPModelSegment::GetInteriorOrientationParams(void) const
253 : {
254 0 : if (io_params_ == NULL) {
255 0 : ThrowPCIDSKException("There was a failure in reading the APModel IO params.");
256 : }
257 0 : return *io_params_;
258 : }
259 :
260 : // Exterior Orientation Parameters
261 0 : PCIDSKAPModelEOParams const& CPCIDSKAPModelSegment::GetExteriorOrientationParams(void) const
262 : {
263 0 : if (eo_params_ == NULL) {
264 0 : ThrowPCIDSKException("There was a failure in reading the APModel EO params.");
265 : }
266 0 : return *eo_params_;
267 : }
268 :
269 0 : PCIDSKAPModelMiscParams const& CPCIDSKAPModelSegment::GetAdditionalParams(void) const
270 : {
271 0 : if (misc_params_ == NULL) {
272 0 : ThrowPCIDSKException("There was a failure in reading the APModel camera params.");
273 : }
274 0 : return *misc_params_;
275 : }
276 :
277 0 : std::string CPCIDSKAPModelSegment::GetMapUnitsString(void) const
278 : {
279 0 : return map_units_;
280 : }
281 :
282 0 : std::string CPCIDSKAPModelSegment::GetUTMUnitsString(void) const
283 : {
284 0 : return map_units_;
285 : }
286 :
287 0 : std::vector<double> const& CPCIDSKAPModelSegment::GetProjParams(void) const
288 : {
289 0 : return proj_parms_;
290 : }
291 :
292 : /************************************************************************/
293 : /* BinaryToAPInfo() */
294 : /************************************************************************/
295 : /**
296 : * Convert the contents of the PCIDSKBuffer buf to a set of APModel
297 : * params
298 : *
299 : * @param buf A reference pointer to a PCIDSKBuffer
300 : * @param eo_params A pointer to EO params to be populated
301 : * @param io_params A pointer to IO params to be populated
302 : * @param misc_params A pointer to camera params to be populated
303 : * @param pixels The number of pixels in the image
304 : * @param lines The number of lines in the image
305 : * @param downsample The downsampling factor applied
306 : * @param map_units the map units/geosys string
307 : * @param utm_units the UTM units string
308 : */
309 : namespace {
310 0 : void BinaryToAPInfo(PCIDSKBuffer& buf,
311 : PCIDSKAPModelEOParams*& eo_params,
312 : PCIDSKAPModelIOParams*& io_params,
313 : PCIDSKAPModelMiscParams*& misc_params,
314 : unsigned int& pixels,
315 : unsigned int& lines,
316 : unsigned int& downsample,
317 : std::string& map_units,
318 : std::vector<double>& proj_parms,
319 : std::string& utm_units)
320 :
321 : {
322 0 : proj_parms.clear();
323 0 : map_units.clear();
324 0 : utm_units.clear();
325 : /* -------------------------------------------------------------------- */
326 : /* Read the header block */
327 : /* -------------------------------------------------------------------- */
328 :
329 0 : if(strncmp(buf.buffer,"APMODEL ",8))
330 : {
331 0 : std::string magic(buf.buffer, 8);
332 : ThrowPCIDSKException("Bad segment magic found. Found: [%s] expecting [APMODEL ]",
333 0 : magic.c_str());
334 : }
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Allocate the APModel. */
338 : /* -------------------------------------------------------------------- */
339 :
340 0 : downsample = buf.GetInt(24, 3);
341 0 : if (0 >= downsample) downsample = 0;
342 :
343 : /* -------------------------------------------------------------------- */
344 : /* Read the values */
345 : /* -------------------------------------------------------------------- */
346 0 : pixels = buf.GetInt(0 * 22 + 512, 22);
347 0 : lines = buf.GetInt(1 * 22 + 512, 22);
348 0 : double focal_length = buf.GetDouble(2 * 22 + 512, 22);
349 0 : std::vector<double> perspective_centre(3);
350 0 : perspective_centre[0] = buf.GetDouble(3 * 22 + 512, 22);
351 0 : perspective_centre[1] = buf.GetDouble(4 * 22 + 512, 22);
352 0 : perspective_centre[2] = buf.GetDouble(5 * 22 + 512, 22);
353 :
354 0 : std::vector<double> earth_to_body(3);
355 0 : earth_to_body[0] = buf.GetDouble(6 * 22 + 512, 22);
356 0 : earth_to_body[1] = buf.GetDouble(7 * 22 + 512, 22);
357 0 : earth_to_body[2] = buf.GetDouble(8 * 22 + 512, 22);
358 :
359 : // NOTE: PCIDSK itself doesn't support storing information
360 : // about the rotation type, nor the EPSG code for the
361 : // transformation. However, in the (not so distant)
362 : // future, we will likely want to add this support to
363 : // the APMODEL segment (or perhaps a future means of
364 : // storing airphoto information).
365 : eo_params = new PCIDSKAPModelEOParams("",
366 : earth_to_body,
367 : perspective_centre,
368 0 : -1);
369 :
370 0 : std::vector<double> x3d(3);
371 0 : std::vector<double> y3d(3);
372 0 : std::vector<double> z3d(3);
373 :
374 0 : x3d[0] = buf.GetDouble(9 * 22 + 512, 22);
375 0 : x3d[1] = buf.GetDouble(10 * 22 + 512, 22);
376 0 : x3d[2] = buf.GetDouble(11 * 22 + 512, 22);
377 0 : y3d[0] = buf.GetDouble(12 * 22 + 512, 22);
378 0 : y3d[1] = buf.GetDouble(13 * 22 + 512, 22);
379 0 : y3d[2] = buf.GetDouble(14 * 22 + 512, 22);
380 0 : z3d[0] = buf.GetDouble(15 * 22 + 512, 22);
381 0 : z3d[1] = buf.GetDouble(16 * 22 + 512, 22);
382 0 : z3d[2] = buf.GetDouble(17 * 22 + 512, 22);
383 :
384 0 : std::vector<double> img_to_focal_plane_x(4);
385 0 : std::vector<double> img_to_focal_plane_y(4);
386 0 : img_to_focal_plane_x[0] = buf.GetDouble(18 * 22 + 512, 22);
387 0 : img_to_focal_plane_x[1] = buf.GetDouble(19 * 22 + 512, 22);
388 0 : img_to_focal_plane_x[2] = buf.GetDouble(20 * 22 + 512, 22);
389 0 : img_to_focal_plane_x[3] = buf.GetDouble(21 * 22 + 512, 22);
390 :
391 0 : img_to_focal_plane_y[0] = buf.GetDouble(0 * 22 + 512 * 2, 22);
392 0 : img_to_focal_plane_y[1] = buf.GetDouble(1 * 22 + 512 * 2, 22);
393 0 : img_to_focal_plane_y[2] = buf.GetDouble(2 * 22 + 512 * 2, 22);
394 0 : img_to_focal_plane_y[3] = buf.GetDouble(3 * 22 + 512 * 2, 22);
395 :
396 0 : std::vector<double> focal_to_cols(4);
397 0 : std::vector<double> focal_to_lines(4);
398 0 : focal_to_cols[0] = buf.GetDouble(4 * 22 + 512 * 2, 22);
399 0 : focal_to_cols[1] = buf.GetDouble(5 * 22 + 512 * 2, 22);
400 0 : focal_to_cols[2] = buf.GetDouble(6 * 22 + 512 * 2, 22);
401 0 : focal_to_cols[3] = buf.GetDouble(7 * 22 + 512 * 2, 22);
402 :
403 0 : focal_to_lines[0] = buf.GetDouble(8 * 22 + 512 * 2, 22);
404 0 : focal_to_lines[1] = buf.GetDouble(9 * 22 + 512 * 2, 22);
405 0 : focal_to_lines[2] = buf.GetDouble(10 * 22 + 512 * 2, 22);
406 0 : focal_to_lines[3] = buf.GetDouble(11 * 22 + 512 * 2, 22);
407 :
408 0 : std::pair<double, double> principal_point;
409 :
410 0 : principal_point.first = buf.GetDouble(12 * 22 + 512 * 2, 22);
411 0 : principal_point.second = buf.GetDouble(13 * 22 + 512 * 2, 22);
412 :
413 0 : std::vector<double> radial_distortion(8);
414 0 : radial_distortion[0] = buf.GetDouble(14 * 22 + 512 * 2, 22);
415 0 : radial_distortion[1] = buf.GetDouble(15 * 22 + 512 * 2, 22);
416 0 : radial_distortion[2] = buf.GetDouble(16 * 22 + 512 * 2, 22);
417 0 : radial_distortion[3] = buf.GetDouble(17 * 22 + 512 * 2, 22);
418 0 : radial_distortion[4] = buf.GetDouble(18 * 22 + 512 * 2, 22);
419 0 : radial_distortion[5] = buf.GetDouble(19 * 22 + 512 * 2, 22);
420 0 : radial_distortion[6] = buf.GetDouble(20 * 22 + 512 * 2, 22);
421 0 : radial_distortion[7] = buf.GetDouble(21 * 22 + 512 * 2, 22);
422 :
423 : // We have enough information now to construct the interior
424 : // orientation parameters
425 : io_params = new PCIDSKAPModelIOParams(img_to_focal_plane_x,
426 : img_to_focal_plane_y,
427 : focal_to_cols,
428 : focal_to_lines,
429 : focal_length,
430 : principal_point,
431 0 : radial_distortion);
432 :
433 0 : std::vector<double> decentering(4);
434 0 : decentering[0] = buf.GetDouble(0 * 22 + 512 * 3, 22);
435 0 : decentering[1] = buf.GetDouble(1 * 22 + 512 * 3, 22);
436 0 : decentering[2] = buf.GetDouble(2 * 22 + 512 * 3, 22);
437 0 : decentering[3] = buf.GetDouble(3 * 22 + 512 * 3, 22);
438 :
439 0 : double radius = buf.GetDouble(4 * 22 + 512 * 3, 22);
440 0 : double rff = buf.GetDouble(5 * 22 + 512 * 3, 22);
441 0 : double gcp_min_height = buf.GetDouble(6 * 22 + 512 * 3, 22);
442 0 : double gcp_max_height = buf.GetDouble(7 * 22 + 512 * 3, 22);
443 0 : bool prin_off = buf.GetInt(8 * 22 + 512 * 3, 22) != 0;
444 0 : bool distort_true = buf.GetInt(9 * 22 + 512 * 3, 22) != 0;
445 0 : bool has_decentering = buf.GetInt(10 * 22 + 512 * 3, 22) != 0;
446 0 : bool has_radius = buf.GetInt(11 * 22 + 512 * 3, 22) != 0;
447 :
448 : // Fill in the camera parameters
449 : misc_params = new PCIDSKAPModelMiscParams(decentering,
450 : x3d,
451 : y3d,
452 : z3d,
453 : radius,
454 : rff,
455 : gcp_min_height,
456 : gcp_max_height,
457 : prin_off,
458 : distort_true,
459 : has_decentering,
460 0 : has_radius);
461 :
462 :
463 : /* -------------------------------------------------------------------- */
464 : /* Read the projection required */
465 : /* -------------------------------------------------------------------- */
466 0 : buf.Get(512 * 4, 16, map_units);
467 :
468 0 : if (!std::strncmp(buf.Get(512 * 4 + 16, 3), "UTM", 3))
469 : {
470 0 : buf.Get(512 * 4, 3, utm_units);
471 : }
472 :
473 : // Parse the Proj Params
474 0 : proj_parms.clear();
475 :
476 0 : if (*buf.Get(512 * 4 + 256, 1) == '\0')
477 : {
478 0 : for (std::size_t i = 0; i < 18; i++)
479 : {
480 0 : proj_parms.push_back(0.0);
481 : }
482 : }
483 : else
484 : {
485 0 : std::stringstream proj_stream(std::string(buf.Get(512 * 4 + 256, 256)));
486 :
487 0 : for (std::size_t i = 0; i < 18; i++)
488 : {
489 : double parm;
490 0 : proj_stream >> parm;
491 0 : proj_parms.push_back(parm);
492 0 : }
493 0 : }
494 0 : }
495 : } // end anonymous namespace
496 :
497 0 : void CPCIDSKAPModelSegment::UpdateFromDisk(void)
498 : {
499 0 : if (filled_) {
500 0 : return;
501 : }
502 :
503 : // Start reading in the APModel segment. APModel segments should be
504 : // 7 blocks long.
505 0 : if (data_size < (1024 + 7 * 512)) {
506 : ThrowPCIDSKException("APMODEL segment is smaller than expected. A "
507 0 : "segment of size %d was found", data_size);
508 : }
509 0 : buf.SetSize( (int) (data_size - 1024) );
510 0 : ReadFromFile(buf.buffer, 0, data_size - 1024);
511 :
512 : // Expand it using an analogue to a method pulled from GDB
513 : BinaryToAPInfo(buf,
514 : eo_params_,
515 : io_params_,
516 : misc_params_,
517 : width_,
518 : height_,
519 : downsample_,
520 : map_units_,
521 : proj_parms_,
522 0 : utm_units_);
523 :
524 : // Done, mark ourselves as having been properly filled
525 0 : filled_ = true;
526 : }
|