OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimPositionQualityEvaluator.cpp
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 //
3 // License: See top level LICENSE.txt file.
4 //
5 // Author: David Hicks
6 //
7 // Description: Base class for position quality evaluation operations.
8 //
9 //----------------------------------------------------------------------------
10 // $Id$
11 
13 #include <ossim/base/ossimDatum.h>
15 #include <ossim/base/ossimDms.h>
16 #include <ossim/base/ossimTrace.h>
17 #include <ossim/base/ossimString.h>
18 #include <ossim/base/ossimNotify.h>
20 
21 static ossimTrace traceDebug(ossimString("ossimPositionQualityEvaluator:debug"));
22 static ossimTrace traceExec(ossimString("ossimPositionQualityEvaluator:exec"));
23 
24 #ifdef OSSIM_ID_ENABLED
25 static const char OSSIM_ID[] = "$Id: ossimPositionQualityEvaluator.cpp";
26 #endif
27 
28 // 2D 90% function coefficients
32  {1.644854,1.645623,1.647912,1.651786,1.657313,
33  1.664580,1.673829,1.685227,1.699183,1.716257,
34  1.737080,1.762122,1.791522,1.825112,1.862530,
35  1.903349,1.947158,1.993595,2.042360,2.093214,2.145966};
36 
37 // 1D conversion factors relative to ONE_SIGMA
39  {1.0, 0.6745, 1.6449, 1.96};
40 
41 // 2D conversion factors relative to ONE_SIGMA
43  {1.0, 1.1774, 2.1460, 2.4477};
44 
45 // 2D conversion factors relative to P90
47  {0.46598, 0.54865, 1.0, 1.14059};
48 
49 
50 //*****************************************************************************
51 // METHOD: ossimPositionQualityEvaluator::ossimPositionQualityEvaluator()
52 //
53 // Constructor.
54 //
55 //*****************************************************************************
57 {
58  if (traceDebug())
59  {
61  << "\nossimPositionQualityEvaluator::ossimPositionQualityEvaluator DEBUG:" << std::endl;
62 #ifdef OSSIM_ID_ENABLED
64  << "OSSIM_ID: " << OSSIM_ID << std::endl;
65 #endif
66  }
67 
68  theEvaluatorValid = false;
69  theRpcModel.theType = 'N';
70 }
71 
72 
73 //*****************************************************************************
74 // METHOD: ossimPositionQualityEvaluator::ossimPositionQualityEvaluator()
75 //
76 // Covariance matrix-based constructor.
77 //
78 //*****************************************************************************
80 ossimPositionQualityEvaluator(const ossimEcefPoint& pt,const NEWMAT::Matrix& covMat)
81 {
82  if (traceDebug())
83  {
85  << "\nossimPositionQualityEvaluator::ossimPositionQualityEvaluator DEBUG:" << std::endl;
86 #ifdef OSSIM_ID_ENABLED
88  << "OSSIM_ID: " << OSSIM_ID << std::endl;
89 #endif
90  }
91  theRpcModel.theType = 'N';
92 
93  // Set the point
94  ossimGpt ptG(pt);
95  thePtG = ptG;
96 
97  // Define the local frame centered on the point
98  ossimLsrSpace enu(ptG);
99  theLocalFrame = enu;
100 
101  // Propagate input ECF cov matrix to local
104 
105  // Compute evaluation parameters
107 }
108 
109 
110 //*****************************************************************************
111 // METHOD: ossimPositionQualityEvaluator::ossimPositionQualityEvaluator()
112 //
113 // LOS error/geometry-based constructor.
114 //
115 //*****************************************************************************
118  const ossim_float64& errBiasLOS,
119  const ossim_float64& errRandLOS,
120  const ossim_float64& elevAngleLOS,
121  const ossim_float64& azimAngleLOS,
122  const ossimColumnVector3d& surfN,
123  const NEWMAT::Matrix& surfCovMat)
124 {
125  if (traceDebug())
126  {
128  << "\nossimPositionQualityEvaluator::ossimPositionQualityEvaluator DEBUG:" << std::endl;
129 #ifdef OSSIM_ID_ENABLED
131  << "OSSIM_ID: " << OSSIM_ID << std::endl;
132 #endif
133  }
134  theRpcModel.theType = 'N';
135 
136  // Set the point
137  ossimGpt ptG(pt);
138  thePtG = ptG;
139 
140  // Define the local frame centered on the point
141  ossimLsrSpace enu(ptG);
142  theLocalFrame = enu;
143 
144  // Form the covariance matrix
145  if (constructMatrix
146  (errBiasLOS, errRandLOS, elevAngleLOS, azimAngleLOS, surfN, surfCovMat))
147  {
148  // Compute evaluation parameters
150  }
151  else
152  {
153  theEvaluatorValid = false;
154  }
155 }
156 
157 
158 //*****************************************************************************
159 // METHOD: ossimPositionQualityEvaluator::ossimPositionQualityEvaluator()
160 //
161 // LOS error/coefficient-based constructor.
162 //
163 //*****************************************************************************
166  const ossim_float64& errBiasLOS,
167  const ossim_float64& errRandLOS,
168  const pqeRPCModel& rpc,
169  const ossimColumnVector3d& surfN,
170  const NEWMAT::Matrix& surfCovMat)
171 {
172  if (traceDebug())
173  {
175  << "\nossimPositionQualityEvaluator::ossimPositionQualityEvaluator DEBUG:" << std::endl;
176 #ifdef OSSIM_ID_ENABLED
178  << "OSSIM_ID: " << OSSIM_ID << std::endl;
179 #endif
180  }
181 
182  // Set the point
183  ossimGpt ptG(pt);
184  thePtG = ptG;
185 
186  // Define the local frame centered on the point
187  ossimLsrSpace enu(ptG);
188  theLocalFrame = enu;
189 
190  // Set the model parameters
191  theRpcModel = rpc;
192 
193  // Compute the target elevation & azimuth angles
194  double elevAngleLOS;
195  double azimAngleLOS;
196  computeElevAzim(rpc, elevAngleLOS, azimAngleLOS);
197 
198  // Form the covariance matrix
199  if (constructMatrix
200  (errBiasLOS, errRandLOS, elevAngleLOS, azimAngleLOS, surfN, surfCovMat))
201  {
202  // Compute evaluation parameters
204  }
205  else
206  {
207  theEvaluatorValid = false;
208  }
209 }
210 
211 
212 //*****************************************************************************
213 // DESTRUCTOR: ~ossimPositionQualityEvaluator()
214 //
215 //*****************************************************************************
217 {
218  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG)
219  << "DEBUG: ~ossimPositionQualityEvaluator(): returning..." << std::endl;
220 }
221 
222 
223 //*****************************************************************************
224 // METHOD: ossimPositionQualityEvaluator::print()
225 //
226 // Print info.
227 //
228 //*****************************************************************************
230 print(std::ostream& out) const
231 {
232  out << "\nPositionQualityEvaluator Summary..."<<std::endl;
233  out << " theEvaluatorValid: ";
234  if (theEvaluatorValid)
235  out<<"True"<<std::endl;
236  else
237  out<<"False"<<std::endl;
238  out << " thePtG: "<<thePtG<<std::endl;
239  out << " theCovMat [m]:\n"<<theCovMat;
240  out << fixed << setprecision(1);
241  out << " theEllipse: "<<theEllipse.theSemiMajorAxis<<" "
243  <<" [m, 1 sigma] at ";
244  out << theEllipse.theAzimAngle*DEG_PER_RAD<<" [deg] azimuth"<<endl;
245 
246  return out;
247 }
248 
249 
250 //*****************************************************************************
251 // METHOD: ossimPositionQualityEvaluator::getCovMatrix()
252 //
253 // Access the covariance matrix.
254 //
255 //*****************************************************************************
256 bool ossimPositionQualityEvaluator::getCovMatrix(NEWMAT::Matrix& covMat) const
257 {
258  if (theEvaluatorValid)
259  {
260  covMat = theCovMat;
261  }
262 
263  return theEvaluatorValid;
264 }
265 
266 
267 //*****************************************************************************
268 // METHOD: ossimPositionQualityEvaluator::addContributingCovariance()
269 //
270 // Sum in a contributing covariance matrix.
271 //
272 //*****************************************************************************
274 addContributingCovariance(NEWMAT::Matrix& covMat)
275 {
276  bool matrixOK = (covMat.Nrows()==3) && (covMat.Nrows()==3);
277  if (theEvaluatorValid && matrixOK)
278  {
279  // Add contribution
280  theCovMat += covMat;
281 
282  // Update the ellipse parameters
284  }
285 
286  return (theEvaluatorValid && matrixOK);
287 }
288 
289 
290 //*****************************************************************************
291 // METHOD: ossimPositionQualityEvaluator::addContributingCE_LE()
292 //
293 // Sum in a contributing CE/LE.
294 //
295 //*****************************************************************************
298 {
299  NEWMAT::Matrix covMat(3,3);
300 
301  formCovMatrixFromCE_LE(cCE, cLE, covMat);
302 
303  return addContributingCovariance(covMat);
304 }
305 
306 
307 //*****************************************************************************
308 // METHOD: ossimPositionQualityEvaluator::subtractContributingCovariance()
309 //
310 // Subtract out a contributing covariance matrix.
311 //
312 //*****************************************************************************
314 subtractContributingCovariance(NEWMAT::Matrix& covMat)
315 {
316  bool matrixOK = (covMat.Nrows()==3) && (covMat.Nrows()==3);
317  if (theEvaluatorValid && matrixOK)
318  {
319  // Subtract contribution
320  theCovMat -= covMat;
321 
322  // Update the ellipse parameters
324  }
325 
326  return (theEvaluatorValid && matrixOK);
327 }
328 
329 
330 //*****************************************************************************
331 // METHOD: ossimPositionQualityEvaluator::subtractContributingCE_LE()
332 //
333 // Subtract out a contributing CE/LE.
334 //
335 //*****************************************************************************
338 {
339  NEWMAT::Matrix covMat(3,3);
340 
341  formCovMatrixFromCE_LE(cCE, cLE, covMat);
342 
343  return subtractContributingCovariance(covMat);
344 }
345 
346 
347 //*****************************************************************************
348 // METHOD: ossimPositionQualityEvaluator::computeCE_LE()
349 //
350 // Compute CE/LE (ft) @ pLev probability level.
351 //
352 //*****************************************************************************
355 {
356  if (theEvaluatorValid)
357  {
358  // Compute 1D LE
359  LE = sqrt(theCovMat(3,3)) * (ossim_float64)Fac1D[pLev];
360 
361  // Compute 2D CE
362  CE = (ossim_float64)Fac2D90[pLev] * compute90PCE();
363  }
364 
365  return theEvaluatorValid;
366 }
367 
368 
369 //*****************************************************************************
370 // METHOD: ossimPositionQualityEvaluator::extractErrorEllipse()
371 //
372 // Extract error ellipse parameters @ pLev probability level.
373 //
374 //*****************************************************************************
377 {
378  if (theEvaluatorValid)
379  {
380  // Scale the axes
381  ellipse.theSemiMinorAxis =
383  ellipse.theSemiMajorAxis =
385 
386  // Orientation angle
388 
389  // Center position
390  ellipse.theCenter = thePtG;
391  }
392 
393  return theEvaluatorValid;
394 }
395 
396 
397 //*****************************************************************************
398 // METHOD: ossimPositionQualityEvaluator::extractErrorEllipse()
399 //
400 // Extract error ellipse parameters @ pLev probability level.
401 //
402 //*****************************************************************************
405  const ossim_float64& angularIncrement,
406  pqeErrorEllipse& ellipse,
407  pqeImageErrorEllipse_t& ellImage)
408 {
409  bool computeImageEllipse = true;
410 
411  if (theRpcModel.theType == 'N')
412  computeImageEllipse = false;
413 
414  if (theEvaluatorValid && computeImageEllipse)
415  {
416  // Get object space ellipse parameters
417  extractErrorEllipse(pLev, ellipse);
418 
419  //***
420  // Generate the image space ellipse point at 'angularIncrement' spacing
421  //***
422  int numSteps = 360/(int)angularIncrement;
423 
424  // Semi-axes components
425  double dxMaj = ellipse.theSemiMajorAxis*sin(ellipse.theAzimAngle);
426  double dyMaj = ellipse.theSemiMajorAxis*cos(ellipse.theAzimAngle);
427  double dxMin = ellipse.theSemiMinorAxis*sin(ellipse.theAzimAngle+M_PI/2.0);
428  double dyMin = ellipse.theSemiMinorAxis*cos(ellipse.theAzimAngle+M_PI/2.0);
429 
430  for (int j = 0; j<=numSteps; ++j)
431  {
432 
433  // Compute current ENU ellipse point
434  double ang = TWO_PI*j/numSteps;
435  double sang = sin(ang);
436  double cang = cos(ang);
437  double x = dxMaj*cang + dxMin*sang;
438  double y = dyMaj*cang + dyMin*sang;
439  double z = 0.0;
440 
441  ossimLsrPoint cpLSR(x, y, z, theLocalFrame);
442  ossimEcefPoint cp = ossimEcefPoint(cpLSR);
443  ossimGpt cpG(cp);
444  double lat = cpG.latd();
445  double lon = cpG.lond();
446  double hgt = cpG.height();
447 
448  // Normalize the lat, lon, hgt:
449  double nlat = (lat - theRpcModel.theLatOffset) /
451  double nlon = (lon - theRpcModel.theLonOffset) /
453  double nhgt;
454 
455  if( ossim::isnan(hgt) )
456  {
459  }
460  else
461  {
463  }
464 
465  //***
466  // Compute the normalized line (Un) and sample (Vn)
467  //***
468  double Pu = polynomial(nlat, nlon, nhgt, theRpcModel.theLineNumCoef);
469  double Qu = polynomial(nlat, nlon, nhgt, theRpcModel.theLineDenCoef);
470  double Pv = polynomial(nlat, nlon, nhgt, theRpcModel.theSampNumCoef);
471  double Qv = polynomial(nlat, nlon, nhgt, theRpcModel.theSampDenCoef);
472  double Un = Pu / Qu;
473  double Vn = Pv / Qv;
474 
475  //***
476  // Compute the actual line (U) and sample (V):
477  //***
480 
481  ossimDpt img(V,U);
482  ellImage.push_back(img);
483 
484  }
485  }
486 
487  return (theEvaluatorValid && computeImageEllipse);
488 }
489 
490 
491 //*****************************************************************************
492 // PRIVATE METHOD: ossimPositionQualityEvaluator::decomposeMatrix()
493 //
494 // Perform eigenvector decomposition and extract ellipse parameters.
495 // Compute eigenvalues (D) of horizontal 2X2 sub-matrix
496 // Note: eigenvectors (columns of V) contain unit vectors
497 // defining orientation of pMin/pMax error ellipse axes
498 //
499 //*****************************************************************************
501 {
502  // Decompose upper left 2X2 partition
503  NEWMAT::SymmetricMatrix S(2);
504  S<<theCovMat(1,1)<<theCovMat(1,2)<<theCovMat(2,2);
505  NEWMAT::DiagonalMatrix D;
506  NEWMAT::Matrix V;
507  NEWMAT::Jacobi(S,D,V);
508  theEllipse.theSemiMinorAxis = sqrt(D(1,1));
509  theEllipse.theSemiMajorAxis = sqrt(D(2,2));
510  theEigenvectors = V;
511 
512  // Compute error ellipse orientation
513  // (ccw rotation of major axis from x-axis)
514  ossim_float64 sin2theta = 2.0*theCovMat(1,2);
515  ossim_float64 cos2theta = theCovMat(1,1)-theCovMat(2,2);
516  if (cos2theta == 0.0)
517  {
518  return false;
519  }
520  else
521  {
522  // Convert "ccw from x-axis" to "cw from y-axis(N)"
523  double rotAngle = atan3(sin2theta, cos2theta)/2.0;
524  theEllipse.theAzimAngle = M_PI/2.0 - rotAngle;
525  if (theEllipse.theAzimAngle < 0.0)
527  }
528 
529  return true;
530 }
531 
532 
533 //*****************************************************************************
534 // PRIVATE METHOD: ossimPositionQualityEvaluator::constructMatrix()
535 //
536 // Construct covariance matrix from LOS-centered error components
537 // and target acxquistion geometry.
538 //
539 //*****************************************************************************
541 constructMatrix(const ossim_float64& errBiasLOS,
542  const ossim_float64& errRandLOS,
543  const ossim_float64& elevAngleLOS,
544  const ossim_float64& azimAngleLOS,
545  const ossimColumnVector3d& surfN,
546  const NEWMAT::Matrix& surfCovMat)
547 {
548  bool constructOK = true;
549  ossimColumnVector3d lsrNorm(0.0,0.0,1.0);
550 
551  // Set the total error
552  ossim_float64 eTot = sqrt(errBiasLOS*errBiasLOS + errRandLOS*errRandLOS);
553  if (eTot == 0.0)
554  eTot = 0.001;
555 
556  // Set the LOS unit vector
557  double elC = elevAngleLOS;
558  double azC = azimAngleLOS;
559  ossimColumnVector3d LOS(sin(azC)*cos(elC), cos(azC)*cos(elC), sin(elC));
560 
561  if (traceDebug())
562  {
563  ossimNotify(ossimNotifyLevel_DEBUG)<<"DEBUG: constructMatrix..."<<endl;
565  <<" tEl,tAz: "<<elC*DEG_PER_RAD<<" "<<azC*DEG_PER_RAD<<endl;
567  <<" LOS: "<<LOS<<endl;
569  <<" eTot: "<<eTot<<endl;
570  }
571 
572 
573  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
574  // Set ENU-referenced terrain slope normal
575  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
576  ossimColumnVector3d tSlopeN = surfN.unit();
577  if (traceDebug())
578  {
579  ossimNotify(ossimNotifyLevel_DEBUG) <<" tSlopeN: "<<tSlopeN<<endl;
580  }
581 
582  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
583  // Compute normal to plane containing LOS and terrain normal
584  // this is direction of minor axis unless geometry causes swap
585  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
586  ossimColumnVector3d pMinU(0,1,0);
587  ossimColumnVector3d pMinAxis = LOS.cross(tSlopeN);
588  if (pMinAxis.magnitude() > DBL_EPSILON)
589  {
590  pMinU = pMinAxis.unit();
591  }
592  if (traceDebug())
593  {
594  ossimNotify(ossimNotifyLevel_DEBUG) <<" pMinU: "<<pMinU<<endl;
595  }
596 
597  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
598  // Compute nominal major axis direction from cross
599  // product of minor axis vector and terrain slope normal
600  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
601  ossimColumnVector3d pMaxU = (tSlopeN.cross(pMinU)).unit();
602  if (traceDebug())
603  {
604  ossimNotify(ossimNotifyLevel_DEBUG) <<" pMaxU: "<<pMaxU<<endl;
605  }
606 
607 
608  // Compute elevation angle relative to terrain plane and check for positive
609  double elevAngTerr = acos(pMaxU.dot(LOS));
610  if (traceDebug())
611  {
612  ossimNotify(ossimNotifyLevel_DEBUG)<<" elev angle rel to surface: "
613  <<elevAngTerr*DEG_PER_RAD<<endl;
614  }
615 
616  if (elevAngTerr > 0.0)
617  {
618  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
619  // Compute the LOS error the surface plane
620  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
621  double planeErrorL = eTot/sin(elevAngTerr);
622 
623  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
624  // Project axes to horizontal
625  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
626  ossimColumnVector3d pL = vperp(pMaxU, lsrNorm);
627  ossimColumnVector3d pN = vperp(pMinU, lsrNorm);
628 
629  ossimColumnVector3d eL = pL * planeErrorL;
630  ossimColumnVector3d eN = pN * eTot;
631  double magL = eL.magnitude();
632  double magN = eN.magnitude();
633 
634  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
635  // Compute vertical component due to intersection geometry
636  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
637  ossimColumnVector3d pV = pMaxU - pL;
638  ossimColumnVector3d eV = pV * planeErrorL;
639  double magV = eV.magnitude();
640 
641  if (traceDebug())
642  {
644  <<" Projected horizontal/vertical components...."<<endl
645  <<" pL: "<<pL<<" magL: "<<magL<<endl
646  <<" pN: "<<pN<<" magN: "<<magN<<endl
647  <<" pV: "<<pV<<" magV: "<<magV<<endl;
648  }
649 
650 
651 
652 
653  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
654  // Now compute the contributions of the surface uncertainty
655  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
656 
657  // Terrain slope angle
658  double tSlope = acos(tSlopeN.dot(lsrNorm));
659 
660  // Vertical & horizontal components from surface covariance matrix
661  double surfSigV = sqrt(surfCovMat(3,3));
662  double surfSigH = sqrt((surfCovMat(1,1)+surfCovMat(2,2))/2.0);
663  double surfSigV_h = surfSigH * tan(tSlope);
664 
665  // Effective total vertical error component includes
666  // horizontal uncertainty induced by local slope
667  double vSigTot = sqrt(surfSigV*surfSigV + surfSigV_h*surfSigV_h);
668 
669  // Project to surface normal direction to bring it into the L-surfN plane
670  ossimColumnVector3d s_surfN = (lsrNorm.dot(tSlopeN))*tSlopeN;
671  if (traceDebug())
672  {
673  ossimNotify(ossimNotifyLevel_DEBUG) <<" Surface uncertainty...."<<endl;
674  ossimNotify(ossimNotifyLevel_DEBUG) <<" tSlope angle: "<<tSlope*DEG_PER_RAD<<endl;
675  ossimNotify(ossimNotifyLevel_DEBUG) <<" s_surfN(unit): "<<s_surfN<<endl;
676  }
677  s_surfN = s_surfN * vSigTot;
678  double sigTn = s_surfN.magnitude();
679 
680  // Compute corresponding error in LOS direction
681  double sigVl = sigTn/sin(elevAngTerr);
682 
683  // Resolve total vertical error to components based on intersection geometry
684  ossimColumnVector3d vSigHvec = sigVl * vperp(LOS, lsrNorm);
685  ossimColumnVector3d vSigVvec = sigVl * (LOS.dot(lsrNorm))*lsrNorm;
686  double vSigH = vSigHvec.magnitude();
687  double vSigV = vSigVvec.magnitude();
688  if (traceDebug())
689  {
691  <<" s_surfN: "<<s_surfN
692  <<"\n vSigHvec: "<<vSigHvec
693  <<"\n vSigVvec: "<<vSigVvec<<endl;
694  }
695 
696 
697  if (traceDebug())
698  {
699  ossimNotify(ossimNotifyLevel_DEBUG)<<"----------------------------"<<endl;
700  ossimNotify(ossimNotifyLevel_DEBUG)<<" surfSigH: "<<surfSigH<<endl;
701  ossimNotify(ossimNotifyLevel_DEBUG)<<" surfSigV: "<<surfSigV<<endl;
702  ossimNotify(ossimNotifyLevel_DEBUG)<<" vSigTot: "<<vSigTot<<endl;
703  ossimNotify(ossimNotifyLevel_DEBUG)<<" vSigH: "<<vSigH<<endl;
704  ossimNotify(ossimNotifyLevel_DEBUG)<<" vSigV: "<<vSigV<<endl;
705  ossimNotify(ossimNotifyLevel_DEBUG)<<"----------------------------"<<endl;
706  }
707 
708 
709 
710  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
711  // Add vSigH contribution (vSigH in L-surfN plane)
712  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
713  magL = sqrt(magL*magL + vSigH*vSigH);
714 
715  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
716  // Compute the axes magnitudes & rotation angle
717  // These parameters represent the horizontal error
718  // due to acquisition geometry & terrain slope
719  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
720  double theta;
721  double pMax, pMin;
722  if (magL > magN)
723  {
724  pMax = magL;
725  pMin = magN;
726  theta = atan3(pL[1],pL[0]);
727  }
728  else
729  {
730  pMax = magN;
731  pMin = magL;
732  theta = atan3(pN[1],pN[0]);
733  }
734 
735 
736  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
737  // Form final covariance matrix from axes & rotation angle
738  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
739  NEWMAT::Matrix Cov(2,2);
740  NEWMAT::Matrix Vcomp(2,2);
741  NEWMAT::DiagonalMatrix Dcomp(2);
742 
743  Dcomp(1,1) = pMax*pMax;
744  Dcomp(2,2) = pMin*pMin;
745  Vcomp(1,1) = cos(theta);
746  Vcomp(2,1) = sin(theta);
747  Vcomp(1,2) =-Vcomp(2,1);
748  Vcomp(2,2) = Vcomp(1,1);
749  Cov = Vcomp*Dcomp*Vcomp.t();
750 
751  // Load full 3X3 matrix in local frame
752  NEWMAT::Matrix covMat(3,3);
753  covMat(1,1) = Cov(1,1);
754  covMat(1,2) = Cov(1,2);
755  covMat(1,3) = 0.0;
756  covMat(2,1) = Cov(2,1);
757  covMat(2,2) = Cov(2,2);
758  covMat(2,3) = 0.0;
759  covMat(3,1) = covMat(1,3);
760  covMat(3,2) = covMat(2,3);
761  covMat(3,3) = magV*magV + vSigV*vSigV;
762 
763  // Save the matrix in local frame
764  theCovMat = covMat;
765 
766  } //end if (elevAngTerr > 0.0)
767  else
768  {
769  constructOK = false;
771  << "WARNING: ossimPositionQualityEvaluator::constructMatrix(): "
772  << "\n terrain-referenced elev ang: "<<elevAngTerr*DEG_PER_RAD
773  << std::endl;
774  }
775 
776 
777  return constructOK;
778 }
779 
780 
781 //*****************************************************************************
782 // PRIVATE METHOD: ossimPositionQualityEvaluator::formCovMatrixFromCE_LE()
783 //
784 // Form 3X3 ENU covariance matrix from CE/LE.
785 //
786 //*****************************************************************************
789  const ossim_float64& LE,
790  NEWMAT::Matrix& covMat) const
791 {
792  covMat = 0.0;
793  covMat(1,1) = CE/2.146;
794  covMat(2,2) = CE/2.146;
795  covMat(3,3) = LE/1.6449;
796  covMat(1,1) *= covMat(1,1);
797  covMat(2,2) *= covMat(2,2);
798  covMat(3,3) *= covMat(3,3);
799 
800  return true;
801 }
802 
803 
804 //*****************************************************************************
805 // PRIVATE METHOD: ossimPositionQualityEvaluator::compute90PCE()
806 //
807 // Compute CE @ 90% probability level.
808 //
809 //*****************************************************************************
811 {
812  // Evaluate CE function via linear interpolation
815  ossim_uint32 ndx = int(floor(pRatio*nMultiplier));
816  ossim_float64 alpha;
817 
818  if (ndx == nMultiplier)
819  {
820  alpha = table90[ndx];
821  }
822  else
823  {
824  ossim_float64 fac = (pRatio-(ossim_float64)ndx/(ossim_float64)nMultiplier) / 0.05;
825  alpha = fac * (table90[ndx+1]-table90[ndx]) + table90[ndx];
826  }
827 
829 
830  return CE90;
831 }
832 
833 
834 //*****************************************************************************
835 // PRIVATE METHOD: ossimPositionQualityEvaluator::computeElevAzim()
836 //
837 // Compute elevation and azimuth angles from RPC coefficients.
838 //
839 //*****************************************************************************
842  ossim_float64& elevAngleLOS,
843  ossim_float64& azimAngleLOS) const
844 {
845  //***
846  // Normalize the lat, lon, hgt:
847  //***
848  double nlat = (thePtG.lat - rpc.theLatOffset) / rpc.theLatScale;
849  double nlon = (thePtG.lon - rpc.theLonOffset) / rpc.theLonScale;
850  double nhgt;
851 
852  if( ossim::isnan(thePtG.hgt) )
853  {
854  nhgt = (rpc.theHgtScale - rpc.theHgtOffset) / rpc.theHgtScale;
855  }
856  else
857  {
858  nhgt = (thePtG.hgt - rpc.theHgtOffset) / rpc.theHgtScale;
859  }
860 
861  //***
862  // Compute the numerators & denominators
863  //***
864  double Pu = polynomial(nlat, nlon, nhgt, rpc.theLineNumCoef);
865  double Qu = polynomial(nlat, nlon, nhgt, rpc.theLineDenCoef);
866  double Pv = polynomial(nlat, nlon, nhgt, rpc.theSampNumCoef);
867  double Qv = polynomial(nlat, nlon, nhgt, rpc.theSampDenCoef);
868 
869  //***
870  // Compute the partials of each polynomial wrt lat, lon, hgt
871  //***
872  double dPu_dLat = dPoly_dLat(nlat, nlon, nhgt, rpc.theLineNumCoef);
873  double dQu_dLat = dPoly_dLat(nlat, nlon, nhgt, rpc.theLineDenCoef);
874  double dPv_dLat = dPoly_dLat(nlat, nlon, nhgt, rpc.theSampNumCoef);
875  double dQv_dLat = dPoly_dLat(nlat, nlon, nhgt, rpc.theSampDenCoef);
876  double dPu_dLon = dPoly_dLon(nlat, nlon, nhgt, rpc.theLineNumCoef);
877  double dQu_dLon = dPoly_dLon(nlat, nlon, nhgt, rpc.theLineDenCoef);
878  double dPv_dLon = dPoly_dLon(nlat, nlon, nhgt, rpc.theSampNumCoef);
879  double dQv_dLon = dPoly_dLon(nlat, nlon, nhgt, rpc.theSampDenCoef);
880  double dPu_dHgt = dPoly_dHgt(nlat, nlon, nhgt, rpc.theLineNumCoef);
881  double dQu_dHgt = dPoly_dHgt(nlat, nlon, nhgt, rpc.theLineDenCoef);
882  double dPv_dHgt = dPoly_dHgt(nlat, nlon, nhgt, rpc.theSampNumCoef);
883  double dQv_dHgt = dPoly_dHgt(nlat, nlon, nhgt, rpc.theSampDenCoef);
884 
885  //***
886  // Compute partials of quotients U and V wrt lat, lon, hgt
887  //***
888  double dU_dLat = (Qu*dPu_dLat - Pu*dQu_dLat)/(Qu*Qu);
889  double dU_dLon = (Qu*dPu_dLon - Pu*dQu_dLon)/(Qu*Qu);
890  double dU_dHgt = (Qu*dPu_dHgt - Pu*dQu_dHgt)/(Qu*Qu);
891  double dV_dLat = (Qv*dPv_dLat - Pv*dQv_dLat)/(Qv*Qv);
892  double dV_dLon = (Qv*dPv_dLon - Pv*dQv_dLon)/(Qv*Qv);
893  double dV_dHgt = (Qv*dPv_dHgt - Pv*dQv_dHgt)/(Qv*Qv);
894 
895  //***
896  // Apply necessary scale factors
897  //***
898  dU_dLat *= rpc.theLineScale/rpc.theLatScale;
899  dU_dLon *= rpc.theLineScale/rpc.theLonScale;
900  dU_dHgt *= rpc.theLineScale/rpc.theHgtScale;
901  dV_dLat *= rpc.theSampScale/rpc.theLatScale;
902  dV_dLon *= rpc.theSampScale/rpc.theLonScale;
903  dV_dHgt *= rpc.theSampScale/rpc.theHgtScale;
904 
905  dU_dLat *= DEG_PER_RAD;
906  dU_dLon *= DEG_PER_RAD;
907  dV_dLat *= DEG_PER_RAD;
908  dV_dLon *= DEG_PER_RAD;
909 
910  // Save the partials referenced to ECF
911  ossimEcefPoint location(thePtG);
912  NEWMAT::Matrix jMat(3,3);
913  thePtG.datum()->ellipsoid()->jacobianWrtEcef(location, jMat);
914  ossimDpt pWRTx;
915  ossimDpt pWRTy;
916  ossimDpt pWRTz;
917  // Line
918  pWRTx.u = dU_dLat*jMat(1,1)+dU_dLon*jMat(2,1)+dU_dHgt*jMat(3,1);
919  pWRTy.u = dU_dLat*jMat(1,2)+dU_dLon*jMat(2,2)+dU_dHgt*jMat(3,2);
920  pWRTz.u = dU_dLat*jMat(1,3)+dU_dLon*jMat(2,3)+dU_dHgt*jMat(3,3);
921  // Samp
922  pWRTx.v = dV_dLat*jMat(1,1)+dV_dLon*jMat(2,1)+dV_dHgt*jMat(3,1);
923  pWRTy.v = dV_dLat*jMat(1,2)+dV_dLon*jMat(2,2)+dV_dHgt*jMat(3,2);
924  pWRTz.v = dV_dLat*jMat(1,3)+dV_dLon*jMat(2,3)+dV_dHgt*jMat(3,3);
925 
926  // Form required partials in local frame
927  NEWMAT::Matrix jECF(3,2);
928  jECF(1,1) = pWRTx.u;
929  jECF(1,2) = pWRTx.v;
930  jECF(2,1) = pWRTy.u;
931  jECF(2,2) = pWRTy.v;
932  jECF(3,1) = pWRTz.u;
933  jECF(3,2) = pWRTz.v;
934  NEWMAT::Matrix jLSR(3,2);
935  jLSR = theLocalFrame.ecefToLsrRotMatrix()*jECF;
936  double dU_dx = jLSR(1,1);
937  double dU_dy = jLSR(2,1);
938  double dU_dz = jLSR(3,1);
939  double dV_dx = jLSR(1,2);
940  double dV_dy = jLSR(2,2);
941  double dV_dz = jLSR(3,2);
942 
943  // Compute azimuth & elevation angles
944  double den = dU_dy*dV_dx - dV_dy*dU_dx;
945  double dY = dU_dx*dV_dz - dV_dx*dU_dz;
946  double dX = dV_dy*dU_dz - dU_dy*dV_dz;
947  double dy_dH = dY / den;
948  double dx_dH = dX / den;
949 
950  azimAngleLOS = atan2(dx_dH, dy_dH);
951  elevAngleLOS = atan2(1.0, sqrt(dy_dH*dy_dH+dx_dH*dx_dH));
952 
953  if (traceDebug())
954  {
955  ossimNotify(ossimNotifyLevel_DEBUG)<<"DEBUG: computeElevAzim..."<<endl;
957  " el,az = "<<elevAngleLOS*DEG_PER_RAD<<" "<<azimAngleLOS*DEG_PER_RAD<<endl;
958  }
959 
960  return true;
961 }
962 
963 
964 //*****************************************************************************
965 // PRIVATE METHOD: ossimPositionQualityEvaluator::vperp()
966 //
967 // Perpendicular vector component.
968 //
969 //*****************************************************************************
971 vperp(const ossimColumnVector3d& v1, const ossimColumnVector3d& v2) const
972 {
973 
974  double scale = v1.dot(v2)/v2.dot(v2);
975  ossimColumnVector3d v = v2*scale;
976 
977  ossimColumnVector3d p = v1 - v;
978 
979  return p;
980 }
981 
982 
983 //*****************************************************************************
984 // PRIVATE METHOD: ossimPositionQualityEvaluator::atan3()
985 //
986 // arctan 0-360 counter-clockwise from x-axis
987 //
988 //*****************************************************************************
990  const double x) const
991 {
992  double u,v,pih=0.5*M_PI,result;
993 
994  if (x == 0.0)
995  result = M_PI - pih * ossim::sgn(y);
996  else
997  {
998  if (y == 0.0)
999  {
1000  if (x > 0.0)
1001  result = 0.0;
1002  else
1003  result = M_PI;
1004  }
1005  else
1006  {
1007  u = y/x;
1008  v = fabs(u);
1009  result = atan(v);
1010  result *= v/u;
1011  if (x < 0.0)
1012  result += M_PI;
1013  else
1014  if (result < 0.0)
1015  result += TWO_PI;
1016  }
1017  }
1018 
1019  return result;
1020 
1021 }
1022 
1023 
1024 //*****************************************************************************
1025 // PRIVATE METHOD: ossimPositionQualityEvaluator::polynomial
1026 //
1027 // Evaluates polynomial function.
1028 //
1029 //*****************************************************************************
1031  const double& P,
1032  const double& L,
1033  const double& H,
1034  const double* c) const
1035 {
1036  double r;
1037 
1038  if (theRpcModel.theType == 'A')
1039  {
1040  r = c[ 0] + c[ 1]*L + c[ 2]*P + c[ 3]*H +
1041  c[ 4]*L*P + c[ 5]*L*H + c[ 6]*P*H + c[ 7]*L*P*H +
1042  c[ 8]*L*L + c[ 9]*P*P + c[10]*H*H + c[11]*L*L*L +
1043  c[12]*L*L*P + c[13]*L*L*H + c[14]*L*P*P + c[15]*P*P*P +
1044  c[16]*P*P*H + c[17]*L*H*H + c[18]*P*H*H + c[19]*H*H*H;
1045  }
1046  else
1047  {
1048  r = c[ 0] + c[ 1]*L + c[ 2]*P + c[ 3]*H +
1049  c[ 4]*L*P + c[ 5]*L*H + c[ 6]*P*H + c[ 7]*L*L +
1050  c[ 8]*P*P + c[ 9]*H*H + c[10]*L*P*H + c[11]*L*L*L +
1051  c[12]*L*P*P + c[13]*L*H*H + c[14]*L*L*P + c[15]*P*P*P +
1052  c[16]*P*H*H + c[17]*L*L*H + c[18]*P*P*H + c[19]*H*H*H;
1053  }
1054 
1055  return r;
1056 }
1057 
1058 
1059 //*****************************************************************************
1060 // PRIVATE METHOD: ossimPositionQualityEvaluator::dPoly_dLat
1061 //
1062 // Computes derivative of polynomial WRT normalized latitude P.
1063 //
1064 //*****************************************************************************
1066  const double& P,
1067  const double& L,
1068  const double& H,
1069  const double* c) const
1070 {
1071  double dr;
1072 
1073  if (theRpcModel.theType == 'A')
1074  {
1075  dr = c[2] + c[4]*L + c[6]*H + c[7]*L*H + 2*c[9]*P + c[12]*L*L +
1076  2*c[14]*L*P + 3*c[15]*P*P +2*c[16]*P*H + c[18]*H*H;
1077  }
1078  else
1079  {
1080  dr = c[2] + c[4]*L + c[6]*H + 2*c[8]*P + c[10]*L*H + 2*c[12]*L*P +
1081  c[14]*L*L + 3*c[15]*P*P + c[16]*H*H + 2*c[18]*P*H;
1082  }
1083 
1084  return dr;
1085 }
1086 
1087 
1088 //*****************************************************************************
1089 // PRIVATE METHOD: ossimPositionQualityEvaluator::dPoly_dLon
1090 //
1091 // Computes derivative of polynomial WRT normalized longitude L.
1092 //
1093 //*****************************************************************************
1095  const double& P,
1096  const double& L,
1097  const double& H,
1098  const double* c) const
1099 {
1100  double dr;
1101 
1102  if (theRpcModel.theType == 'A')
1103  {
1104  dr = c[1] + c[4]*P + c[5]*H + c[7]*P*H + 2*c[8]*L + 3*c[11]*L*L +
1105  2*c[12]*L*P + 2*c[13]*L*H + c[14]*P*P + c[17]*H*H;
1106  }
1107  else
1108  {
1109  dr = c[1] + c[4]*P + c[5]*H + 2*c[7]*L + c[10]*P*H + 3*c[11]*L*L +
1110  c[12]*P*P + c[13]*H*H + 2*c[14]*P*L + 2*c[17]*L*H;
1111  }
1112  return dr;
1113 }
1114 
1115 
1116 //*****************************************************************************
1117 // PRIVATE METHOD: ossimPositionQualityEvaluator::dPoly_dHgt
1118 //
1119 // Computes derivative of polynomial WRT normalized height H.
1120 //
1121 //*****************************************************************************
1123  const double& P,
1124  const double& L,
1125  const double& H,
1126  const double* c) const
1127 {
1128  double dr;
1129 
1130  if (theRpcModel.theType == 'A')
1131  {
1132  dr = c[3] + c[5]*L + c[6]*P + c[7]*L*P + 2*c[10]*H + c[13]*L*L +
1133  c[16]*P*P + 2*c[17]*L*H + 2*c[18]*P*H + 3*c[19]*H*H;
1134  }
1135  else
1136  {
1137  dr = c[3] + c[5]*L + c[6]*P + 2*c[9]*H + c[10]*L*P + 2*c[13]*L*H +
1138  2*c[16]*P*H + c[17]*L*L + c[18]*P*P + 3*c[19]*H*H;
1139  }
1140  return dr;
1141 }
ossim_uint32 x
double dPoly_dHgt(const double &nlat, const double &nlon, const double &nhgt, const double *coeffs) const
ossimColumnVector3d cross(const ossimColumnVector3d &rhs) const
bool subtractContributingCovariance(NEWMAT::Matrix &covMat)
Subtract contributing covariance matrix.
std::vector< ossimDpt > pqeImageErrorEllipse_t
const ossim_uint32 nTableEntries
bool getCovMatrix(NEWMAT::Matrix &covMat) const
Covariance matrix access.
T sgn(T x)
Definition: ossimCommon.h:339
const ossim_float64 table90[nTableEntries]
bool addContributingCE_LE(const ossim_float64 &cCE, const ossim_float64 &cLE)
Add contributing CE/LE.
const ossim_float64 Fac1D[NUM_PROB_LEVELS]
double lond() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:97
double dot(const ossimColumnVector3d &rhs) const
#define DEG_PER_RAD
double u
Definition: ossimDpt.h:164
ossim_uint32 y
double polynomial(const double &nlat, const double &nlon, const double &nhgt, const double *coeffs) const
double dPoly_dLat(const double &nlat, const double &nlon, const double &nhgt, const double *coeffs) const
bool computeElevAzim(const pqeRPCModel rpc, ossim_float64 &elevAngleLOS, ossim_float64 &azimAngleLOS) const
ossimColumnVector3d vperp(const ossimColumnVector3d &v1, const ossimColumnVector3d &v2) const
ossimColumnVector3d unit() const
ossim_float64 hgt
Height in meters above the ellipsiod.
Definition: ossimGpt.h:274
bool addContributingCovariance(NEWMAT::Matrix &covMat)
Add contributing covariance matrix.
double latd() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:87
const ossim_float64 Fac2D[NUM_PROB_LEVELS]
bool formCovMatrixFromCE_LE(const ossim_float64 &CE, const ossim_float64 &LE, NEWMAT::Matrix &covMat) const
const ossimDatum * datum() const
datum().
Definition: ossimGpt.h:196
const ossim_uint32 nMultiplier
double ossim_float64
const NEWMAT::Matrix & lsrToEcefRotMatrix() const
#define M_PI
ossim_float64 lon
Definition: ossimGpt.h:266
unsigned int ossim_uint32
virtual const ossimEllipsoid * ellipsoid() const
Definition: ossimDatum.h:60
double height() const
Definition: ossimGpt.h:107
bool constructMatrix(const ossim_float64 &errBiasLOS, const ossim_float64 &errRandLOS, const ossim_float64 &elevAngleLOS, const ossim_float64 &azimAngleLOS, const ossimColumnVector3d &surfN, const NEWMAT::Matrix &surfCovMat)
#define DBL_EPSILON
NEWMAT::Matrix ecefToLsrRotMatrix() const
bool subtractContributingCE_LE(const ossim_float64 &cCE, const ossim_float64 &cLE)
Subtract contributing CE/LE.
double atan3(const ossim_float64 y, const ossim_float64 x) const
double dPoly_dLon(const double &nlat, const double &nlon, const double &nhgt, const double *coeffs) const
void jacobianWrtEcef(const ossimEcefPoint &location, NEWMAT::Matrix &jMat) const
std::ostream & print(std::ostream &out) const
Print method.
#define TWO_PI
const ossim_float64 Fac2D90[NUM_PROB_LEVELS]
ossim_float64 lat
Definition: ossimGpt.h:265
void Jacobi(const SymmetricMatrix &, DiagonalMatrix &)
Definition: jacobi.cpp:110
bool computeCE_LE(const pqeProbLev_t pLev, ossim_float64 &CE, ossim_float64 &LE) const
Compute circular/linear error (CE/LE).
bool extractErrorEllipse(const pqeProbLev_t pLev, pqeErrorEllipse &ellipse)
Extract error ellipse parameters.
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
double v
Definition: ossimDpt.h:165
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91