OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimRsmModel.cpp
Go to the documentation of this file.
1 //---
2 // File: ossimRsmModel.cpp
3 //
4 // RP
5 // LIMITATIONS - This is supporting only the RSM features that have been
6 // observed in current data samples and does not attempt to support the entire
7 // RSM specification.
8 // Examples of currently unsupported items include ->
9 // 1. multiple RSMPC tags for different polynomials for separate image sections
10 // 2. Error Covariance (this may gain priority as we have access to RSMECA data)
11 // 3. Illumination model
12 // 4. Rectangular coodinate system conversion (RSDIDA GRNDD = "R")
13 //
14 //---
15 
17 #include <ossim/base/ossimDatum.h>
22 #include <ossim/base/ossimNotify.h>
23 #include <ossim/base/ossimTrace.h>
27 
28 #include <algorithm>
29 #include <iomanip>
30 #include <iostream>
31 #include <sstream>
32 
33 RTTI_DEF1(ossimRsmModel, "ossimRsmModel", ossimSensorModel);
34 
35 // Define Trace flags for use within this file:
36 static const ossimTrace traceExec ("ossimRsmModel:exec");
37 static const ossimTrace traceDebug ("ossimRsmModel:debug");
38 
39 static std::string MODEL_TYPE_KW = "ossimRsmModel";
40 
42  :
44  m_ida(),
45  m_pia(),
46  m_pca()
47 {
49 
50 }
51 
53  :
54  ossimSensorModel( obj ),
55  m_ida( obj.m_ida ),
56  m_pia( obj.m_pia ),
57  m_pca( obj.m_pca )
58 {
59 
60 }
61 
63 {
64  if (this != &rhs)
65  {
67  m_ida = rhs.m_ida;
68  m_pia = rhs.m_pia;
69  m_pca = rhs.m_pca;
70  }
71  return *this;
72 }
73 
75 {
76 }
77 
78 //---
79 // METHOD: ossimRsmModel::worldToLineSample()
80 //
81 // Overrides base class implementation. Directly computes line-sample from
82 // the polynomials.
83 //---
84 void ossimRsmModel::worldToLineSample(const ossimGpt& ground_point,
85  ossimDpt& img_pt) const
86 {
87  if(ground_point.isLatNan() || ground_point.isLonNan() )
88  {
89  img_pt.makeNan();
90  return;
91  }
92 
93  //---
94  // RSMIDA GRNDD Ground Domain Form:
95  // G: Geodetic: range x is -pi to pi, y is -pi/2 to pi/2
96  // H: Geodetic: range x is 0 to 2pi, y is -pi/2 to pi/2 (where image is close to pi.
97  // R: Rectangular (not supported).
98  //---
99 
100  // Initial xyz for computing the pca index.
101  double x;
102  if ( m_ida.m_grndd == 'H' )
103  {
104  x = ossim::degreesToRadians((ground_point.lon >= 0.0) ?
105  ground_point.lon : ground_point.lon + 360.0);
106  }
107  else
108  {
109  x = ossim::degreesToRadians( ground_point.lon );
110  }
111 
112  double y = ossim::degreesToRadians(ground_point.lat);
113  double z = ground_point.hgt;
114  if ( ossim::isnan( z ) )
115  {
116  z = 0.0; // ??? drb
117  }
118 
119  ossim_uint32 pcaIndex = getPcaIndex( x, y, z );
120 
121  //---
122  // Normalize the lat, lon, hgt:
123  // a_norm = (a-offset)/scalefactor
124  //---
125  y = (y - m_pca[pcaIndex].m_ynrmo) / m_pca[pcaIndex].m_ynrmsf;
126  x = (x - m_pca[pcaIndex].m_xnrmo) / m_pca[pcaIndex].m_xnrmsf;
127  if( ground_point.isHgtNan() )
128  {
129  z = ( - m_pca[pcaIndex].m_znrmo) / m_pca[pcaIndex].m_znrmsf;
130  }
131  else
132  {
133  z = (ground_point.hgt - m_pca[pcaIndex].m_znrmo) / m_pca[pcaIndex].m_znrmsf;
134  }
135 
136  double rnNrm = polynomial(x, y, z, m_pca[pcaIndex].m_rnpwrx, m_pca[pcaIndex].m_rnpwry, m_pca[pcaIndex].m_rnpwrz, m_pca[pcaIndex].m_rnpcf);
137  double rdNrm = polynomial(x, y, z, m_pca[pcaIndex].m_rdpwrx, m_pca[pcaIndex].m_rdpwry, m_pca[pcaIndex].m_rdpwrz, m_pca[pcaIndex].m_rdpcf);
138  double cnNrm = polynomial(x, y, z, m_pca[pcaIndex].m_cnpwrx, m_pca[pcaIndex].m_cnpwry, m_pca[pcaIndex].m_cnpwrz, m_pca[pcaIndex].m_cnpcf);
139  double cdNrm = polynomial(x, y, z, m_pca[pcaIndex].m_cdpwrx, m_pca[pcaIndex].m_cdpwry, m_pca[pcaIndex].m_cdpwrz, m_pca[pcaIndex].m_cdpcf);
140 
141  double rNrm = rnNrm / rdNrm;
142  double cNrm = cnNrm / cdNrm;
143 
144  //---
145  // Unnormalize the computed value
146  // a = (a_norm * scalefactor) + offset
147  //
148  // Note:
149  //
150  // RSM (0,0) is upper left corner of pixel(0,0). OSSIM (0,0) is
151  // center of the pixel; hence, the - 0.5. (drb 22 May 2015)
152  //---
153 
154  // img_pt.line = (rNrm * m_rnrmsf) + m_rnrmo;
155  // img_pt.samp = (cNrm * m_cnrmsf) + m_cnrmo;
156  img_pt.line = (rNrm * m_pca[pcaIndex].m_rnrmsf) + m_pca[pcaIndex].m_rnrmo - 0.5;
157  img_pt.samp = (cNrm * m_pca[pcaIndex].m_cnrmsf) + m_pca[pcaIndex].m_cnrmo - 0.5;
158 
159 
160 } // End: ossimRsmModel::worldToLineSample( ... )
161 
162 //---
163 // METHOD: ossimRsmModel::lineSampleToWorld()
164 //
165 // Overrides base class implementation. Performs DEM intersection.
166 //---
168  ossimGpt& worldPoint) const
169 {
170  if(!imagePoint.hasNans())
171  {
172  ossimEcefRay ray;
173 
174  //---
175  // Note:
176  // RSM (0,0) is upper left corner of pixel(0,0). OSSIM (0,0) is
177  // center of the pixel; hence, the + 0.5. (drb 22 May 2015)
178  //---
179  // imagingRay(imagePoint, ray);
180  imagingRay(ossimDpt(imagePoint.x+0.5, imagePoint.y+0.5), ray);
181  ossimElevManager::instance()->intersectRay(ray, worldPoint);
182  }
183  else
184  {
185  worldPoint.makeNan();
186  }
187 }
188 
189 //---
190 // METHOD: ossimRsmModel::lineSampleHeightToWorld()
191 //
192 // Performs reverse projection of image line/sample to ground point.
193 // The imaging ray is intersected with a level plane at height = elev.
194 //
195 // NOTE: U = line, V = sample -- this differs from the convention.
196 //
197 //---
199  const double& ellHeight,
200  ossimGpt& gpt) const
201 {
202  // Borrowed from ossimRpcModel algorithm to converge on polynomial roots
203 
204  //---
205  // Constants for convergence tests:
206  //---
207  // SPEC says 1/20 of a pixel for polynomial fit, so converge to at least that point
208  static const int MAX_NUM_ITERATIONS = 100;
209  static const double CONVERGENCE_EPSILON = 0.05; // pixels
210 
211  ossim_uint32 pcaIndex = getPcaIndex( image_point, true );
212 
213  // Image point of 0 to ossim is 0.5 to RSM.
214  // double U = (image_point.y-m_rnrmo) / (m_rnrmsf);
215  // double V = (image_point.x-m_cnrmo) / (m_cnrmsf);
216 
217  double U = (image_point.y+0.5-m_pca[pcaIndex].m_rnrmo) / (m_pca[pcaIndex].m_rnrmsf);
218  double V = (image_point.x+0.5-m_pca[pcaIndex].m_cnrmo) / (m_pca[pcaIndex].m_cnrmsf);
219 
220  //---
221  // Initialize quantities to be used in the iteration for ground point:
222  //---
223  double nlat = 0.0; // normalized latitude
224  double nlon = 0.0; // normalized longitude
225  double nhgt;
226 
227  if(ossim::isnan(ellHeight))
228  {
229  nhgt = (- m_pca[pcaIndex].m_znrmo) / m_pca[pcaIndex].m_znrmsf; // norm height
230  }
231  else
232  {
233  nhgt = (ellHeight - m_pca[pcaIndex].m_znrmo) / m_pca[pcaIndex].m_znrmsf; // norm height
234  }
235 
236  double epsilonU = CONVERGENCE_EPSILON/m_pca[pcaIndex].m_rnrmsf;
237  double epsilonV = CONVERGENCE_EPSILON/m_pca[pcaIndex].m_cnrmsf;
238  int iteration = 0;
239  //---
240  // Declare variables only once outside the loop. These include:
241  // * polynomials (numerators Pu, Pv, and denominators Qu, Qv),
242  // * partial derivatives of polynomials wrt X, Y,
243  // * computed normalized image point: Uc, Vc,
244  // * residuals of normalized image point: deltaU, deltaV,
245  // * partial derivatives of Uc and Vc wrt X, Y,
246  // * corrections to normalized lat, lon: deltaLat, deltaLon.
247  //---
248  double Pu, Qu, Pv, Qv;
249  double dPu_dLat, dQu_dLat, dPv_dLat, dQv_dLat;
250  double dPu_dLon, dQu_dLon, dPv_dLon, dQv_dLon;
251  double Uc, Vc;
252  double deltaU, deltaV;
253  double dU_dLat, dU_dLon, dV_dLat, dV_dLon, W;
254  double deltaLat, deltaLon;
255 
256  //---
257  // Now iterate until the computed Uc, Vc is within epsilon of the desired
258  // image point U, V:
259  //---
260  do
261  {
262  //---
263  // Calculate the normalized line and sample Uc, Vc as ratio of
264  // polynomials Pu, Qu and Pv, Qv:
265  //---
266  Pu = polynomial(nlon, nlat, nhgt, m_pca[pcaIndex].m_rnpwrx, m_pca[pcaIndex].m_rnpwry, m_pca[pcaIndex].m_rnpwrz, m_pca[pcaIndex].m_rnpcf);
267  Qu = polynomial(nlon, nlat, nhgt, m_pca[pcaIndex].m_rdpwrx, m_pca[pcaIndex].m_rdpwry, m_pca[pcaIndex].m_rdpwrz, m_pca[pcaIndex].m_rdpcf);
268  Pv = polynomial(nlon, nlat, nhgt, m_pca[pcaIndex].m_cnpwrx, m_pca[pcaIndex].m_cnpwry, m_pca[pcaIndex].m_cnpwrz, m_pca[pcaIndex].m_cnpcf);
269  Qv = polynomial(nlon, nlat, nhgt, m_pca[pcaIndex].m_cdpwrx, m_pca[pcaIndex].m_cdpwry, m_pca[pcaIndex].m_cdpwrz, m_pca[pcaIndex].m_cdpcf);
270  Uc = Pu/Qu;
271  Vc = Pv/Qv;
272 
273  //---
274  // Compute residuals between desired and computed line, sample:
275  //---
276  deltaU = U - Uc;
277  deltaV = V - Vc;
278 
279  //---
280  // Check for convergence and skip re-linearization if converged:
281  //---
282  if ((fabs(deltaU) > epsilonU) || (fabs(deltaV) > epsilonV))
283  {
284  //---
285  // Analytically compute the partials of each polynomial wrt lat, lon:
286  //---
287  dPu_dLat = dPoly_dLat(nlon, nlat, nhgt, m_pca[pcaIndex].m_rnpwrx, m_pca[pcaIndex].m_rnpwry, m_pca[pcaIndex].m_rnpwrz, m_pca[pcaIndex].m_rnpcf);
288  dQu_dLat = dPoly_dLat(nlon, nlat, nhgt, m_pca[pcaIndex].m_rdpwrx, m_pca[pcaIndex].m_rdpwry, m_pca[pcaIndex].m_rdpwrz, m_pca[pcaIndex].m_rdpcf);
289  dPv_dLat = dPoly_dLat(nlon, nlat, nhgt, m_pca[pcaIndex].m_cnpwrx, m_pca[pcaIndex].m_cnpwry, m_pca[pcaIndex].m_cnpwrz, m_pca[pcaIndex].m_cnpcf);
290  dQv_dLat = dPoly_dLat(nlon, nlat, nhgt, m_pca[pcaIndex].m_cdpwrx, m_pca[pcaIndex].m_cdpwry, m_pca[pcaIndex].m_cdpwrz, m_pca[pcaIndex].m_cdpcf);
291  dPu_dLon = dPoly_dLon(nlon, nlat, nhgt, m_pca[pcaIndex].m_rnpwrx, m_pca[pcaIndex].m_rnpwry, m_pca[pcaIndex].m_rnpwrz, m_pca[pcaIndex].m_rnpcf);
292  dQu_dLon = dPoly_dLon(nlon, nlat, nhgt, m_pca[pcaIndex].m_rdpwrx, m_pca[pcaIndex].m_rdpwry, m_pca[pcaIndex].m_rdpwrz, m_pca[pcaIndex].m_rdpcf);
293  dPv_dLon = dPoly_dLon(nlon, nlat, nhgt, m_pca[pcaIndex].m_cnpwrx, m_pca[pcaIndex].m_cnpwry, m_pca[pcaIndex].m_cnpwrz, m_pca[pcaIndex].m_cnpcf);
294  dQv_dLon = dPoly_dLon(nlon, nlat, nhgt, m_pca[pcaIndex].m_cdpwrx, m_pca[pcaIndex].m_cdpwry, m_pca[pcaIndex].m_cdpwrz, m_pca[pcaIndex].m_cdpcf);
295 
296  //---
297  // Analytically compute partials of quotients U and V wrt lat, lon:
298  //---
299  dU_dLat = (Qu*dPu_dLat - Pu*dQu_dLat)/(Qu*Qu);
300  dU_dLon = (Qu*dPu_dLon - Pu*dQu_dLon)/(Qu*Qu);
301  dV_dLat = (Qv*dPv_dLat - Pv*dQv_dLat)/(Qv*Qv);
302  dV_dLon = (Qv*dPv_dLon - Pv*dQv_dLon)/(Qv*Qv);
303 
304  W = dU_dLon*dV_dLat - dU_dLat*dV_dLon;
305 
306  //---
307  // Now compute the corrections to normalized lat, lon:
308  //---
309  deltaLat = (dU_dLon*deltaV - dV_dLon*deltaU) / W;
310  deltaLon = (dV_dLat*deltaU - dU_dLat*deltaV) / W;
311  nlat += deltaLat;
312  nlon += deltaLon;
313  }
314 
315  ++iteration;
316 
317  } while (((fabs(deltaU)>epsilonU) || (fabs(deltaV)>epsilonV))
318  && (iteration < MAX_NUM_ITERATIONS));
319  //---
320  // Test for exceeding allowed number of iterations. Flag error if so:
321  //---
322  if (iteration == MAX_NUM_ITERATIONS)
323  {
325  << "WARNING ossimRsmModel::lineSampleHeightToWorld:\n"
326  << "Max number of iterations reached in ground point "
327  << "solution. Results are inaccurate." << endl;
328  }
329 
330  //---
331  // Now un-normalize the ground point lat, lon and establish return quantity:
332  //
333  // lon will 0 to 2PI when image is near PI radians as specified in RSMIDA
334  // GRNDD field when value is "H" versus "G". OSSIMGPT wrap handles this
335  // automatically, so no need to worry about it.
336  //---
337  gpt.lat = ossim::radiansToDegrees(nlat*m_pca[pcaIndex].m_ynrmsf + m_pca[pcaIndex].m_ynrmo);
338  gpt.lon = ossim::radiansToDegrees(nlon*m_pca[pcaIndex].m_xnrmsf + m_pca[pcaIndex].m_xnrmo);
339  gpt.hgt = (nhgt * m_pca[pcaIndex].m_znrmsf) + m_pca[pcaIndex].m_znrmo; //ellHeight;
340 
341  //---
342  // Note: See above note. Added in wrap call. Longitude was coming out 242
343  // when should have been -118. (drb - 22 May 2015)
344  //---
345  gpt.wrap();
346 
347 } // End: ossimRsmModel::lineSampleHeightToWorld( ... )
348 
349 //---
350 // METHOD: ossimRsmModel::imagingRay()
351 //
352 // Constructs a ray by intersecting 2 ellipsoid heights above and
353 // below the RPC height offset, and then forming a vector between the two.
354 //
355 //---
356 void ossimRsmModel::imagingRay(const ossimDpt& imagePoint,
357  ossimEcefRay& imageRay) const
358 {
359  ossim_uint32 pcaIndex = getPcaIndex( imagePoint, true );
360 
361  //---
362  // For "from point", "to point" we want the image ray to be from above the
363  // ellipsoid down to Earth.
364  //
365  // It appears the ray "from point" must be above the ellipsiod for the
366  // ossimElevSource::intersectRay method; ultimately, the
367  // ossimEllipsoid::nearestIntersection method, else it goes off in the
368  // weeds...
369  //---
370  double vectorLength = m_pca[pcaIndex].m_znrmsf * 2.0;
371 
372  ossimGpt gpt;
373 
374  // "from" point
375  double intHgt = m_pca[pcaIndex].m_znrmo + vectorLength;
376  lineSampleHeightToWorld(imagePoint, intHgt, gpt);
377  ossimEcefPoint intECFfrom(gpt);
378 
379  // "to" point
380  lineSampleHeightToWorld(imagePoint, m_pca[pcaIndex].m_znrmo, gpt);
381  ossimEcefPoint intECFto(gpt);
382 
383  // Construct ray
384  ossimEcefRay ray(intECFfrom, intECFto);
385 
386  imageRay = ray;
387 }
388 
390 {
391 }
392 
394 {
395 }
396 
398 {
399  return new ossimRsmModel(*this);
400 }
401 
402 //---
403 // METHOD: ossimRsmModel::print()
404 //
405 // Formatted dump of data members.
406 //---
408 {
409  std::string prefix = "";
410  ossimKeywordlist kwl;
411  saveState( kwl, prefix.c_str() );
412  out << kwl;
413  return out;
414 }
415 
417  const char* prefix) const
418 {
419  static const char MODULE[] = "ossimRsmModel::saveState";
420  if (traceExec())
421  {
422  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
423  }
424 
425  kwl.add(prefix, ossimKeywordNames::TYPE_KW, MODEL_TYPE_KW.c_str());
426 
427  //---
428  // Hand off to base class for common stuff:
429  //---
430  ossimSensorModel::saveState(kwl, prefix);
431 
432  std::string pfx = (prefix ? prefix : "" );
433 
434  // IDA:
435  m_ida.saveState( kwl, prefix );
436 
437  // PIA:
438  m_pia.saveState( kwl, prefix );
439 
440  // PCA:
441  for ( ossim_uint32 i = 0; i < m_pca.size(); ++i )
442  {
443  m_pca[i].saveState( kwl, pfx, i );
444  }
445 
446  if (traceExec())
447  {
448  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " exited...\n";
449  }
450 
451  return true;
452 }
453 
455  const char* prefix)
456 {
457  static const char MODULE[] = "ossimRsmModel::loadState";
458  if (traceExec())
459  {
460  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
461  }
462 
463  bool status = false;
464 
465  // Check for type match before preceeding:
466  std::string pfx = ( prefix ? prefix : "" );
467  std::string type = kwl.findKey( pfx, std::string(ossimKeywordNames::TYPE_KW) );
468  if ( (type == "ossimNitfRsmModel" ) || ( type == MODEL_TYPE_KW ) )
469  {
470  // Pass on to the base-class for parsing first:
471  if ( ossimSensorModel::loadState(kwl, prefix) )
472  {
473  if ( m_ida.loadState( kwl, pfx ) )
474  {
475  if ( m_pia.loadState( kwl, pfx ) )
476  {
477  m_pca.clear();
478 
479  for ( ossim_uint32 tagIndex = 0; tagIndex < m_pia.m_tnis; ++tagIndex )
480  {
481  ossimRsmpca pca;
482  if ( pca.loadState( kwl, pfx, tagIndex ) )
483  {
484  m_pca.push_back( pca );
485  }
486  else
487  {
489  << "WARNING! RSMPCA[" << tagIndex << "] intitialization failed!"
490  << std::endl;
491  break; // Get out...
492  }
493  }
494 
495  // Should now have a rsmpca record for each segment.
496  if ( m_pia.m_tnis == (ossim_uint32)m_pca.size() )
497  {
498  // Set the status for downstream code.
499  status = true;
500 
501  updateModel();
502  }
503 
504  } // Matches: if ( m_pia.loadState( kwl, pfx ) )
505 
506  } // Matches:if ( m_ida.loadState( kwl, pfx ) )
507 
508  } // Matches: if ( ossimSensorModel::loadState(kwl, prefix) )
509 
510  } // Matches: if ( (type == "ossimNitfRsmModel" ) || ...
511 
512  if (traceExec())
513  {
515  << MODULE << " exit status = " << (status?"true":"false") << "\n";
516  }
517 
518  return status;
519 }
520 
522  const double& x, const double& y, const double& z) const
523 {
524  ossimDpt ipt;
525  lowOrderPolynomial( x, y, z, ipt );
526  return getPcaIndex( ipt, false );
527 }
528 
529 ossim_uint32 ossimRsmModel::getPcaIndex( const ossimDpt& ipt, bool shiftPoint ) const
530 {
531  //---
532  // RSM (0,0) is upper left corner of pixel(0,0). OSSIM (0,0) is
533  // center of the pixel; hence, the shift 0.5 if coming from ossim.
534  //---
535  double shift = shiftPoint ? 0.5 : 0.0;
536 
537  // Row section number:
538  double rsn = std::floor( ( ipt.y + shift - (double)(m_ida.m_minr) ) /
539  (double)(m_pia.m_rssiz) );
540  if ( rsn < 0.0 )
541  {
542  rsn = 0.0;
543  }
544  else if ( rsn > (m_pia.m_rnis-1) )
545  {
546  rsn = m_pia.m_rnis-1;
547  }
548  // Column section number:
549  double csn = std::floor( ( ipt.x + shift - (double)(m_ida.m_minc) ) / (double)(m_pia.m_cssiz) );
550  if ( csn < 0.0 )
551  {
552  csn = 0.0;
553  }
554  else if ( csn > (m_pia.m_cnis-1) )
555  {
556  csn = m_pia.m_cnis-1;
557  }
558 
559  //return static_cast<ossim_uint32>(rsn) * m_pia.m_rnis + static_cast<ossim_uint32>(csn);
560  return static_cast<ossim_uint32>(rsn) * m_pia.m_cnis + static_cast<ossim_uint32>(csn);
561 }
562 
564  const double& x, const double& y, const double& z, ossimDpt& ipt ) const
565 {
566  ipt.y = m_pia.m_r0 + m_pia.m_rx * x + m_pia.m_ry * y + m_pia.m_rz * z +
567  m_pia.m_rxx * x * x + m_pia.m_rxy * x * y + m_pia.m_rxz * x * z +
568  m_pia.m_ryy * y * y + m_pia.m_ryz * y * z + m_pia.m_rzz * z * z;
569 
570  ipt.x = m_pia.m_c0 + m_pia.m_cx * x + m_pia.m_cy * y + m_pia.m_cz * z +
571  m_pia.m_cxx * x * x + m_pia.m_cxy * x * y + m_pia.m_cxz * x * z +
572  m_pia.m_cyy * y * y + m_pia.m_cyz * y * z + m_pia.m_czz * z * z;
573 }
574 
576  const double& x, const double& y, const double& z, const ossim_uint32& maxx,
577  const ossim_uint32& maxy, const ossim_uint32& maxz, std::vector<double> pcf) const
578 {
579  double r = 0.0;
580  ossim_uint32 index = 0;
581  for (ossim_uint32 k = 0; k <= maxz; ++k)
582  {
583  for (ossim_uint32 j = 0; j <= maxy; ++j)
584  {
585  for (ossim_uint32 i = 0; i <= maxx; ++i)
586  {
587  r+=pcf[index]*std::pow(x,(double)i)*std::pow(y,(double)j)*std::pow(z,(double)k);
588  ++index;
589  }
590  }
591  }
592  return r;
593 }
594 
596  const double& x, const double& y, const double& z, const ossim_uint32& maxx,
597  const ossim_uint32& maxy, const ossim_uint32& maxz, std::vector<double> pcf) const
598 
599 {
600  double dr = 0.0;
601  ossim_uint32 index = 0;
602  for (ossim_uint32 k = 0; k <= maxz; ++k)
603  {
604  for (ossim_uint32 j = 0; j <= maxy; ++j)
605  {
606  for (ossim_uint32 i = 0; i <= maxx; ++i)
607  {
608  if (j>0)
609  {
610  dr+=j*pcf[index]*std::pow(x,(double)i)*std::pow(y,(double)(j-1))*std::pow(z,(double)k);
611  }
612  ++index;
613  }
614  }
615  }
616  return dr;
617 }
618 
620  const double& x, const double& y, const double& z, const ossim_uint32& maxx,
621  const ossim_uint32& maxy, const ossim_uint32& maxz, std::vector<double> pcf) const
622 {
623  double dr = 0.0;
624  ossim_uint32 index = 0;
625  for (ossim_uint32 k = 0; k <= maxz; ++k)
626  {
627  for (ossim_uint32 j = 0; j <= maxy; ++j)
628  {
629  for (ossim_uint32 i = 0; i <= maxx; ++i)
630  {
631  if (i>0)
632  {
633  dr += i*pcf[index]*std::pow(x,(double)(i-1)) *
634  std::pow(y,(double)j)*std::pow(z,(double)k);
635  }
636  ++index;
637  }
638  }
639  }
640  return dr;
641 }
642 
644  const double& x, const double& y, const double& z, const ossim_uint32& maxx,
645  const ossim_uint32& maxy, const ossim_uint32& maxz, std::vector<double> pcf) const
646 {
647  double dr = 0.0;
648  ossim_uint32 index = 0;
649  for (ossim_uint32 k = 0; k <= maxz; ++k)
650  {
651  for (ossim_uint32 j = 0; j <= maxy; ++j)
652  {
653  for (ossim_uint32 i = 0; i <= maxx; ++i)
654  {
655  if (k>0)
656  {
657  dr += k*pcf[index]*std::pow(x,(double)i) *
658  std::pow(y,(double)j)*std::pow(z,(double)(k-1));
659  }
660  ++index;
661  }
662  }
663  }
664  return dr;
665 }
666 
668 {
669  static const char MODULE[] = "ossimRsmModel::validate";
670 
671  bool status = true;
672 
673  if ( (m_pia.m_rnis == 0) || (m_pia.m_rnis == 0) || (m_pia.m_tnis == 0) )
674  {
675  status = false;
677  << MODULE
678  << " ERROR: rsmpia must have at least one section!" << std::endl;
679  }
680 
681  if ( m_pca.size() != m_pia.m_tnis )
682  {
683  status = false;
685  << MODULE
686  << " ERROR: rsmpca array not equal to section count!" << std::endl;
687  }
688  if ( ( m_ida.m_grndd != 'G' ) && ( m_ida.m_grndd != 'H' ) && ( m_ida.m_grndd != 'R' ) )
689  {
690  status = false;
692  << MODULE
693  << " ERROR: rsmida grndd Ground Domain Form not set!" << std::endl;
694  }
695  if ( m_ida.m_grndd == 'R' )
696  {
697  status = false;
699  << MODULE
700  << " ERROR: rsmida grndd Rectangular Ground Domain not supported!" << std::endl;
701  }
702  if ( m_pia.m_rssiz == 0 )
703  {
704  status = false; // divide by zero.
706  << MODULE
707  << " ERROR: rsmpia rrsiz Section row size cannot be zero!" << std::endl;
708  }
709  if ( m_pia.m_cssiz == 0 )
710  {
711  status = false; // divide by zero.
713  << MODULE
714  << " ERROR: rsmpia cssiz Section column size cannot be zero!" << std::endl;
715  }
716 
717  return status;
718 }
719 
720 
virtual void lineSampleHeightToWorld(const ossimDpt &image_point, const double &heightEllipsoid, ossimGpt &worldPoint) const
lineSampleHeightToWorld() Overrides base class pure virtual.
ossim_uint32 x
virtual void initAdjustableParameters()
virtual void updateModel()
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
bool validate() const
Performs sanity check on key/required rsm data.
double dPoly_dLat(const double &x, const double &y, const double &z, const ossim_uint32 &maxx, const ossim_uint32 &maxy, const ossim_uint32 &maxz, std::vector< double > pcf) const
virtual void imagingRay(const ossimDpt &image_point, ossimEcefRay &image_ray) const
imagingRay() Overrides base class pure virtual.
Represents serializable keyword/value map.
const std::string & findKey(const std::string &key) const
Find methods that take std::string(s).
bool isLonNan() const
Definition: ossimGpt.h:140
ossim_uint32 y
bool intersectRay(const ossimEcefRay &ray, ossimGpt &gpt, double defaultElevValue=0.0)
METHOD: intersectRay()
void saveState(ossimKeywordlist &kwl, const std::string &prefix) const
saveState Saves state to keyword list.
double samp
Definition: ossimDpt.h:164
ossim_float64 m_cy
Definition: ossimRsmpia.h:79
ossim_uint32 m_rnis
Definition: ossimRsmpia.h:90
const ossimRsmModel & operator=(const ossimRsmModel &rhs)
assignment operator
void lowOrderPolynomial(const double &x, const double &y, const double &z, ossimDpt &ipt) const
Gets index into RSM Polynomial Coefficients(rsmpca) container array for a given ground point...
double y
Definition: ossimDpt.h:165
double dPoly_dHgt(const double &x, const double &y, const double &z, const ossim_uint32 &maxx, const ossim_uint32 &maxy, const ossim_uint32 &maxz, std::vector< double > pcf) const
void makeNan()
Definition: ossimGpt.h:130
ossim_uint32 getPcaIndex(const double &x, const double &y, const double &z) const
Gets index into RSM Polynomial Coefficients(rsmpca) container array for a given ground point...
ossim_uint32 m_tnis
Definition: ossimRsmpia.h:92
virtual ~ossimRsmModel()
virtual destructor
ossim_float64 hgt
Height in meters above the ellipsiod.
Definition: ossimGpt.h:274
bool loadState(const ossimKeywordlist &kwl, const std::string &prefix, ossim_uint32 index)
loadState Loads state from keyword list.
double polynomial(const double &x, const double &y, const double &z, const ossim_uint32 &maxx, const ossim_uint32 &maxy, const ossim_uint32 &maxz, std::vector< double > pcf) const
static ossimElevManager * instance()
METHOD: instance() Implements singelton pattern.
ossim_uint32 m_minc
Definition: ossimRsmida.h:140
ossim_float64 m_cxy
Definition: ossimRsmpia.h:83
ossim_float64 m_rz
Definition: ossimRsmpia.h:67
void wrap()
Wrap method to maintain longitude between -180 and +180 and latitude between -90 and +90...
Definition: ossimGpt.h:305
bool isLatNan() const
Definition: ossimGpt.h:139
bool loadState(const ossimKeywordlist &kwl, const std::string &prefix)
loadState Loads state from keyword list.
static const char * TYPE_KW
bool isHgtNan() const
Definition: ossimGpt.h:143
ossim_float64 m_ryy
Definition: ossimRsmpia.h:73
double radiansToDegrees(double x)
Definition: ossimCommon.h:257
bool loadState(const ossimKeywordlist &kwl, const std::string &prefix)
loadState Loads state from keyword list.
const ossimSensorModel & operator=(const ossimSensorModel &rhs)
assignment operator
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
ossim_uint32 m_cssiz
Definition: ossimRsmpia.h:95
ossim_float64 m_cz
Definition: ossimRsmpia.h:80
ossim_float64 m_r0
Definition: ossimRsmpia.h:64
double line
Definition: ossimDpt.h:165
std::vector< ossimRsmpca > m_pca
ossim_float64 lon
Definition: ossimGpt.h:266
double degreesToRadians(double x)
Definition: ossimCommon.h:258
virtual ossimObject * dup() const
dup() Returns pointer to a new instance, copy of this.
double dPoly_dLon(const double &x, const double &y, const double &z, const ossim_uint32 &maxx, const ossim_uint32 &maxy, const ossim_uint32 &maxz, std::vector< double > pcf) const
ossim_float64 m_cxz
Definition: ossimRsmpia.h:84
unsigned int ossim_uint32
ossimRsmModel()
default constructor
virtual void lineSampleToWorld(const ossimDpt &image_point, ossimGpt &world_point) const
lineSampleToWorld() Overrides base class pure virtual.
void saveState(ossimKeywordlist &kwl, const std::string &prefix) const
saveState Saves state to keyword list.
ossim_float64 m_rzz
Definition: ossimRsmpia.h:75
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
bool hasNans() const
Definition: ossimDpt.h:67
ossim_uint32 m_rssiz
Definition: ossimRsmpia.h:94
ossim_float64 m_ry
Definition: ossimRsmpia.h:66
ossimRsmpia m_pia
virtual void worldToLineSample(const ossimGpt &world_point, ossimDpt &image_point) const
worldToLineSample() Overrides base class implementation.
virtual std::ostream & print(std::ostream &out) const
print() Extends base-class implementation.
return status
ossim_uint32 m_minr
Definition: ossimRsmida.h:138
ossim_float64 m_czz
Definition: ossimRsmpia.h:88
ossim_float64 m_cyy
Definition: ossimRsmpia.h:86
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
loadState Fulfills ossimObject base-class pure virtuals.
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
saveState Fulfills ossimObject base-class pure virtuals.
double x
Definition: ossimDpt.h:164
ossim_float64 m_rxx
Definition: ossimRsmpia.h:69
char m_grndd
Definition: ossimRsmida.h:81
ossim_float64 m_cx
Definition: ossimRsmpia.h:78
ossim_float64 lat
Definition: ossimGpt.h:265
ossim_float64 m_ryz
Definition: ossimRsmpia.h:74
ossimRsmida m_ida
ossim_float64 m_cxx
Definition: ossimRsmpia.h:82
ossim_uint32 m_cnis
Definition: ossimRsmpia.h:91
ossim_float64 m_rxy
Definition: ossimRsmpia.h:70
ossim_float64 m_c0
Definition: ossimRsmpia.h:77
ossim_float64 m_cyz
Definition: ossimRsmpia.h:87
ossim_float64 m_rxz
Definition: ossimRsmpia.h:71
ossim_float64 m_rx
Definition: ossimRsmpia.h:65
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
void makeNan()
Definition: ossimDpt.h:65
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
RTTI_DEF1(ossimRsmModel, "ossimRsmModel", ossimSensorModel)
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91