OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimRpcModel.cpp
Go to the documentation of this file.
1 //*****************************************************************************
2 // FILE: ossimRpcModel.cpp
3 //
4 // License: See top level LICENSE.txt file.
5 //
6 // AUTHOR: Oscar Kramer
7 //
8 // DESCRIPTION: Contains implementation of class ossimRpcModel.
9 // This is a replacement model utilizing the Rational Polynomial Coefficients
10 // (RPC), a.k.a. Rapid Positioning Capability, and Universal Sensor Model
11 // (USM).
12 //
13 // LIMITATIONS: Does not support parameter adjustment (YET)
14 //
15 //*****************************************************************************
16 // $Id: ossimRpcModel.cpp 23670 2015-12-18 22:33:12Z dburken $
17 
20 
21 RTTI_DEF1(ossimRpcModel, "ossimRpcModel", ossimSensorModel);
22 
24 #include <ossim/base/ossimGpt.h>
25 #include <ossim/base/ossimDpt.h>
26 #include <ossim/base/ossimDatum.h>
31 #include <ossim/base/ossimNotify.h>
32 #include <iostream>
33 #include <algorithm>
34 #include <iomanip>
35 #include <sstream>
37 
38 #if OSSIM_HAS_JSONCPP
39 #include <json/json.h>
40 #endif
41 
42 //***
43 // Define Trace flags for use within this file:
44 //***
45 #include <ossim/base/ossimTrace.h>
46 static ossimTrace traceExec ("ossimRpcModel:exec");
47 static ossimTrace traceDebug ("ossimRpcModel:debug");
48 
49 //static const int MODEL_VERSION_NUMBER = 1;
50 static const int NUM_COEFFS = 20;
51 static const char* MODEL_TYPE = "ossimRpcModel";
52 static const char* POLY_TYPE_KW = "polynomial_format";
53 static const char* LINE_SCALE_KW = "line_scale";
54 static const char* SAMP_SCALE_KW = "samp_scale";
55 static const char* LAT_SCALE_KW = "lat_scale";
56 static const char* LON_SCALE_KW = "long_scale";
57 static const char* HGT_SCALE_KW = "height_scale";
58 static const char* LINE_OFFSET_KW = "line_off";
59 static const char* SAMP_OFFSET_KW = "samp_off";
60 static const char* LAT_OFFSET_KW = "lat_off";
61 static const char* LON_OFFSET_KW = "long_off";
62 static const char* HGT_OFFSET_KW = "height_off";
63 
64 static const char* BIAS_ERROR_KW = "bias_error";
65 static const char* RAND_ERROR_KW = "rand_error";
66 
67 static const char* LINE_NUM_COEF_KW = "line_num_coeff_";
68 static const char* LINE_DEN_COEF_KW = "line_den_coeff_";
69 static const char* SAMP_NUM_COEF_KW = "samp_num_coeff_";
70 static const char* SAMP_DEN_COEF_KW = "samp_den_coeff_";
71 
72 static const ossimString PARAM_NAMES[] ={"intrack_offset",
73  "crtrack_offset",
74  "intrack_scale",
75  "crtrack_scale",
76  "map_rotation",
77  "yaw_offset"};
78 static const ossimString PARAM_UNITS[] ={"pixel",
79  "pixel",
80  "scale",
81  "scale",
82  "degrees",
83  "degrees"};
84 
85 //*****************************************************************************
86 // DEFAULT CONSTRUCTOR: ossimRpcModel()
87 //
88 //*****************************************************************************
90  : ossimSensorModel(),
91  thePolyType (A),
92  theLineScale (0.0),
93  theSampScale (0.0),
94  theLatScale (0.0),
95  theLonScale (0.0),
96  theHgtScale (0.0),
97  theLineOffset (0.0),
98  theSampOffset (0.0),
99  theLatOffset (0.0),
100  theLonOffset (0.0),
101  theHgtOffset (0.0),
102  theIntrackOffset(0.0),
103  theCrtrackOffset(0.0),
104  theIntrackScale (0.0),
105  theCrtrackScale (0.0),
106  theCosMapRot (1.0),
107  theSinMapRot (0.0),
108  theBiasError (0.0),
109  theRandError (0.0)
110 
111 {
113 }
114 
115 //*****************************************************************************
116 // COPY CONSTRUCTOR: ossimRpcModel(ossimRpcModel)
117 //
118 //*****************************************************************************
120  :
121  ossimSensorModel(model),
122  thePolyType (model.thePolyType),
123  theLineScale (model.theLineScale),
124  theSampScale (model.theSampScale),
125  theLatScale (model.theLatScale),
126  theLonScale (model.theLonScale),
127  theHgtScale (model.theHgtScale),
128  theLineOffset (model.theLineOffset),
129  theSampOffset (model.theSampOffset),
130  theLatOffset (model.theLatOffset),
131  theLonOffset (model.theLonOffset),
132  theHgtOffset (model.theHgtOffset),
133  theIntrackOffset(model.theIntrackOffset),
134  theCrtrackOffset(model.theCrtrackOffset),
135  theIntrackScale(model.theIntrackScale),
136  theCrtrackScale(model.theCrtrackScale),
137  theCosMapRot (model.theCosMapRot),
138  theSinMapRot (model.theSinMapRot),
139  theBiasError (model.theBiasError),
140  theRandError (model.theRandError)
141 {
142  for (int i=0; i<20; ++i )
143  {
144  theLineNumCoef[i] = model.theLineNumCoef[i];
145  theLineDenCoef[i] = model.theLineDenCoef[i];
146  theSampNumCoef[i] = model.theSampNumCoef[i];
147  theSampDenCoef[i] = model.theSampDenCoef[i];
148  }
149 }
150 
151 //*****************************************************************************
152 // DESTRUCTOR: ~ossimRpcModel()
153 //
154 //*****************************************************************************
156 {
157 }
158 
160  ossim_float64 lineOffset,
161  ossim_float64 sampleScale,
162  ossim_float64 lineScale,
163  ossim_float64 latOffset,
164  ossim_float64 lonOffset,
165  ossim_float64 heightOffset,
166  ossim_float64 latScale,
167  ossim_float64 lonScale,
168  ossim_float64 heightScale,
169  const std::vector<double>& xNumeratorCoeffs,
170  const std::vector<double>& xDenominatorCoeffs,
171  const std::vector<double>& yNumeratorCoeffs,
172  const std::vector<double>& yDenominatorCoeffs,
173  PolynomialType polyType,
174  bool computeGsdFlag)
175 {
176  thePolyType = polyType;
177 
178  theLineScale = lineScale;
179  theSampScale = sampleScale;
180  theLatScale = latScale;
181  theLonScale = lonScale;
182  theHgtScale = heightScale;
183  theLineOffset = lineOffset;
184  theSampOffset = sampleOffset;
185  theLatOffset = latOffset;
186  theLonOffset = lonOffset;
187  theHgtOffset = heightOffset;
188 
189  if(xNumeratorCoeffs.size() == 20)
190  {
191  std::copy(xNumeratorCoeffs.begin(),
192  xNumeratorCoeffs.end(),
194  }
195  if(xDenominatorCoeffs.size() == 20)
196  {
197  std::copy(xDenominatorCoeffs.begin(),
198  xDenominatorCoeffs.end(),
200  }
201  if(yNumeratorCoeffs.size() == 20)
202  {
203  std::copy(yNumeratorCoeffs.begin(),
204  yNumeratorCoeffs.end(),
206  }
207  if(yDenominatorCoeffs.size() == 20)
208  {
209  std::copy(yDenominatorCoeffs.begin(),
210  yDenominatorCoeffs.end(),
212  }
213 
214  if(computeGsdFlag)
215  {
216  try
217  {
218  // This will set theGSD and theMeanGSD. Method throws ossimException.
219  computeGsd();
220  }
221  catch (const ossimException& e)
222  {
223  if (traceDebug())
224  {
226  << "ossimRpcModel::setAttributes Caught Exception:\n"
227  << e.what() << std::endl;
228  }
229  }
230  }
231 }
232 
233 void ossimRpcModel::setMetersPerPixel(const ossimDpt& metersPerPixel)
234 {
235  theGSD = metersPerPixel;
236  theMeanGSD = (theGSD.x+theGSD.y)*.5;
237 }
238 
240  const ossim_float64& randomError,
241  bool initNominalPostionErrorFlag)
242 {
243  theBiasError = biasError;
244  theRandError = randomError;
245  if (initNominalPostionErrorFlag)
246  {
248  theRandError*theRandError); // meters
249  }
250 }
251 
252 //*****************************************************************************
253 // METHOD: ossimRpcModel::worldToLineSample()
254 //
255 // Overrides base class implementation. Directly computes line-sample from
256 // the polynomials.
257 //*****************************************************************************
259  ossimDpt& img_pt) const
260 {
261  // if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimRpcModel::worldToLineSample(): entering..." << std::endl;
262 
263  if(ground_point.isLatNan() || ground_point.isLonNan() )
264  {
265  img_pt.makeNan();
266  return;
267  }
268 
269  //***
270  // First check if the world point is inside bounding rectangle:
271  //***
272  //ossimDpt wdp (ground_point);
273  //if (!(theBoundGndPolygon.pointWithin(ground_point)))
274  // {
275  //img_pt = extrapolate(ground_point);
276  //if (traceExec()) CLOG << "returning..." << endl;
277  // img_pt.makeNan();
278  // return;
279  // }
280 
281  //***
282  // Normalize the lat, lon, hgt:
283  //***
284  double nlat = (ground_point.lat - theLatOffset) / theLatScale;
285  double nlon = (ground_point.lon - theLonOffset) / theLonScale;
286  double nhgt;
287 
288  if( ground_point.isHgtNan() )
289  {
290  // nhgt = (theHgtScale - theHgtOffset) / theHgtScale;
291  nhgt = ( - theHgtOffset) / theHgtScale;
292  }
293  else
294  {
295  nhgt = (ground_point.hgt - theHgtOffset) / theHgtScale;
296  }
297 
298  //***
299  // Compute the adjusted, normalized line (U) and sample (V):
300  //***
301  double Pu = polynomial(nlat, nlon, nhgt, theLineNumCoef);
302  double Qu = polynomial(nlat, nlon, nhgt, theLineDenCoef);
303  double Pv = polynomial(nlat, nlon, nhgt, theSampNumCoef);
304  double Qv = polynomial(nlat, nlon, nhgt, theSampDenCoef);
305  double U_rot = Pu / Qu;
306  double V_rot = Pv / Qv;
307 
308  //***
309  // U, V are normalized quantities. Need now to establish the image file
310  // line and sample. First, back out the adjustable parameter effects
311  // starting with rotation:
312  //***
313  double U = U_rot*theCosMapRot + V_rot*theSinMapRot;
314  double V = V_rot*theCosMapRot - U_rot*theSinMapRot;
315 
316  //***
317  // Now back out skew, scale, and offset adjustments:
318  //***
321 
322  // if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimRpcModel::worldToLineSample(): returning..." << std::endl;
323  return;
324 }
325 
326 //*****************************************************************************
327 // METHOD: ossimRpcModel::lineSampleToWorld()
328 //
329 // Overrides base class implementation. Performs DEM intersection.
330 //*****************************************************************************
332  ossimGpt& worldPoint) const
333 {
334 //---
335 // Under debate... (drb 20130610)
336 // this seems to be more accurate for the round trip
337 //---
338 #if 0
339  if(!imagePoint.hasNans())
340  {
341 
342  lineSampleHeightToWorld(imagePoint,
343  worldPoint.height(),
344  worldPoint);
345  }
346  else
347  {
348  worldPoint.makeNan();
349  }
350 #else
351  if(!imagePoint.hasNans())
352  {
353  ossimEcefRay ray;
354  imagingRay(imagePoint, ray);
355  ossimElevManager::instance()->intersectRay(ray, worldPoint);
356  }
357  else
358  {
359  worldPoint.makeNan();
360  }
361 #endif
362 }
363 
364 //*****************************************************************************
365 // METHOD: ossimRpcModel::imagingRay()
366 //
367 // Constructs an RPC ray by intersecting 2 ellipsoid heights above and
368 // below the RPC height offset, and then forming a vector between the two.
369 //
370 //*****************************************************************************
371 void ossimRpcModel::imagingRay(const ossimDpt& imagePoint,
372  ossimEcefRay& imageRay) const
373 {
374  //---
375  // For "from point", "to point" we want the image ray to be from above the
376  // ellipsoid down to Earth.
377  //
378  // It appears the ray "from point" must be above the ellipsiod for the
379  // ossimElevSource::intersectRay method; ultimately, the
380  // ossimEllipsoid::nearestIntersection method, else it goes off in the
381  // weeds...
382  //---
383 
384 // this one is messed up so keep as #if 0 untill tested more
385  #if 0
386 
387  ossimGpt gpt;
388 
389  lineSampleHeightToWorld(imagePoint, theHgtOffset, gpt);
390 
391  //lineSampleHeightToWorld(imagePoint, ossim::nan(), gpt);
392 
393  ossimEcefVector v;
394  if(gpt.datum())
395  {
396  if(gpt.datum()->ellipsoid())
397  {
398  gpt.datum()->ellipsoid()->gradient(ossimEcefPoint(gpt), v);
399 
400  v = v.unitVector();
401 
402  ossimEcefPoint intECFto(gpt);
403  ossimEcefPoint intECFfrom = (intECFto + v*100000);
404 
405  ossimEcefRay ray(intECFfrom, intECFto);
406 
407  imageRay = ray;
408  }
409  }
410 #else
411  double vectorLength = theHgtScale ? (theHgtScale * 2.0) : 1000.0;
412 
413  ossimGpt gpt;
414 
415  // "from" point
416  double intHgt = theHgtOffset + vectorLength;
417  lineSampleHeightToWorld(imagePoint, intHgt, gpt);
418  ossimEcefPoint intECFfrom(gpt);
419 
420  // "to" point
421  lineSampleHeightToWorld(imagePoint, theHgtOffset, gpt);
422  ossimEcefPoint intECFto(gpt);
423 
424  // Construct ray
425  ossimEcefRay ray(intECFfrom, intECFto);
426 
427  imageRay = ray;
428 
429  #endif
430 }
431 
432 
433 //*****************************************************************************
434 // METHOD: ossimRpcModel::lineSampleHeightToWorld()
435 //
436 // Performs reverse projection of image line/sample to ground point.
437 // The imaging ray is intersected with a level plane at height = elev.
438 //
439 // NOTE: U = line, V = sample -- this differs from the convention.
440 //
441 //*****************************************************************************
443  const double& ellHeight,
444  ossimGpt& gpt) const
445 {
446  // if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG)
447  // << "DEBUG ossimRpcModel::lineSampleHeightToWorld: entering..." << std::endl;
448 
449  //---
450  // Removed below "gpt.makeNan()" if outside of image. This was put in
451  // troubleshooting dateline wrap issues. Returned nans are also
452  // causing issues so commenting out. drb - 17 Dec. 2015
453  //---
454 
455  //***
456  // Extrapolate if point is outside image:
457  //***
458  // if (!insideImage(image_point))
459  // {
460  // gpt = extrapolate(image_point, ellHeight);
461  // if (traceExec()) CLOG << "returning..." << endl;
462  // return;
463  // }
464 
465  //***
466  // Constants for convergence tests:
467  //***
468  static const int MAX_NUM_ITERATIONS = 10;
469  static const double CONVERGENCE_EPSILON = 0.1; // pixels
470 
471  //***
472  // The image point must be adjusted by the adjustable parameters as well
473  // as the scale and offsets given as part of the RPC param normalization.
474  //
475  // NOTE: U = line, V = sample
476  //***
477  double U = (image_point.y-theLineOffset - theIntrackOffset) / (theLineScale+theIntrackScale);
478  double V = (image_point.x-theSampOffset - theCrtrackOffset) / (theSampScale+theCrtrackScale);
479 
480  //***
481  // Rotate the normalized U, V by the map rotation error (adjustable param):
482  //***
483  double U_rot = theCosMapRot*U - theSinMapRot*V;
484  double V_rot = theSinMapRot*U + theCosMapRot*V;
485  U = U_rot; V = V_rot;
486 
487 
488  // now apply adjust intrack and cross track
489  //***
490  // Initialize quantities to be used in the iteration for ground point:
491  //***
492  double nlat = 0.0; // normalized latitude
493  double nlon = 0.0; // normalized longitude
494 
495  double nhgt;
496 
497  if(ossim::isnan(ellHeight))
498  {
499  nhgt = (theHgtScale - theHgtOffset) / theHgtScale; // norm height
500  }
501  else
502  {
503  nhgt = (ellHeight - theHgtOffset) / theHgtScale; // norm height
504  }
505 
506  double epsilonU = CONVERGENCE_EPSILON/(theLineScale+theIntrackScale);
507  double epsilonV = CONVERGENCE_EPSILON/(theSampScale+theCrtrackScale);
508  int iteration = 0;
509 
510  //***
511  // Declare variables only once outside the loop. These include:
512  // * polynomials (numerators Pu, Pv, and denominators Qu, Qv),
513  // * partial derivatives of polynomials wrt X, Y,
514  // * computed normalized image point: Uc, Vc,
515  // * residuals of normalized image point: deltaU, deltaV,
516  // * partial derivatives of Uc and Vc wrt X, Y,
517  // * corrections to normalized lat, lon: deltaLat, deltaLon.
518  //***
519  double Pu, Qu, Pv, Qv;
520  double dPu_dLat, dQu_dLat, dPv_dLat, dQv_dLat;
521  double dPu_dLon, dQu_dLon, dPv_dLon, dQv_dLon;
522  double Uc, Vc;
523  double deltaU, deltaV;
524  double dU_dLat, dU_dLon, dV_dLat, dV_dLon, W;
525  double deltaLat, deltaLon;
526 
527  //***
528  // Now iterate until the computed Uc, Vc is within epsilon of the desired
529  // image point U, V:
530  //***
531  do
532  {
533  //***
534  // Calculate the normalized line and sample Uc, Vc as ratio of
535  // polynomials Pu, Qu and Pv, Qv:
536  //***
537  Pu = polynomial(nlat, nlon, nhgt, theLineNumCoef);
538  Qu = polynomial(nlat, nlon, nhgt, theLineDenCoef);
539  Pv = polynomial(nlat, nlon, nhgt, theSampNumCoef);
540  Qv = polynomial(nlat, nlon, nhgt, theSampDenCoef);
541  Uc = Pu/Qu;
542  Vc = Pv/Qv;
543 
544  //***
545  // Compute residuals between desired and computed line, sample:
546  //***
547  deltaU = U - Uc;
548  deltaV = V - Vc;
549 
550  //***
551  // Check for convergence and skip re-linearization if converged:
552  //***
553  if ((fabs(deltaU) > epsilonU) || (fabs(deltaV) > epsilonV))
554  {
555  //***
556  // Analytically compute the partials of each polynomial wrt lat, lon:
557  //***
558  dPu_dLat = dPoly_dLat(nlat, nlon, nhgt, theLineNumCoef);
559  dQu_dLat = dPoly_dLat(nlat, nlon, nhgt, theLineDenCoef);
560  dPv_dLat = dPoly_dLat(nlat, nlon, nhgt, theSampNumCoef);
561  dQv_dLat = dPoly_dLat(nlat, nlon, nhgt, theSampDenCoef);
562  dPu_dLon = dPoly_dLon(nlat, nlon, nhgt, theLineNumCoef);
563  dQu_dLon = dPoly_dLon(nlat, nlon, nhgt, theLineDenCoef);
564  dPv_dLon = dPoly_dLon(nlat, nlon, nhgt, theSampNumCoef);
565  dQv_dLon = dPoly_dLon(nlat, nlon, nhgt, theSampDenCoef);
566 
567  //***
568  // Analytically compute partials of quotients U and V wrt lat, lon:
569  //***
570  dU_dLat = (Qu*dPu_dLat - Pu*dQu_dLat)/(Qu*Qu);
571  dU_dLon = (Qu*dPu_dLon - Pu*dQu_dLon)/(Qu*Qu);
572  dV_dLat = (Qv*dPv_dLat - Pv*dQv_dLat)/(Qv*Qv);
573  dV_dLon = (Qv*dPv_dLon - Pv*dQv_dLon)/(Qv*Qv);
574 
575  W = dU_dLon*dV_dLat - dU_dLat*dV_dLon;
576 
577  //***
578  // Now compute the corrections to normalized lat, lon:
579  //***
580  deltaLat = (dU_dLon*deltaV - dV_dLon*deltaU) / W;
581  deltaLon = (dV_dLat*deltaU - dU_dLat*deltaV) / W;
582  nlat += deltaLat;
583  nlon += deltaLon;
584  }
585 
586  //double h = ossimElevManager::instance()->getHeightAboveEllipsoid(ossimGpt(nlat, nlon));
587  // if(!ossim::isnan(h))
588  // {
589  // nhgt = h;
590  // }
591 
592  iteration++;
593 
594  } while (((fabs(deltaU)>epsilonU) || (fabs(deltaV)>epsilonV))
595  && (iteration < MAX_NUM_ITERATIONS));
596 
597  //***
598  // Test for exceeding allowed number of iterations. Flag error if so:
599  //***
600  if (iteration == MAX_NUM_ITERATIONS)
601  {
602  ossimNotify(ossimNotifyLevel_WARN) << "WARNING ossimRpcModel::lineSampleHeightToWorld: \nMax number of iterations reached in ground point "
603  << "solution. Results are inaccurate." << endl;
604  }
605 
606  //***
607  // Now un-normalize the ground point lat, lon and establish return quantity:
608  //***
609  gpt.lat = nlat*theLatScale + theLatOffset;
610  gpt.lon = nlon*theLonScale + theLonOffset;
611  gpt.hgt = ellHeight;
612 
613 }
614 
615 //*****************************************************************************
616 // PRIVATE METHOD: ossimRpcModel::polynomial
617 //
618 // Computes polynomial.
619 //
620 //*****************************************************************************
621 double ossimRpcModel::polynomial(const double& P, const double& L,
622  const double& H, const double* c) const
623 {
624  double r;
625 
626  if (thePolyType == A)
627  {
628  r = c[ 0] + c[ 1]*L + c[ 2]*P + c[ 3]*H +
629  c[ 4]*L*P + c[ 5]*L*H + c[ 6]*P*H + c[ 7]*L*P*H +
630  c[ 8]*L*L + c[ 9]*P*P + c[10]*H*H + c[11]*L*L*L +
631  c[12]*L*L*P + c[13]*L*L*H + c[14]*L*P*P + c[15]*P*P*P +
632  c[16]*P*P*H + c[17]*L*H*H + c[18]*P*H*H + c[19]*H*H*H;
633  }
634  else
635  {
636  r = c[ 0] + c[ 1]*L + c[ 2]*P + c[ 3]*H +
637  c[ 4]*L*P + c[ 5]*L*H + c[ 6]*P*H + c[ 7]*L*L +
638  c[ 8]*P*P + c[ 9]*H*H + c[10]*L*P*H + c[11]*L*L*L +
639  c[12]*L*P*P + c[13]*L*H*H + c[14]*L*L*P + c[15]*P*P*P +
640  c[16]*P*H*H + c[17]*L*L*H + c[18]*P*P*H + c[19]*H*H*H;
641  }
642 
643  return r;
644 }
645 
646 //*****************************************************************************
647 // PRIVATE METHOD: ossimRpcModel::dPoly_dLat
648 //
649 // Computes derivative of polynomial wrt normalized Latitude P.
650 //
651 //*****************************************************************************
652 double ossimRpcModel::dPoly_dLat(const double& P, const double& L,
653  const double& H, const double* c) const
654 {
655  double dr;
656 
657  if (thePolyType == A)
658  {
659  dr = c[2] + c[4]*L + c[6]*H + c[7]*L*H + 2*c[9]*P + c[12]*L*L +
660  2*c[14]*L*P + 3*c[15]*P*P +2*c[16]*P*H + c[18]*H*H;
661  }
662  else
663  {
664  dr = c[2] + c[4]*L + c[6]*H + 2*c[8]*P + c[10]*L*H + 2*c[12]*L*P +
665  c[14]*L*L + 3*c[15]*P*P + c[16]*H*H + 2*c[18]*P*H;
666  }
667 
668  return dr;
669 }
670 
671 //*****************************************************************************
672 // PRIVATE METHOD: ossimRpcModel::dPoly_dLon
673 //
674 // Computes derivative of polynomial wrt normalized Longitude L.
675 //
676 //*****************************************************************************
677 double ossimRpcModel::dPoly_dLon(const double& P, const double& L,
678  const double& H, const double* c) const
679 {
680  double dr;
681 
682  if (thePolyType == A)
683  {
684  dr = c[1] + c[4]*P + c[5]*H + c[7]*P*H + 2*c[8]*L + 3*c[11]*L*L +
685  2*c[12]*L*P + 2*c[13]*L*H + c[14]*P*P + c[17]*H*H;
686  }
687  else
688  {
689  dr = c[1] + c[4]*P + c[5]*H + 2*c[7]*L + c[10]*P*H + 3*c[11]*L*L +
690  c[12]*P*P + c[13]*H*H + 2*c[14]*P*L + 2*c[17]*L*H;
691  }
692  return dr;
693 }
694 
695 //*****************************************************************************
696 // PRIVATE METHOD: ossimRpcModel::dPoly_dHgt
697 //
698 // Computes derivative of polynomial wrt normalized Height H.
699 //
700 //*****************************************************************************
701 double ossimRpcModel::dPoly_dHgt(const double& P, const double& L,
702  const double& H, const double* c) const
703 {
704  double dr;
705 
706  if (thePolyType == A)
707  {
708  dr = c[3] + c[5]*L + c[6]*P + c[7]*L*P + 2*c[10]*H + c[13]*L*L +
709  c[16]*P*P + 2*c[17]*L*H + 2*c[18]*P*H + 3*c[19]*H*H;
710  }
711  else
712  {
713  dr = c[3] + c[5]*L + c[6]*P + 2*c[9]*H + c[10]*L*P + 2*c[13]*L*H +
714  2*c[16]*P*H + c[17]*L*L + c[18]*P*P + 3*c[19]*H*H;
715  }
716  return dr;
717 }
718 
720 {
725  double mapRotation = computeParameterOffset(MAP_ROTATION);
726  theCosMapRot = ossim::cosd(mapRotation);
727  theSinMapRot = ossim::sind(mapRotation);
728 }
729 
731 {
733  int numParams = getNumberOfAdjustableParameters();
734  for (int i=0; i<numParams; i++)
735  {
736  setAdjustableParameter(i, 0.0);
737  setParameterDescription(i, PARAM_NAMES[i]);
738  setParameterUnit(i,PARAM_UNITS[i]);
739  }
745 // setParameterSigma(YAW_OFFSET, 0.001);
746 }
747 
749 {
750  return new ossimRpcModel(*this);
751 }
752 
753 //*****************************************************************************
754 // METHOD: ossimRpcModel::print()
755 //
756 // Formatted dump of data members.
757 //
758 //*****************************************************************************
760 {
761  out << "\nDump of ossimRpcModel object at " << std::hex << this << std::dec << ":\n"
762  << POLY_TYPE_KW << ": " << thePolyType << "\n"
763  << LINE_SCALE_KW << ": " << theLineScale << "\n"
764  << SAMP_SCALE_KW << ": " << theSampScale << "\n"
765  << LAT_SCALE_KW << ": " << theLatScale << "\n"
766  << LON_SCALE_KW << ": " << theLonScale << "\n"
767  << HGT_SCALE_KW << ": " << theHgtScale << "\n"
768  << LINE_OFFSET_KW << ": " << theLineOffset << "\n"
769  << SAMP_OFFSET_KW << ": " << theSampOffset << "\n"
770  << LAT_OFFSET_KW << ": " << theLatOffset << "\n"
771  << LON_OFFSET_KW << ": " << theLonOffset << "\n"
772  << HGT_OFFSET_KW << ": " << theHgtOffset << "\n"
773  << BIAS_ERROR_KW << ": " << theBiasError << "\n"
774  << RAND_ERROR_KW << ": " << theRandError << "\n"
775  << std::endl;
776 
777  for (int i=0; i<NUM_COEFFS; i++)
778  out<<" "<<LINE_NUM_COEF_KW<<"["<<i<<"]: "<<theLineNumCoef[i]<<std::endl;
779 
780  out << std::endl;
781  for (int i=0; i<NUM_COEFFS; i++)
782  out<<" "<<LINE_DEN_COEF_KW<<"["<<i<<"]: "<<theLineDenCoef[i]<<std::endl;
783 
784  out << std::endl;
785  for (int i=0; i<NUM_COEFFS; i++)
786  out<<" "<<SAMP_NUM_COEF_KW<<"["<<i<<"]: "<<theSampNumCoef[i]<<std::endl;
787 
788  out << std::endl;
789  for (int i=0; i<NUM_COEFFS; i++)
790  out<<" "<<SAMP_DEN_COEF_KW<<"["<<i<<"]: "<<theSampDenCoef[i]<<std::endl;
791 
792  out << std::endl;
793 
794  return ossimSensorModel::print(out);
795 }
796 
797 //*****************************************************************************
798 // METHOD: ossimRpcModel::saveState()
799 //
800 // Saves the model state to the KWL. This KWL also serves as a geometry file.
801 //
802 //*****************************************************************************
804  const char* prefix) const
805 {
806  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimRpcModel::saveState(): entering..." << std::endl;
807 
808  kwl.add(prefix, ossimKeywordNames::TYPE_KW, MODEL_TYPE);
809 
810  //***
811  // Hand off to base class for common stuff:
812  //***
813  ossimSensorModel::saveState(kwl, prefix);
814 
815  //---
816  // Save off offsets and scales:
817  //---
818  kwl.add(prefix, POLY_TYPE_KW, ((char)thePolyType));
819  kwl.add(prefix, LINE_SCALE_KW, theLineScale);
820  kwl.add(prefix, SAMP_SCALE_KW, theSampScale);
821  kwl.add(prefix, LAT_SCALE_KW, theLatScale);
822  kwl.add(prefix, LON_SCALE_KW, theLonScale);
823  kwl.add(prefix, HGT_SCALE_KW, theHgtScale);
824  kwl.add(prefix, LINE_OFFSET_KW, theLineOffset);
825  kwl.add(prefix, SAMP_OFFSET_KW, theSampOffset);
826  kwl.add(prefix, LAT_OFFSET_KW, theLatOffset);
827  kwl.add(prefix, LON_OFFSET_KW, theLonOffset);
828  kwl.add(prefix, HGT_OFFSET_KW, theHgtOffset);
829  kwl.add(prefix, BIAS_ERROR_KW, theBiasError);
830  kwl.add(prefix, RAND_ERROR_KW, theRandError);
831 
832  for (int i=0; i<NUM_COEFFS; i++)
833  {
834  ossimString key;
836  os << setw(2) << setfill('0') << right << i;
837 
838  key = LINE_NUM_COEF_KW;
839  key += os.str();
840  kwl.add(prefix, key.c_str(), theLineNumCoef[i],
841  true, 15);
842 
843  key = LINE_DEN_COEF_KW;
844  key += os.str();
845  kwl.add(prefix, key.c_str(), theLineDenCoef[i],
846  true, 15);
847 
848  key = SAMP_NUM_COEF_KW;
849  key += os.str();
850  kwl.add(prefix, key.c_str(), theSampNumCoef[i],
851  true, 15);
852 
853  key = SAMP_DEN_COEF_KW;
854  key += os.str();
855  kwl.add(prefix, key.c_str(), theSampDenCoef[i],
856  true, 15);
857  }
858 
859  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimRpcModel::saveState(): returning..." << std::endl;
860  return true;
861 }
862 
863 //*****************************************************************************
864 // METHOD: ossimRpcModel::loadState()
865 //
866 // Restores the model's state from the KWL. This KWL also serves as a
867 // geometry file.
868 //
869 //*****************************************************************************
871  const char* prefix)
872 {
873  if (traceExec())
874  {
876  << "DEBUG ossimRpcModel::loadState(): entering..." << std::endl;
877  }
878 
879  const char* value;
880  const char* keyword;
881 
882  //***
883  // Pass on to the base-class for parsing first:
884  //***
885  bool success = ossimSensorModel::loadState(kwl, prefix);
886  if (!success)
887  {
888  theErrorStatus++;
889 
890  if (traceExec())
891  {
893  << "DEBUG ossimRpcModel::loadState(): returning with error..."
894  << std::endl;
895  }
896  return false;
897  }
898 
899  //---
900  // Continue parsing for local members:
901  //---
902  value = kwl.find(prefix, BIAS_ERROR_KW);
903  if (value)
904  {
905  theBiasError = ossimString(value).toDouble();
906  }
907 
908  value = kwl.find(prefix, RAND_ERROR_KW);
909  if (value)
910  {
911  theRandError = ossimString(value).toDouble();
912  }
913 
914  keyword = POLY_TYPE_KW;
915  value = kwl.find(prefix, keyword);
916  if (!value)
917  {
918  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
919  << "<" << keyword << ">. Check the keywordlist for proper syntax."
920  << std::endl;
921  return false;
922  }
923  thePolyType = (PolynomialType) value[0];
924 
925  keyword = LINE_SCALE_KW;
926  value = kwl.find(prefix, keyword);
927  if (!value)
928  {
929  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
930  << "<" << keyword << ">. Check the keywordlist for proper syntax."
931  << std::endl;
932  return false;
933  }
934  theLineScale = atof(value);
935 
936  keyword = SAMP_SCALE_KW;
937  value = kwl.find(prefix, keyword);
938  if (!value)
939  {
940  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
941  << "<" << keyword << ">. Check the keywordlist for proper syntax."
942  << std::endl;
943  return false;
944  }
945  theSampScale = atof(value);
946 
947  keyword = LAT_SCALE_KW;
948  value = kwl.find(prefix, keyword);
949  if (!value)
950  {
951  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
952  << "<" << keyword << ">. Check the keywordlist for proper syntax."
953  << std::endl;
954  return false;
955  }
956  theLatScale = atof(value);
957 
958  keyword = LON_SCALE_KW;
959  value = kwl.find(prefix, keyword);
960  if (!value)
961  {
962  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
963  << "<" << keyword << ">. Check the keywordlist for proper syntax."
964  << std::endl;
965  return false;
966  }
967  theLonScale = atof(value);
968 
969  keyword = HGT_SCALE_KW;
970  value = kwl.find(prefix, keyword);
971  if (!value)
972  {
973  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
974  << "<" << keyword << ">. Check the keywordlist for proper syntax."
975  << std::endl;
976  return false;
977  }
978  theHgtScale = atof(value);
979 
980  keyword = LINE_OFFSET_KW;
981  value = kwl.find(prefix, keyword);
982  if (!value)
983  {
984  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
985  << "<" << keyword << ">. Check the keywordlist for proper syntax."
986  << std::endl;
987  return false;
988  }
989  theLineOffset = atof(value);
990 
991  keyword = SAMP_OFFSET_KW;
992  value = kwl.find(prefix, keyword);
993  if (!value)
994  {
995  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
996  << "<" << keyword << ">. Check the keywordlist for proper syntax."
997  << std::endl;
998  return false;
999  }
1000  theSampOffset = atof(value);
1001 
1002  keyword = LAT_OFFSET_KW;
1003  value = kwl.find(prefix, keyword);
1004  if (!value)
1005  {
1006  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
1007  << "<" << keyword << ">. Check the keywordlist for proper syntax."
1008  << std::endl;
1009  return false;
1010  }
1011  theLatOffset = atof(value);
1012 
1013  keyword = LON_OFFSET_KW;
1014  value = kwl.find(prefix, keyword);
1015  if (!value)
1016  {
1017  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
1018  << "<" << keyword << ">. Check the keywordlist for proper syntax."
1019  << std::endl;
1020  return false;
1021  }
1022  theLonOffset = atof(value);
1023 
1024  keyword = HGT_OFFSET_KW;
1025  value = kwl.find(prefix, keyword);
1026  if (!value)
1027  {
1028  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
1029  << "<" << keyword << ">. Check the keywordlist for proper syntax."
1030  << std::endl;
1031  return false;
1032  }
1033  theHgtOffset = atof(value);
1034 
1035  for (int i=0; i<NUM_COEFFS; i++)
1036  {
1037  ossimString keyword;
1038  ostringstream os;
1039  os << setw(2) << setfill('0') << right << i;
1040 
1041  keyword = LINE_NUM_COEF_KW;
1042  keyword += os.str();
1043  value = kwl.find(prefix, keyword.c_str());
1044  if (!value)
1045  {
1047  << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
1048  << "<" << keyword << ">. Check the keywordlist for proper syntax."
1049  << std::endl;
1050  return false;
1051  }
1052  theLineNumCoef[i] = atof(value);
1053 
1054  keyword = LINE_DEN_COEF_KW;
1055  keyword += os.str();
1056  value = kwl.find(prefix, keyword.c_str());
1057  if (!value)
1058  {
1059  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
1060  << "<" << keyword << ">. Check the keywordlist for proper syntax."
1061  << std::endl;
1062  return false;
1063  }
1064  theLineDenCoef[i] = atof(value);
1065 
1066  keyword = SAMP_NUM_COEF_KW;
1067  keyword += os.str();
1068  value = kwl.find(prefix, keyword.c_str());
1069  if (!value)
1070  {
1071  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
1072  << "<" << keyword << ">. Check the keywordlist for proper syntax."
1073  << std::endl;
1074  return false;
1075  }
1076  theSampNumCoef[i] = atof(value);
1077 
1078  keyword = SAMP_DEN_COEF_KW;
1079  keyword += os.str();
1080  value = kwl.find(prefix, keyword.c_str());
1081  if (!value)
1082  {
1083  ossimNotify(ossimNotifyLevel_FATAL) << "FATAL ossimRpcModel::loadState(): Error encountered parsing the following required keyword: "
1084  << "<" << keyword << ">. Check the keywordlist for proper syntax."
1085  << std::endl;
1086  return false;
1087  }
1088  theSampDenCoef[i] = atof(value);
1089  }
1090 
1091  //***
1092  // Initialize other data members given quantities read in KWL:
1093  //***
1094  theCosMapRot = 1.0;
1095  theSinMapRot = 0.0;
1096 
1097  updateModel();
1098 
1099  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimRpcModel::loadState(): returning..." << std::endl;
1100  return true;
1101 }
1102 
1103 //*****************************************************************************
1104 // STATIC METHOD: ossimRpcModel::writeGeomTemplate
1105 //
1106 // Writes a sample kwl to output stream.
1107 //
1108 //*****************************************************************************
1110 {
1111  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimRpcModel::writeGeomTemplate(): entering..." << std::endl;
1112 
1113  os <<
1114  "//**************************************************************\n"
1115  "// Template for RPC model keywordlist\n"
1116  "//**************************************************************\n"
1117  << ossimKeywordNames::TYPE_KW << ": " << MODEL_TYPE << endl;
1118 
1120 
1121  os << "//\n"
1122  << "// Derived-class ossimRpcModel Keywords:\n"
1123  << "//\n"
1124  << POLY_TYPE_KW << ": A|B\n"
1125  << "\n"
1126  << "// RPC data consists of coefficients and normalization \n"
1127  << "// parameters. The RPC keywords used here are compatible with \n"
1128  << "// keywords found in Ikonos \"rpc.txt\" files.\n"
1129  << "// First are the normalization parameters:\n"
1130  << LINE_OFFSET_KW << ": <float>\n"
1131  << SAMP_OFFSET_KW << ": <float>\n"
1132  << LAT_OFFSET_KW << ": <float>\n"
1133  << LON_OFFSET_KW << ": <float>\n"
1134  << HGT_OFFSET_KW << ": <float>\n"
1135  << LINE_SCALE_KW << ": <float>\n"
1136  << SAMP_SCALE_KW << ": <float>\n"
1137  << LAT_SCALE_KW << ": <float>\n"
1138  << LON_SCALE_KW << ": <float>\n"
1139  << HGT_SCALE_KW << ": <float>\n"
1140  << BIAS_ERROR_KW << ": <float>\n"
1141  << RAND_ERROR_KW << ": <float>\n"
1142  << "\n"
1143  << "// RPC Coefficients are specified with indexes. Coefficients \n "
1144  << "// are specified for the four polynomials: line numerator, line \n"
1145  << "// denominator, sample numerator, and sample denominator:" << endl;
1146 
1147  for (int i=1; i<=20; i++)
1148  os << LINE_NUM_COEF_KW << setw(2) << setfill('0') << right
1149  << i << ": <float>" << endl;
1150  os << endl;
1151  for (int i=1; i<=20; i++)
1152  os << LINE_DEN_COEF_KW << setw(2) << setfill('0') << right
1153  << i << ": <float>" << endl;
1154  os << endl;
1155  for (int i=1; i<=20; i++)
1156  os << SAMP_NUM_COEF_KW << setw(2) << setfill('0') << right
1157  << i << ": <float>" << endl;
1158  os << endl;
1159  for (int i=1; i<=20; i++)
1160  os << SAMP_DEN_COEF_KW << setw(2) << setfill('0') << right
1161  << i << ": <float>" << endl;
1162  os << "\n" <<endl;
1163 
1164  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimRpcModel::writeGeomTemplate(): returning..." << std::endl;
1165  return;
1166 }
1167 
1169 {
1170  ossimKeywordlist kwl;
1171 
1172  if(kwl.addFile(ossimFilename(init_file)))
1173  {
1174  return loadState(kwl);
1175  }
1176  else
1177  {
1179  if(proj.valid())
1180  {
1181  kwl.clear();
1182  proj->saveState(kwl);
1183 
1184  return loadState(kwl);
1185  }
1186  }
1187 
1188  return false;
1189 }
1190 
1191 //*****************************************************************************
1192 // METHOD: ossimSarModel::getForwardDeriv()
1193 //
1194 // Compute partials of samp/line WRT to ground.
1195 //
1196 //*****************************************************************************
1198  const ossimGpt& pos,
1199  double h)
1200 {
1201  // If derivMode (parmIdx) >= 0 call base class version
1202  // for "adjustable parameters"
1203  if (derivMode >= 0)
1204  {
1205  return ossimSensorModel::getForwardDeriv(derivMode, pos, h);
1206  }
1207 
1208  // Use alternative derivMode definitions
1209  else
1210  {
1211  ossimDpt returnData;
1212 
1213  //******************************************
1214  // OBS_INIT mode
1215  // [1]
1216  // [2]
1217  // Note: In this mode, pos is used to pass
1218  // in the (s,l) observations.
1219  //******************************************
1220  if (derivMode==OBS_INIT)
1221  {
1222  // Image coordinates
1223  ossimDpt obs;
1224  obs.samp = pos.latd();
1225  obs.line = pos.lond();
1226  theObs = obs;
1227  }
1228 
1229  //******************************************
1230  // EVALUATE mode
1231  // [1] evaluate & save partials, residuals
1232  // [2] return residuals
1233  //******************************************
1234  else if (derivMode==EVALUATE)
1235  {
1236  //***
1237  // Normalize the lat, lon, hgt:
1238  //***
1239  double nlat = (pos.lat - theLatOffset) / theLatScale;
1240  double nlon = (pos.lon - theLonOffset) / theLonScale;
1241  double nhgt;
1242 
1243  if( ossim::isnan(pos.hgt) )
1244  {
1245  nhgt = (theHgtScale - theHgtOffset) / theHgtScale;
1246  }
1247  else
1248  {
1249  nhgt = (pos.hgt - theHgtOffset) / theHgtScale;
1250  }
1251 
1252  //***
1253  // Compute the normalized line (Un) and sample (Vn):
1254  //***
1255  double Pu = polynomial(nlat, nlon, nhgt, theLineNumCoef);
1256  double Qu = polynomial(nlat, nlon, nhgt, theLineDenCoef);
1257  double Pv = polynomial(nlat, nlon, nhgt, theSampNumCoef);
1258  double Qv = polynomial(nlat, nlon, nhgt, theSampDenCoef);
1259  double Un = Pu / Qu;
1260  double Vn = Pv / Qv;
1261 
1262  //***
1263  // Compute the actual line (U) and sample (V):
1264  //***
1265  double U = Un*theLineScale + theLineOffset;
1266  double V = Vn*theSampScale + theSampOffset;
1267 
1268  //***
1269  // Compute the partials of each polynomial wrt lat, lon, hgt
1270  //***
1271  double dPu_dLat, dQu_dLat, dPv_dLat, dQv_dLat;
1272  double dPu_dLon, dQu_dLon, dPv_dLon, dQv_dLon;
1273  double dPu_dHgt, dQu_dHgt, dPv_dHgt, dQv_dHgt;
1274  dPu_dLat = dPoly_dLat(nlat, nlon, nhgt, theLineNumCoef);
1275  dQu_dLat = dPoly_dLat(nlat, nlon, nhgt, theLineDenCoef);
1276  dPv_dLat = dPoly_dLat(nlat, nlon, nhgt, theSampNumCoef);
1277  dQv_dLat = dPoly_dLat(nlat, nlon, nhgt, theSampDenCoef);
1278  dPu_dLon = dPoly_dLon(nlat, nlon, nhgt, theLineNumCoef);
1279  dQu_dLon = dPoly_dLon(nlat, nlon, nhgt, theLineDenCoef);
1280  dPv_dLon = dPoly_dLon(nlat, nlon, nhgt, theSampNumCoef);
1281  dQv_dLon = dPoly_dLon(nlat, nlon, nhgt, theSampDenCoef);
1282  dPu_dHgt = dPoly_dHgt(nlat, nlon, nhgt, theLineNumCoef);
1283  dQu_dHgt = dPoly_dHgt(nlat, nlon, nhgt, theLineDenCoef);
1284  dPv_dHgt = dPoly_dHgt(nlat, nlon, nhgt, theSampNumCoef);
1285  dQv_dHgt = dPoly_dHgt(nlat, nlon, nhgt, theSampDenCoef);
1286 
1287  //***
1288  // Compute partials of quotients U and V wrt lat, lon, hgt
1289  //***
1290  double dU_dLat, dU_dLon, dU_dHgt, dV_dLat, dV_dLon, dV_dHgt;
1291  dU_dLat = (Qu*dPu_dLat - Pu*dQu_dLat)/(Qu*Qu);
1292  dU_dLon = (Qu*dPu_dLon - Pu*dQu_dLon)/(Qu*Qu);
1293  dU_dHgt = (Qu*dPu_dHgt - Pu*dQu_dHgt)/(Qu*Qu);
1294  dV_dLat = (Qv*dPv_dLat - Pv*dQv_dLat)/(Qv*Qv);
1295  dV_dLon = (Qv*dPv_dLon - Pv*dQv_dLon)/(Qv*Qv);
1296  dV_dHgt = (Qv*dPv_dHgt - Pv*dQv_dHgt)/(Qv*Qv);
1297 
1298  //***
1299  // Apply necessary scale factors
1300  //***
1301  dU_dLat *= theLineScale/theLatScale;
1302  dU_dLon *= theLineScale/theLonScale;
1303  dU_dHgt *= theLineScale/theHgtScale;
1304  dV_dLat *= theSampScale/theLatScale;
1305  dV_dLon *= theSampScale/theLonScale;
1306  dV_dHgt *= theSampScale/theHgtScale;
1307 
1308  dU_dLat *= DEG_PER_RAD;
1309  dU_dLon *= DEG_PER_RAD;
1310  dV_dLat *= DEG_PER_RAD;
1311  dV_dLon *= DEG_PER_RAD;
1312 
1313  // Save the partials referenced to ECF
1314  ossimEcefPoint location(pos);
1315  NEWMAT::Matrix jMat(3,3);
1316  pos.datum()->ellipsoid()->jacobianWrtEcef(location, jMat);
1317  // Line
1318  theParWRTx.u = dU_dLat*jMat(1,1)+dU_dLon*jMat(2,1)+dU_dHgt*jMat(3,1);
1319  theParWRTy.u = dU_dLat*jMat(1,2)+dU_dLon*jMat(2,2)+dU_dHgt*jMat(3,2);
1320  theParWRTz.u = dU_dLat*jMat(1,3)+dU_dLon*jMat(2,3)+dU_dHgt*jMat(3,3);
1321  // Samp
1322  theParWRTx.v = dV_dLat*jMat(1,1)+dV_dLon*jMat(2,1)+dV_dHgt*jMat(3,1);
1323  theParWRTy.v = dV_dLat*jMat(1,2)+dV_dLon*jMat(2,2)+dV_dHgt*jMat(3,2);
1324  theParWRTz.v = dV_dLat*jMat(1,3)+dV_dLon*jMat(2,3)+dV_dHgt*jMat(3,3);
1325 
1326  // Residuals
1327  ossimDpt resid(theObs.samp-V, theObs.line-U);
1328  returnData = resid;
1329  }
1330 
1331  //******************************************
1332  // P_WRT_X, P_WRT_Y, P_WRT_Z modes
1333  // [1] 3 separate calls required
1334  // [2] return 3 sets of partials
1335  //******************************************
1336  else if (derivMode==P_WRT_X)
1337  {
1338  returnData = theParWRTx;
1339  }
1340 
1341  else if (derivMode==P_WRT_Y)
1342  {
1343  returnData = theParWRTy;
1344  }
1345 
1346  else
1347  {
1348  returnData = theParWRTz;
1349  }
1350 
1351  return returnData;
1352  }
1353 }
1354 
1356 {
1357  return theBiasError;
1358 }
1359 
1361 {
1362  return theRandError;
1363 }
1364 
1365 
1366 //*****************************************************************************
1367 // METHOD: ossimSarModel::getRpcParameters)
1368 //
1369 // Accessor for RPC parameter set.
1370 //
1371 //*****************************************************************************
1373 {
1374  model.lineScale = theLineScale;
1375  model.sampScale = theSampScale;
1376  model.latScale = theLatScale;
1377  model.lonScale = theLonScale;
1378  model.hgtScale = theHgtScale;
1379  model.lineOffset = theLineOffset;
1380  model.sampOffset = theSampOffset;
1381  model.latOffset = theLatOffset;
1382  model.lonOffset = theLonOffset;
1383  model.hgtOffset = theHgtOffset;
1384 
1385  for (int i=0; i<20; ++i)
1386  {
1387  model.lineNumCoef[i] = theLineNumCoef[i];
1388  model.lineDenCoef[i] = theLineDenCoef[i];
1389  model.sampNumCoef[i] = theSampNumCoef[i];
1390  model.sampDenCoef[i] = theSampDenCoef[i];
1391  }
1392 
1393  if (thePolyType == A)
1394  {
1395  model.type= 'A';
1396  }
1397  else
1398  {
1399  model.type= 'B';
1400  }
1401 }
1402 
1404 {
1405  theLineOffset -= offset.line;
1406  theSampOffset -= offset.samp;
1407 
1408  if (theImageClipRect.hasNans())
1409  theImageClipRect = ossimDrect(0, 0, theImageSize.x-offset.x-1, theImageSize.y-offset.y-1);
1410  else
1411  theImageClipRect -= offset;
1412 }
1413 
1414 
1415 bool ossimRpcModel::toJSON(std::ostream& jsonStream) const
1416 {
1417 #if OSSIM_HAS_JSONCPP
1418  Json::Value IMAGE;
1419  IMAGE["ERRBIAS"] = theBiasError;
1420  IMAGE["ERRRAND"] = theRandError;
1421  IMAGE["LINEOFFSET"] = (int)theLineOffset;
1422  IMAGE["SAMPOFFSET"] = (int)theSampOffset;
1423  IMAGE["LATOFFSET"] = theLatOffset;
1424  IMAGE["LONGOFFSET"] = theLonOffset;
1425  IMAGE["HEIGHTOFFSET"] = theHgtOffset;
1426  IMAGE["LINESCALE"] = theLineScale;
1427  IMAGE["SAMPSCALE"] = theSampScale;
1428  IMAGE["LATSCALE"] = theLatScale;
1429  IMAGE["LONGSCALE"] = theLonScale;
1430  IMAGE["HEIGHTSCALE"] = theHgtScale;
1431 
1432  // Preferred way to output coeff arrays:
1433 // Json::Value LINENUMCOEF(Json::arrayValue);
1434 // Json::Value LINEDENCOEF(Json::arrayValue);
1435 // Json::Value SAMPNUMCOEF(Json::arrayValue);
1436 // Json::Value SAMPDENCOEF(Json::arrayValue);
1437 // for (int i=0; i<20; ++i)
1438 // {
1439 // LINENUMCOEF.append(theLineNumCoef[i]);
1440 // LINEDENCOEF.append(theLineDenCoef[i]);
1441 // SAMPNUMCOEF.append(theSampNumCoef[i]);
1442 // SAMPDENCOEF.append(theSampDenCoef[i]);
1443 // }
1444 
1445  // Write coeffs as string list for JSON to XML converter to output properly:
1446  ossimString LINENUMCOEF;
1447  ossimString LINEDENCOEF;
1448  ossimString SAMPNUMCOEF;
1449  ossimString SAMPDENCOEF;
1450  for (int i=0; i<20; ++i)
1451  {
1452  LINENUMCOEF += ossimString::toString(theLineNumCoef[i]) + " ";
1453  LINEDENCOEF += ossimString::toString(theLineDenCoef[i]) + " ";
1454  SAMPNUMCOEF += ossimString::toString(theSampNumCoef[i]) + " ";
1455  SAMPDENCOEF += ossimString::toString(theSampDenCoef[i]) + " ";
1456  }
1457 
1458  Json::Value LINENUMCOEFList;
1459  LINENUMCOEFList["LINENUMCOEF"] = LINENUMCOEF.string();
1460  IMAGE["LINENUMCOEFList"] = LINENUMCOEFList;
1461 
1462  Json::Value LINEDENCOEFList;
1463  LINEDENCOEFList["LINEDENCOEF"] = LINEDENCOEF.string();
1464  IMAGE["LINEDENCOEFList"] = LINEDENCOEFList;
1465 
1466  Json::Value SAMPNUMCOEFList;
1467  SAMPNUMCOEFList["SAMPNUMCOEF"] = SAMPNUMCOEF.string();
1468  IMAGE["SAMPNUMCOEFList"] = SAMPNUMCOEFList;
1469 
1470  Json::Value SAMPDENCOEFList;
1471  SAMPDENCOEFList["SAMPDENCOEF"] = SAMPDENCOEF.string();
1472  IMAGE["SAMPDENCOEFList"] = SAMPDENCOEFList;
1473 
1474  Json::Value RPB;
1475  RPB["SATID"] = "NOT_ASSIGNED";
1476  RPB["BANDID"] = "NOT_ASSIGNED";
1477  if (thePolyType == A)
1478  RPB["SPECID"] = "RPC00A"; // Not sure this will work
1479  else
1480  RPB["SPECID"] = "RPC00B";
1481  RPB["IMAGE"] = IMAGE;
1482 
1483  Json::Value ISD;
1484  ISD["RPB"] = RPB;
1485 
1486  Json::Value root;
1487  root["isd"] = ISD;
1488  jsonStream << root;
1489  return true;
1490 #else
1491  jsonStream<<"Error: JSON format not supported."<<endl;
1492  return false;
1493 #endif
1494 }
1495 
1497 {
1498  out<<"satId = \"NOT_ASSIGNED\";\n";
1499  out<<"bandId = \"NOT_ASSIGNED\";\n";
1500  out<<"SpecId = \"RPC00B\";\n";
1501 
1502  out<<"BEGIN_GROUP = IMAGE\n";
1503  out<<"\terrBias = "<<theBiasError<<";\n";
1504  out<<"\terrRand = "<<theRandError<<";\n";
1505  out<<"\tlineOffset = "<<(int)theLineOffset<<";\n";
1506  out<<"\tsampOffset = "<<(int)theSampOffset<<";\n";
1507  out<<"\tlatOffset = "<<theLatOffset<<";\n";
1508  out<<"\tlongOffset = "<<theLonOffset<<";\n";
1509  out<<"\theightOffset = "<<theHgtOffset<<";\n";
1510  out<<"\tlineScale = "<<theLineScale<<";\n";
1511  out<<"\tsampScale = "<<theSampScale<<";\n";
1512  out<<"\tlatScale = "<<theLatScale<<";\n";
1513  out<<"\tlongScale = "<<theLonScale<<";\n";
1514  out<<"\theightScale = "<<theHgtScale<<";\n";
1515 
1516  out<<"\tlineNumCoef = (\n";
1517  for (int i=0; i<19; ++i)
1518  out<<"\t\t\t"<<std::scientific<<theLineNumCoef[i]<<",\n";
1519  out<<"\t\t\t"<<std::scientific<<theLineNumCoef[19]<<");\n";
1520 
1521  out<<"\tlineDenCoef = (\n";
1522  for (int i=0; i<19; ++i)
1523  out<<"\t\t\t"<<std::scientific<<theLineDenCoef[i]<<",\n";
1524  out<<"\t\t\t"<<std::scientific<<theLineDenCoef[19]<<");\n";
1525 
1526  out<<"\tsampNumCoef = (\n";
1527  for (int i=0; i<19; ++i)
1528  out<<"\t\t\t"<<std::scientific<<theSampNumCoef[i]<<",\n";
1529  out<<"\t\t\t"<<std::scientific<<theSampNumCoef[19]<<");\n";
1530 
1531  out<<"\tsampDenCoef = (\n";
1532  for (int i=0; i<19; ++i)
1533  out<<"\t\t\t"<<std::scientific<<theSampDenCoef[i]<<",\n";
1534  out<<"\t\t\t"<<std::scientific<<theSampDenCoef[19]<<");\n";
1535 
1536  out<<"END_GROUP = IMAGE\n";
1537  out<<"END;";
1538 
1539  return true;
1540 }
1541 
double theSampOffset
PolynomialType thePolyType
virtual void worldToLineSample(const ossimGpt &world_point, ossimDpt &image_point) const
worldToLineSample() Overrides base class implementation.
double theSampNumCoef[20]
void setAttributes(ossim_float64 theSampleOffset, ossim_float64 theLineOffset, ossim_float64 theSampleScale, ossim_float64 theLineScale, ossim_float64 theLatOffset, ossim_float64 theLonOffset, ossim_float64 theHeightOffset, ossim_float64 theLatScale, ossim_float64 theLonScale, ossim_float64 theHeightScale, const std::vector< double > &xNumeratorCoeffs, const std::vector< double > &xDenominatorCoeffs, const std::vector< double > &yNumeratorCoeffs, const std::vector< double > &yDenominatorCoeffs, PolynomialType polyType=B, bool computeGsdFlag=true)
void setParameterDescription(ossim_uint32 idx, const ossimString &descrption)
virtual void imagingRay(const ossimDpt &image_point, ossimEcefRay &image_ray) const
imagingRay() Overrides base class pure virtual.
ossimEcefVector unitVector() const
double theIntrackOffset
static void writeGeomTemplate(ostream &os)
STATIC METHOD: writeGeomTemplate(ostream) Writes a template of geom keywords processed by loadState a...
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
virtual ossimDpt getForwardDeriv(int parmIdx, const ossimGpt &gpos, double h)
Compute partials of samp/line WRT ground point.
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
double lond() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:97
#define DEG_PER_RAD
virtual ossimObject * dup() const
dup() Returns pointer to a new instance, copy of this.
Represents serializable keyword/value map.
bool addFile(const char *file)
double u
Definition: ossimDpt.h:164
bool isLonNan() const
Definition: ossimGpt.h:140
double dPoly_dHgt(const double &nlat, const double &nlon, const double &nhgt, const double *coeffs) const
bool intersectRay(const ossimEcefRay &ray, ossimGpt &gpt, double defaultElevValue=0.0)
METHOD: intersectRay()
bool valid() const
Definition: ossimRefPtr.h:75
const char * find(const char *key) const
double samp
Definition: ossimDpt.h:164
double theIntrackScale
double dPoly_dLat(const double &nlat, const double &nlon, const double &nhgt, const double *coeffs) const
double y
Definition: ossimDpt.h:165
void makeNan()
Definition: ossimGpt.h:130
static ossimString toString(bool aValue)
Numeric to string methods.
virtual void updateModel()
ossim_float64 hgt
Height in meters above the ellipsiod.
Definition: ossimGpt.h:274
static ossimElevManager * instance()
METHOD: instance() Implements singelton pattern.
void setMetersPerPixel(const ossimDpt &metersPerPixel)
double sind(double x)
Definition: ossimCommon.h:260
virtual void lineSampleToWorld(const ossimDpt &image_point, ossimGpt &world_point) const
double theLonScale
void getRpcParameters(ossimRpcModel::rpcModelStruct &model) const
Returns RPC parameter set in structure.
double latd() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:87
bool isLatNan() const
Definition: ossimGpt.h:139
#define A(r, c)
double theLineScale
static const char * TYPE_KW
double polynomial(const double &nlat, const double &nlon, const double &nhgt, const double *coeffs) const
virtual ossimDpt getForwardDeriv(int parmIdx, const ossimGpt &gpos, double hdelta=1e-11)
bool isHgtNan() const
Definition: ossimGpt.h:143
virtual void initAdjustableParameters()
const ossimDatum * datum() const
datum().
Definition: ossimGpt.h:196
double theSampDenCoef[20]
double theLineNumCoef[20]
double theLatOffset
double ossim_float64
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
virtual std::ostream & print(std::ostream &out) const
print() Extends base-class implementation.
ossimRpcModel()
default constructor
double dPoly_dLon(const double &nlat, const double &nlon, const double &nhgt, const double *coeffs) const
double theHgtOffset
double theLonOffset
void computeGsd()
This method computes the ground sample distance(gsd) and sets class attributes theGSD and theMeanGSD ...
double line
Definition: ossimDpt.h:165
ossimProjection * createProjection(const ossimFilename &filename, ossim_uint32 entryIdx) const
virtual bool setupOptimizer(const ossimString &init_file)
uses file path to init model
double theRandError
ossim_float64 lon
Definition: ossimGpt.h:266
ossim_float64 theNominalPosError
double theLatScale
double theCrtrackScale
virtual const char * what() const
Returns the error message.
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
saveState Fulfills ossimObject base-class pure virtuals.
virtual ~ossimRpcModel()
virtual destructor
virtual const ossimEllipsoid * ellipsoid() const
Definition: ossimDatum.h:60
double height() const
Definition: ossimGpt.h:107
double toDouble() const
virtual void lineSampleHeightToWorld(const ossimDpt &image_point, const double &heightEllipsoid, ossimGpt &worldPoint) const
void setParameterUnit(ossim_uint32 idx, ossimUnitType unit)
void gradient(const ossimEcefPoint &location, ossimEcefVector &result) const
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
virtual std::ostream & print(std::ostream &out) const
bool hasNans() const
Definition: ossimDrect.h:396
void setImageOffset(const ossimDpt &offset_to_chip_ul)
Allows setting an offset to a subimage while using the coefficients of a full-image model...
RPC model structure used for access function.
Definition: ossimRpcModel.h:44
double cosd(double x)
Definition: ossimCommon.h:259
bool hasNans() const
Definition: ossimDpt.h:67
RTTI_DEF1(ossimRpcModel, "ossimRpcModel", ossimSensorModel)
static void writeGeomTemplate(ostream &os)
static ossimProjectionFactoryRegistry * instance()
ossimDrect theImageClipRect
virtual void setAdjustableParameter(ossim_uint32 idx, double value, bool notify=false)
ossim_int32 y
Definition: ossimIpt.h:142
double getRandError() const
Returns Error - Random.
double getBiasError() const
Returns Error - Bias.
double theCrtrackOffset
void jacobianWrtEcef(const ossimEcefPoint &location, NEWMAT::Matrix &jMat) const
double x
Definition: ossimDpt.h:164
bool toJSON(std::ostream &json) const
Serializes RPC to JSON format.
void resizeAdjustableParameterArray(ossim_uint32 numberOfParameters)
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
double theSampScale
ossim_int32 x
Definition: ossimIpt.h:141
ossim_float64 lat
Definition: ossimGpt.h:265
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
loadState Fulfills ossimObject base-class pure virtuals.
double theLineDenCoef[20]
double theSinMapRot
void setPositionError(const ossim_float64 &biasError, const ossim_float64 &randomError, bool initNominalPostionErrorFlag)
Sets data member theBiasError, theRandError.
ossimDpt theParWRTx
Partials for current point.
double theCosMapRot
double theLineOffset
ossimDpt theObs
Observations & residuals for current point.
double theHgtScale
double theBiasError
error
void setParameterSigma(ossim_uint32 idx, double value, bool notify=false)
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
void makeNan()
Definition: ossimDpt.h:65
ossim_float64 theMeanGSD
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
double v
Definition: ossimDpt.h:165
bool toRPB(std::ostream &out) const
Serialize to WorldView-style .RPB file to the stream provided.
const std::string & string() const
Definition: ossimString.h:414
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91