USGS

Isis 3.0 Object Programmers' Reference

Home

BundleAdjust.cpp
1 #include "BundleAdjust.h"
2 
3 #include <iomanip>
4 #include <iostream>
5 #include <sstream>
6 #include <QFile>
7 #include <QDebug>
8 
9 #include "SpecialPixel.h"
10 #include "BasisFunction.h"
11 #include "LeastSquares.h"
12 #include "CameraGroundMap.h"
13 #include "CameraDetectorMap.h"
14 #include "CameraFocalPlaneMap.h"
15 #include "CameraDistortionMap.h"
16 #include "ControlPoint.h"
17 //#include "SpicePosition.h"
18 //#include "SpiceRotation.h"
19 #include "Application.h"
20 #include "Camera.h"
21 #include "CSVReader.h"
22 #include "SurfacePoint.h"
23 #include "Latitude.h"
24 #include "Longitude.h"
25 #include "iTime.h"
26 #include "StatCumProbDistDynCalc.h"
28 
29 #include "boost/numeric/ublas/matrix_sparse.hpp"
30 #include "boost/numeric/ublas/vector_proxy.hpp"
31 #include "boost/lexical_cast.hpp"
32 
33 #include "boost/numeric/ublas/io.hpp"
34 
35 using namespace boost::numeric::ublas;
36 
37 namespace Isis {
38 
39  static void cholmod_error_handler(int nStatus, const char* file, int nLineNo,
40  const char* message) {
41 
42  QString errlog;
43 
44  errlog = "SPARSE: ";
45  errlog += message;
46 
47  PvlGroup gp(errlog);
48 
49  gp += PvlKeyword("File",file);
50  gp += PvlKeyword("Line_Number", toString(nLineNo));
51  gp += PvlKeyword("Status", toString(nStatus));
52 
53  Application::Log(gp);
54 
55  errlog += ". (See print.prt for details)";
56  throw IException(IException::Unknown, errlog, _FILEINFO_);
57  }
58 
59 
60  BundleAdjust::BundleAdjust(const QString &cnetFile,
61  const QString &cubeList,
62  bool bPrintSummary) {
63  Progress progress;
64  m_bCleanUp = true;
65  m_pCnet = new Isis::ControlNet(cnetFile, &progress);
66  m_pSnList = new Isis::SerialNumberList(cubeList);
67  m_pHeldSnList = NULL;
68  m_bPrintSummary = bPrintSummary;
69  m_strCnetFileName = cnetFile;
70  m_strOutputFilePrefix = "";
71  m_bDeltack = false;
72 
73  Init(&progress);
74 
75  //cumulative residual probability distribution calculator
76  m_cumProRes = new StatCumProbDistDynCalc;
77  m_cumProRes->setQuantiles(101); //set up the cum probibility solver to have a node at every percent of the distribution
78 
79  //initialize maximum likelihood estimation parameters
80  m_wFunc[0]=m_wFunc[1]=m_wFunc[2]=NULL; //initialize to NULL
81  m_maxLikelihoodFlag[0]=m_maxLikelihoodFlag[1]=m_maxLikelihoodFlag[2]=false; //NULL flag by defual
82  m_cumPro=NULL;
83  m_maxLikelihoodIndex=0;
84  m_maxLikelihoodMedianR2Residuals=0.0;
85  }
86 
87 
88  BundleAdjust::BundleAdjust(const QString &cnetFile,
89  const QString &cubeList,
90  const QString &heldList,
91  bool bPrintSummary) {
92  Progress progress;
93  m_bCleanUp = true;
94  m_pCnet = new Isis::ControlNet(cnetFile, &progress);
95  m_pSnList = new Isis::SerialNumberList(cubeList);
96  m_pHeldSnList = new Isis::SerialNumberList(heldList);
97  m_bPrintSummary = bPrintSummary;
98  m_strCnetFileName = cnetFile;
99  m_strOutputFilePrefix = "";
100  m_bDeltack = false;
101 
102  Init(&progress);
103 
104  //cumulative residual probability distribution calculator
105  m_cumProRes = new StatCumProbDistDynCalc;
106  m_cumProRes->setQuantiles(101); //set up the cum probibility solver to have a node at every percent of the distribution
107 
108  //initialize maximum likelihood estimation parameters
109  m_wFunc[0]=m_wFunc[1]=m_wFunc[2]=NULL; //initialize to NULL
110  m_maxLikelihoodFlag[0]=m_maxLikelihoodFlag[1]=m_maxLikelihoodFlag[2]=false; //NULL flag by default
111  m_cumPro=NULL;
112  m_maxLikelihoodIndex=0;
113  }
114 
115 
116  BundleAdjust::BundleAdjust(Isis::ControlNet &cnet,
117  Isis::SerialNumberList &snlist,
118  bool bPrintSummary) {
119  m_bCleanUp = false;
120  m_pCnet = &cnet;
121  m_pSnList = &snlist;
122  m_pHeldSnList = NULL;
123  m_bPrintSummary = bPrintSummary;
124  m_dConvergenceThreshold = 0.; // This is needed for deltack???
125  m_strCnetFileName = "";
126  m_strOutputFilePrefix = "";
127  m_bDeltack = true;
128 
129  Init();
130 
131  //cumulative residual probability distribution calculator
132  m_cumProRes = new StatCumProbDistDynCalc;
133  m_cumProRes->setQuantiles(101); //set up the cum probibility solver to have a node at every percent of the distribution
134 
135  //initialize maximum likelihood estimation parameters
136  m_wFunc[0]=m_wFunc[1]=m_wFunc[2]=NULL; //initialize to NULL
137  m_maxLikelihoodFlag[0]=m_maxLikelihoodFlag[1]=m_maxLikelihoodFlag[2]=false; //NULL flag by defual
138  m_cumPro=NULL;
139  m_maxLikelihoodIndex=0;
140  }
141 
142 
143  BundleAdjust::BundleAdjust(Isis::ControlNet &cnet,
144  Isis::SerialNumberList &snlist,
145  Isis::SerialNumberList &heldsnlist,
146  bool bPrintSummary) {
147  m_bCleanUp = false;
148  m_pCnet = &cnet;
149  m_pSnList = &snlist;
150  m_pHeldSnList = &heldsnlist;
151  m_bPrintSummary = bPrintSummary;
152  m_strCnetFileName = "";
153  m_strOutputFilePrefix = "";
154  m_bDeltack = false;
155 
156  Init();
157 
158  //cumulative residual probability distribution calculator
159  m_cumProRes = new StatCumProbDistDynCalc;
160  m_cumProRes->setQuantiles(101); //set up the cum probibility solver to have a node at every percent of the distribution
161 
162  //initialize maximum likelihood estimation parameters
163  m_wFunc[0]=m_wFunc[1]=m_wFunc[2]=NULL; //initialize to NULL
164  m_maxLikelihoodFlag[0]=m_maxLikelihoodFlag[1]=m_maxLikelihoodFlag[2]=false; //NULL flag by defual
165  m_cumPro=NULL;
166  m_maxLikelihoodIndex=0;
167  }
168 
169 
170  BundleAdjust::~BundleAdjust() {
171  // If we have ownership
172  if (m_bCleanUp) {
173  delete m_pCnet;
174  delete m_pSnList;
175 
176  if (m_nHeldImages > 0)
177  delete m_pHeldSnList;
178 
179  if (m_bObservationMode)
180  delete m_pObsNumList;
181  }
182 
183  if ( m_pLsq )
184  delete m_pLsq;
185 
186  if ( m_strSolutionMethod == "SPARSE" )
187  freeCholMod();
188 
189  //delete residual cumulative probability calculator
190  delete m_cumProRes;
191 
192  //deleting dynamically allocated classes used for maximum likelihood estimation
193  delete m_wFunc[0];
194  delete m_wFunc[1];
195  delete m_wFunc[2];
196  delete m_cumPro;
197  }
198 
199 
208  void BundleAdjust::Init(Progress *progress) {
209 //printf("BOOST_UBLAS_CHECK_ENABLE = %d\n", BOOST_UBLAS_CHECK_ENABLE);
210 //printf("BOOST_UBLAS_TYPE_CHECK = %d\n", BOOST_UBLAS_TYPE_CHECK);
211 
212 // m_pProgressBar = progress;
213 
214  m_dError = DBL_MAX;
215  m_bSimulatedData = true;
216  m_bObservationMode = false;
217  m_strSolutionMethod = "SPECIALK";
218  m_pObsNumList = NULL;
219  m_pLsq = NULL;
220  m_dElapsedTimeErrorProp = 0.0;
221  m_dElapsedTime = 0.0;
222  m_dRejectionMultiplier = 3.;
223 
224  // Get the cameras set up for all images
225  m_pCnet->SetImages(*m_pSnList, progress);
226 
227  // clear JigsawRejected flags
228  m_pCnet->ClearJigsawRejected();
229 
230  m_nHeldImages = 0;
231  int nImages = m_pSnList->size();
232 
233  // Create the image index
234  if (m_pHeldSnList != NULL) {
235  //Check to make sure held images are in the control net
236  CheckHeldList();
237 
238  // Get a count of held images too
239  int count = 0;
240  for ( int i = 0; i < nImages; i++ ) {
241  if ( m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i)) )
242  m_nHeldImages++;
243 
244  m_nImageIndexMap.push_back(count);
245  count++;
246  }
247  }
248  else {
249  for (int i = 0; i < nImages; i++)
250  m_nImageIndexMap.push_back(i);
251  }
252 
253  FillPointIndexMap();
254 
255  // Set default variables to solve for
256  m_bSolveTwist = true;
257  m_bSolveRadii = false;
258  m_bUpdateCubes = false;
259  m_bErrorPropagation = false;
260  m_bMaxIterationsReached = false;
261  m_cmatrixSolveType = AnglesOnly;
262  m_spacecraftPositionSolveType = Nothing;
263  m_nCKDegree = 2;
264  m_nsolveCKDegree = m_nCKDegree;
265  m_nSPKDegree = 2;
266  m_nsolveSPKDegree = m_nSPKDegree;
267  m_nNumberCamAngleCoefSolved = 1;
268  m_nNumberCamPosCoefSolved = 1;
269  m_nUnknownParameters = 0;
270  m_bOutputStandard = true;
271  m_bOutputCSV = true;
272  m_bOutputResiduals = true;
273  m_nPositionType = SpicePosition::PolyFunction;
274  m_nPointingType = SpiceRotation::PolyFunction;
275  m_bSolvePolyOverPointing = false;
276  m_bSolvePolyOverHermite = false;
277 
278  m_idMinSigmaLatitude = "";
279  m_idMaxSigmaLatitude = "";
280  m_idMinSigmaLongitude = "";
281  m_idMaxSigmaLongitude = "";
282  m_idMinSigmaRadius = "";
283  m_idMaxSigmaRadius = "";
284 
285  m_dmaxSigmaLatitude = 0.0;
286  m_dmaxSigmaLongitude = 0.0;
287  m_dmaxSigmaRadius = 0.0;
288 
289  m_dminSigmaLatitude = 1.0e+12;
290  m_dminSigmaLongitude = 1.0e+12;
291  m_dminSigmaRadius = 1.0e+12;
292 
293  m_dGlobalLatitudeAprioriSigma = 1000.0;
294  m_dGlobalLongitudeAprioriSigma = 1000.0;
295  m_dGlobalRadiusAprioriSigma = 1000.0;
296 // m_dGlobalSurfaceXAprioriSigma = 1000.0;
297 // m_dGlobalSurfaceYAprioriSigma = 1000.0;
298 // m_dGlobalSurfaceZAprioriSigma = 1000.0;
299 // m_dGlobalSpacecraftPositionAprioriSigma = -1.0;
300 // m_dGlobalSpacecraftVelocityAprioriSigma = -1.0;
301 // m_dGlobalSpacecraftAccelerationAprioriSigma = -1.0;
302 
303 // m_dGlobalCameraAnglesAprioriSigma = -1.0;
304 // m_dGlobalCameraAngularVelocityAprioriSigma = -1.0;
305 // m_dGlobalCameraAngularAccelerationAprioriSigma = -1.0;
306 
307  m_dGlobalSpacecraftPositionWeight = 0.0;
308  m_dGlobalSpacecraftVelocityWeight = 0.0;
309  m_dGlobalSpacecraftAccelerationWeight = 0.0;
310  m_dGlobalCameraAnglesWeight = 0.0;
311  m_dGlobalCameraAngularVelocityWeight = 0.0;
312  m_dGlobalCameraAngularAccelerationWeight = 0.0;
313 
314  m_dConvergenceThreshold = 1.0e-10;
315  m_nRejectedObservations = 0;
316 
317  if (!m_bSolveRadii)
318  m_dGlobalRadiusAprioriSigma *= -1.0;
319 
320  // (must be a smarter way)
321  // get target body radii and body
322  // specific conversion factors between
323  // radians and meters
324  // need validity checks and different
325  // conversion factors for lat and long
326  m_BodyRadii[0] = m_BodyRadii[1] = m_BodyRadii[2] = Distance();
327  Camera *pCamera = m_pCnet->Camera(0);
328  if (pCamera) {
329  pCamera->radii(m_BodyRadii); // meters
330 
331 // printf("radii: %lf %lf %lf\n",m_BodyRadii[0],m_BodyRadii[1],m_BodyRadii[2]);
332 
333  if (m_BodyRadii[0] >= Distance(0, Distance::Meters)) {
334  m_dMTR = 0.001 / m_BodyRadii[0].kilometers(); // at equator
335  m_dRTM = 1.0 / m_dMTR;
336  }
337 // printf("MTR: %lf\nRTM: %lf\n",m_dMTR,m_dRTM);
338  }
339 
340  // TODO: Need to have some validation code to make sure everything is
341  // on the up-and-up with the control network. Add checks for multiple
342  // networks, images without any points, and points on images removed from
343  // the control net (when we start adding software to remove points with high
344  // residuals) and ?. For "deltack" a single measure on a point is allowed
345  // so skip the test.
346  if (!m_bDeltack)
347  validateNetwork();
348  }
349 
350 
362  bool BundleAdjust::validateNetwork() {
363  printf("Validating network...\n");
364 
365  // verify measures exist for all images
366  int nimagesWithInsufficientMeasures = 0;
367  QString msg = "Images with one or less measures:\n";
368  int nImages = m_pSnList->size();
369  for (int i = 0; i < nImages; i++) {
370  int nMeasures = m_pCnet->GetNumberOfValidMeasuresInImage(m_pSnList->serialNumber(i));
371 
372  if ( nMeasures > 1 )
373  continue;
374 
375  nimagesWithInsufficientMeasures++;
376  msg += m_pSnList->fileName(i) + ": " + toString(nMeasures) + "\n";
377  }
378  if ( nimagesWithInsufficientMeasures > 0 ) {
379  throw IException(IException::User, msg, _FILEINFO_);
380  }
381 
382  printf("Validation complete!...\n");
383 
384  return true;
385  }
386 
390  bool BundleAdjust::initializeCholMod() {
391 
392  if( m_nRank <= 0 )
393  return false;
394 
395  m_pTriplet = NULL;
396 
397  cholmod_start(&m_cm);
398 
399  // set user-defined cholmod error handler
400  m_cm.error_handler = cholmod_error_handler;
401 
402  // testing not using metis
403  m_cm.nmethods = 1;
404  m_cm.method[0].ordering = CHOLMOD_AMD;
405 
406  // set size of sparse block normal equations matrix
407  m_SparseNormals.setNumberOfColumns( Observations() );
408 
409  return true;
410  }
411 
412 
416  bool BundleAdjust::freeCholMod() {
417 
418  cholmod_free_triplet(&m_pTriplet, &m_cm);
419  cholmod_free_sparse(&m_N, &m_cm);
420  cholmod_free_factor(&m_L, &m_cm);
421 
422  cholmod_finish(&m_cm);
423 
424  return true;
425  }
426 
427 
432  void BundleAdjust::FillPointIndexMap() {
433 
434  // Create a lookup table of ignored, and fixed points
435  // TODO Deal with edit lock points
436  m_nFixedPoints = m_nIgnoredPoints = 0;
437  int count = 0;
438  int nObjectPoints = m_pCnet->GetNumPoints();
439 
440  for (int i = 0; i < nObjectPoints; i++) {
441  const ControlPoint *point = m_pCnet->GetPoint(i);
442 
443  if (point->IsIgnored()) {
444  m_nPointIndexMap.push_back(-1);
445  m_nIgnoredPoints++;
446  continue;
447  }
448 
449  else if (point->GetType() == ControlPoint::Fixed) {
450  m_nFixedPoints++;
451 
452  if ( m_strSolutionMethod == "SPECIALK" ||
453  m_strSolutionMethod == "SPARSE" ||
454  m_strSolutionMethod == "OLDSPARSE" ) {
455  m_nPointIndexMap.push_back(count);
456  count++;
457  }
458  else
459  m_nPointIndexMap.push_back(-1);
460  }
461 
462  else {
463  m_nPointIndexMap.push_back(count);
464  count++;
465  }
466  }
467  }
468 
469 
474  void BundleAdjust::CheckHeldList() {
475  for (int ih = 0; ih < m_pHeldSnList->size(); ih++) {
476  if (!(m_pSnList->hasSerialNumber(m_pHeldSnList->serialNumber(ih)))) {
477  QString msg = "Held image [" + m_pHeldSnList->serialNumber(ih)
478  + "not in FROMLIST";
479  throw IException(IException::User, msg, _FILEINFO_);
480  }
481  }
482  }
483 
484 
490  void BundleAdjust::ComputeNumberPartials() {
491  m_nNumImagePartials = 0;
492 
493  if (m_cmatrixSolveType != None) {
494  // Solve for ra/dec always
495  m_nNumImagePartials = 2;
496 
497  // Do we solve for twist
498  if (m_bSolveTwist)
499  m_nNumImagePartials++;
500 
501  // Do we solve for angles only, +velocity, or +velocity and acceleration, or all coefficients
502  m_nNumImagePartials *= m_nNumberCamAngleCoefSolved;
503  }
504 
505  if (m_spacecraftPositionSolveType != Nothing) {
506 
507  // Do we solve for position and velocity, position, velocity and acceleration, or position only
508 // if (m_spacecraftPositionSolveType == Position)
509 // nImagePosPartials = 3;
510 // else if (m_spacecraftPositionSolveType == PositionVelocity)
511 // nImagePosPartials = 6;
512 // else if (m_spacecraftPositionSolveType == PositionVelocityAcceleration)
513 // nImagePosPartials = 9;
514 
515  // account for number of coefficients in "solve" polynomial
516  m_nNumImagePartials += 3.0*m_nNumberCamPosCoefSolved;
517 
518 // m_nNumImagePartials += nImagePosPartials;
519  }
520 
521  // Revised to solve for x/y/z always
522  // Solve for lat/lon always
523  // 2010-03-01 KLE now always solving for all 3 coordinates,
524  // but now, we "hold", "fix", or constrain via weights
525  m_nNumPointPartials = 3;
526 
527  // Test code to match old test runs which don't solve for radius
528  if ( m_strSolutionMethod != "SPECIALK" &&
529  m_strSolutionMethod != "SPARSE" &&
530  m_strSolutionMethod != "OLDSPARSE" ) {
531  m_nNumPointPartials = 2;
532 
533  if (m_bSolveRadii)
534  m_nNumPointPartials++;
535  }
536  }
537 
538 
542  void BundleAdjust::ComputeImageParameterWeights() {
543  // size and initialize to 0.0
544  m_dImageParameterWeights.resize(m_nNumImagePartials);
545  for (int i = 0; i < m_nNumImagePartials; i++)
546  m_dImageParameterWeights[i] = 0.0;
547 
548  int nIndex = 0;
549  if (m_spacecraftPositionSolveType == PositionOnly) {
550  m_dImageParameterWeights[0] = m_dGlobalSpacecraftPositionWeight;
551  m_dImageParameterWeights[1] = m_dGlobalSpacecraftPositionWeight;
552  m_dImageParameterWeights[2] = m_dGlobalSpacecraftPositionWeight;
553  nIndex += 3;
554  }
555  else if (m_spacecraftPositionSolveType == PositionVelocity) {
556  m_dImageParameterWeights[0] = m_dGlobalSpacecraftPositionWeight;
557  m_dImageParameterWeights[1] = m_dGlobalSpacecraftVelocityWeight;
558  m_dImageParameterWeights[2] = m_dGlobalSpacecraftPositionWeight;
559  m_dImageParameterWeights[3] = m_dGlobalSpacecraftVelocityWeight;
560  m_dImageParameterWeights[4] = m_dGlobalSpacecraftPositionWeight;
561  m_dImageParameterWeights[5] = m_dGlobalSpacecraftVelocityWeight;
562  nIndex += 6;
563  }
564  else if (m_spacecraftPositionSolveType >= PositionVelocityAcceleration) {
565  m_dImageParameterWeights[0] = m_dGlobalSpacecraftPositionWeight;
566  m_dImageParameterWeights[1] = m_dGlobalSpacecraftVelocityWeight;
567  m_dImageParameterWeights[2] = m_dGlobalSpacecraftAccelerationWeight;
568  m_dImageParameterWeights[3] = m_dGlobalSpacecraftPositionWeight;
569  m_dImageParameterWeights[4] = m_dGlobalSpacecraftVelocityWeight;
570  m_dImageParameterWeights[5] = m_dGlobalSpacecraftAccelerationWeight;
571  m_dImageParameterWeights[6] = m_dGlobalSpacecraftPositionWeight;
572  m_dImageParameterWeights[7] = m_dGlobalSpacecraftVelocityWeight;
573  m_dImageParameterWeights[8] = m_dGlobalSpacecraftAccelerationWeight;
574  nIndex += 9;
575  }
576 
577  if (m_cmatrixSolveType == AnglesOnly) {
578  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
579  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
580 
581  if (m_bSolveTwist)
582  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
583  }
584  else if (m_cmatrixSolveType == AnglesVelocity) {
585  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
586  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularVelocityWeight;
587  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
588  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularVelocityWeight;
589  if (m_bSolveTwist) {
590  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
591  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularVelocityWeight;
592  }
593  }
594  if (m_cmatrixSolveType >= AnglesVelocityAcceleration) {
595  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
596  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularVelocityWeight;
597  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularAccelerationWeight;
598  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
599  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularVelocityWeight;
600  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularAccelerationWeight;
601 
602  if (m_bSolveTwist) {
603  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAnglesWeight;
604  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularVelocityWeight;
605  m_dImageParameterWeights[nIndex++] = m_dGlobalCameraAngularAccelerationWeight;
606  }
607  }
608  }
609 
610 
617  void BundleAdjust::SetObservationMode(bool observationMode) {
618  m_bObservationMode = observationMode;
619 
620  if (!m_bObservationMode)
621  return;
622 
623  // Create the observation number list
624  m_pObsNumList = new Isis::ObservationNumberList(m_pSnList);
625 
626  if (m_pHeldSnList == NULL)
627  return;
628 
629  // make sure ALL images in an observation are held if any are
630  for (int ih = 0; ih < m_pHeldSnList->size(); ih++) {
631  for (int isn = 0; isn < m_pSnList->size(); isn++) {
632  if (m_pHeldSnList->observationNumber(ih) != m_pSnList->observationNumber(isn))
633  continue;
634 
635  if (m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(isn)))
636  continue;
637 
638  QString msg = "Cube file " + m_pSnList->fileName(isn)
639  + " must be held since it is on the same observation as held cube "
640  + m_pHeldSnList->fileName(ih);
641  throw IException(IException::User, msg, _FILEINFO_);
642  }
643  }
644  }
645 
646 
652  void BundleAdjust::SetDecompositionMethod(DecompositionMethod method) {
653  m_decompositionMethod = method;
654  }
655 
656 
660  void BundleAdjust::SetSolveCmatrix(CmatrixSolveType type) {
661  m_cmatrixSolveType = type;
662 
663  switch (type) {
664  case BundleAdjust::AnglesOnly:
665  m_nNumberCamAngleCoefSolved = 1;
666  break;
667  case BundleAdjust::AnglesVelocity:
668  m_nNumberCamAngleCoefSolved = 2;
669  break;
670  case BundleAdjust::AnglesVelocityAcceleration:
671  m_nNumberCamAngleCoefSolved = 3;
672  break;
673  case BundleAdjust::CKAll:
674  m_nNumberCamAngleCoefSolved = m_nsolveCKDegree + 1;
675  break;
676  default:
677  m_nNumberCamAngleCoefSolved = 0;
678  break;
679  }
680 
681  m_dGlobalCameraAnglesAprioriSigma.resize(m_nNumberCamAngleCoefSolved);
682  for( int i = 0; i < m_nNumberCamAngleCoefSolved; i++ )
683  m_dGlobalCameraAnglesAprioriSigma[i] = -1.0;
684 
685  // Make sure the degree of the polynomial the user selected for
686  // the camera angles fit is sufficient for the selected CAMSOLVE
687  if (m_nNumberCamAngleCoefSolved > m_nsolveCKDegree + 1) {
688  QString msg = "Selected SolveCameraDegree " + toString(m_nsolveCKDegree)
689  + " is not sufficient for the CAMSOLVE";
690  throw IException(IException::User, msg, _FILEINFO_);
691  }
692  }
693 
694 
698  void BundleAdjust::SetSolveSpacecraftPosition(SpacecraftPositionSolveType type) {
699  m_spacecraftPositionSolveType = type;
700 
701  switch (type) {
702  case BundleAdjust::PositionOnly:
703  m_nNumberCamPosCoefSolved = 1;
704  break;
705  case BundleAdjust::PositionVelocity:
706  m_nNumberCamPosCoefSolved = 2;
707  break;
708  case BundleAdjust::PositionVelocityAcceleration:
709  m_nNumberCamPosCoefSolved = 3;
710  break;
711  case BundleAdjust::SPKAll:
712  m_nNumberCamPosCoefSolved = m_nsolveSPKDegree + 1;
713  break;
714  default:
715  m_nNumberCamPosCoefSolved = 0;
716  break;
717  }
718 
719  m_dGlobalSpacecraftPositionAprioriSigma.resize(m_nNumberCamPosCoefSolved);
720  for( int i = 0; i < m_nNumberCamPosCoefSolved; i++ )
721  m_dGlobalSpacecraftPositionAprioriSigma[i] = -1.0;
722 
723  // Make sure the degree of the polynomial the user selected for
724  // the camera position fit is sufficient for the selected CAMSOLVE
725  if (m_nNumberCamPosCoefSolved > m_nsolveSPKDegree + 1) {
726  QString msg = "Selected SolveCameraPositionDegree " + toString(m_nsolveSPKDegree)
727  + " is not sufficient for the CAMSOLVE";
728  throw IException(IException::User, msg, _FILEINFO_);
729  }
730  }
731 
732 
738  int BundleAdjust::BasisColumns() {
739  m_nImageParameters = Observations() * m_nNumImagePartials;
740 
741  int nPointParameterColumns = m_pCnet->GetNumValidPoints() * m_nNumPointPartials;
742 
743  if (m_strSolutionMethod != "SPECIALK" &&
744  m_strSolutionMethod != "SPARSE" &&
745  m_strSolutionMethod != "OLDSPARSE")
746  nPointParameterColumns -= m_nFixedPoints * m_nNumPointPartials;
747 
748  return m_nImageParameters + nPointParameterColumns;
749  }
750 
751 
755  void BundleAdjust::Initialize() {
756 
757  // size of reduced normals matrix
758  m_nRank = m_nNumImagePartials * Observations();
759 
760  int n3DPoints = m_pCnet->GetNumValidPoints();
761 
762  if ( m_decompositionMethod == SPECIALK ) {
763  m_Normals.resize(m_nRank); // set size of reduced normals matrix
764  m_Normals.clear(); // zero all elements
765  m_Qs_SPECIALK.resize(n3DPoints);
766  }
767  else if ( m_decompositionMethod == CHOLMOD ) {
768  m_Qs_CHOLMOD.resize(n3DPoints);
769  }
770 
771  m_nUnknownParameters = m_nRank + 3 * n3DPoints;
772 
773  m_nRejectedObservations = 0;
774 
775  m_Image_Solution.resize(m_nRank);
776  m_Image_Corrections.resize(m_nRank);
777  m_NICs.resize(n3DPoints);
778  m_Point_Corrections.resize(n3DPoints);
779  m_Point_Weights.resize(n3DPoints);
780  m_Point_AprioriSigmas.resize(n3DPoints);
781 
782  // initialize NICS, Qs, and point correction vectors to zero
783  for (int i = 0; i < n3DPoints; i++) {
784  m_NICs[i].clear();
785 
786  // TODO_CHOLMOD: is this needed with new cholmod implementation?
787  if ( m_decompositionMethod == SPECIALK )
788  m_Qs_SPECIALK[i].clear();
789  else if ( m_decompositionMethod == CHOLMOD )
790  m_Qs_CHOLMOD[i].clear();
791 
792  m_Point_Corrections[i].clear();
793  m_Point_Weights[i].clear();
794  m_Point_AprioriSigmas[i].clear();
795  }
796 
797  m_bConverged = false; // flag indicating convergence
798  m_bError = false; // flag indicating general bundle error
799 
800  // convert apriori sigmas into weights (if they're negative or zero, we don't use them)
801  SetSpaceCraftWeights();
802 
803  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
804  // initializations for cholmod
805  if ( m_strSolutionMethod == "SPARSE" )
806  initializeCholMod();
807  }
808 
809  void BundleAdjust::SetSpaceCraftWeights() {
810 
811 // if (m_dGlobalSpacecraftPositionAprioriSigma > 0.0) {
812 // m_dGlobalSpacecraftPositionWeight
813 // = 1.0 / (m_dGlobalSpacecraftPositionAprioriSigma * m_dGlobalSpacecraftPositionAprioriSigma * 1.0e-6);
814 // }
815 //
816 // if (m_dGlobalSpacecraftVelocityAprioriSigma > 0.0) {
817 // m_dGlobalSpacecraftVelocityWeight
818 // = 1.0 / (m_dGlobalSpacecraftVelocityAprioriSigma * m_dGlobalSpacecraftVelocityAprioriSigma * 1.0e-6);
819 // }
820 //
821 // if (m_dGlobalSpacecraftAccelerationAprioriSigma > 0.0) {
822 // m_dGlobalSpacecraftAccelerationWeight
823 // = 1.0 / (m_dGlobalSpacecraftAccelerationAprioriSigma * m_dGlobalSpacecraftAccelerationAprioriSigma * 1.0e-6);
824 // }
825 
826  if ( m_nNumberCamPosCoefSolved >= 1 ) {
827  if ( m_dGlobalSpacecraftPositionAprioriSigma[0] > 0.0 ) {
828  m_dGlobalSpacecraftPositionWeight
829  = 1.0 / (m_dGlobalSpacecraftPositionAprioriSigma[0] * m_dGlobalSpacecraftPositionAprioriSigma[0] * 1.0e-6);
830  }
831  }
832 
833  if ( m_nNumberCamPosCoefSolved >= 2 ) {
834  if ( m_dGlobalSpacecraftPositionAprioriSigma[1] > 0.0 ) {
835  m_dGlobalSpacecraftVelocityWeight
836  = 1.0 / (m_dGlobalSpacecraftPositionAprioriSigma[1] * m_dGlobalSpacecraftPositionAprioriSigma[1] * 1.0e-6);
837  }
838  }
839 
840  if ( m_nNumberCamPosCoefSolved >= 3 ) {
841  if( m_dGlobalSpacecraftPositionAprioriSigma[2] > 0.0 ) {
842  m_dGlobalSpacecraftAccelerationWeight
843  = 1.0 / (m_dGlobalSpacecraftPositionAprioriSigma[2] * m_dGlobalSpacecraftPositionAprioriSigma[2] * 1.0e-6);
844  }
845  }
846 
847  if ( m_nNumberCamAngleCoefSolved >= 1 ) {
848  if ( m_dGlobalCameraAnglesAprioriSigma[0] > 0.0 ) {
849  m_dGlobalCameraAnglesWeight
850  = 1.0 / (m_dGlobalCameraAnglesAprioriSigma[0] * m_dGlobalCameraAnglesAprioriSigma[0] * DEG2RAD * DEG2RAD);
851  }
852  }
853 
854  if ( m_nNumberCamAngleCoefSolved >= 2 ) {
855  if ( m_dGlobalCameraAnglesAprioriSigma[1] > 0.0 ) {
856  m_dGlobalCameraAngularVelocityWeight
857  = 1.0 / (m_dGlobalCameraAnglesAprioriSigma[1] * m_dGlobalCameraAnglesAprioriSigma[1] * DEG2RAD * DEG2RAD);
858  }
859  }
860 
861  if ( m_nNumberCamAngleCoefSolved >= 3 ) {
862  if( m_dGlobalCameraAnglesAprioriSigma[2] > 0.0 ) {
863  m_dGlobalCameraAngularAccelerationWeight
864  = 1.0 / (m_dGlobalCameraAnglesAprioriSigma[2] * m_dGlobalCameraAnglesAprioriSigma[2] * DEG2RAD * DEG2RAD);
865  }
866  }
867  }
868 
869 
883  bool BundleAdjust::SolveCholesky() {
884 
885  // throw error if a frame camera is included AND if m_bSolvePolyOverHermite
886  // is set to true (can only use for line scan or radar)
887 // if (m_bSolvePolyOverHermite == true) {
888 // int nImages = Images();
889 // for (int i = 0; i < nImages; i++) {
890 // if (m_pCnet->Camera(i)->GetCameraType() == 0) {
891 // QString msg = "At least one sensor is a frame camera. Spacecraft Option OVERHERMITE is not valid for frame cameras\n";
892 // throw IException(IException::User, msg, _FILEINFO_);
893 // }
894 // }
895 // }
896 
897 // double averageError;
898  std::vector<int> observationInitialValueIndex; // image index for observation inital values
899  int iIndex = -1; // image index for initial spice for an observation
900  int oIndex = -1; // Index of current observation
901 
902  ComputeNumberPartials();
903 
904  if (m_bObservationMode)
905  observationInitialValueIndex.assign(m_pObsNumList->observationSize(), -1);
906 
907  // std::cout << observationInitialValueIndex << std::endl;
908 
909  for (int i = 0; i < Images(); i++) {
910  Camera *pCamera = m_pCnet->Camera(i);
911 
912  if (m_bObservationMode) {
913  oIndex = i;
914  oIndex = m_pObsNumList->observationNumberMapIndex(oIndex); // get observation index for this image
915  iIndex = observationInitialValueIndex[oIndex]; // get image index for initial observation values
916  }
917 
918  if (m_cmatrixSolveType != None) {
919  // For observations, find the index of the first image and use its polynomial for the observation
920  // initial coefficient values. Initialize indices to -1
921 
922  // Fit the camera pointing to an equation
923  SpiceRotation *pSpiceRot = pCamera->instrumentRotation();
924  if (!m_bObservationMode) {
925  pSpiceRot->SetPolynomialDegree(m_nCKDegree); // Set the ck polynomial fit degree
926  pSpiceRot->SetPolynomial(m_nPointingType);
927  pSpiceRot->SetPolynomialDegree(m_nsolveCKDegree); // Update to the solve polynomial fit degree
928  }
929  else {
930  // Index of image to use for initial values is set already so set polynomial to initial values
931  if (iIndex >= 0) {
932  SpiceRotation *pOrot = m_pCnet->Camera(iIndex)->instrumentRotation(); //Observation rotation
933  std::vector<double> anglePoly1, anglePoly2, anglePoly3;
934  pOrot->GetPolynomial(anglePoly1, anglePoly2, anglePoly3);
935  double baseTime = pOrot->GetBaseTime();
936  double timeScale = pOrot->GetTimeScale();
937  pSpiceRot->SetPolynomialDegree(m_nsolveCKDegree); // Update to the solve polynomial fit degree
938  pSpiceRot->SetOverrideBaseTime(baseTime, timeScale);
939  pSpiceRot->SetPolynomial(anglePoly1, anglePoly2, anglePoly3, m_nPointingType);
940  }
941  else {
942  // Index of image to use for initial observation values has not been assigned yet so use this image
943  pSpiceRot->SetPolynomialDegree(m_nCKDegree);
944  pSpiceRot->SetPolynomial(m_nPointingType);
945  pSpiceRot->SetPolynomialDegree(m_nsolveCKDegree); // Update to the solve polynomial fit degree
946  observationInitialValueIndex[oIndex] = i;
947  }
948  }
949  }
950 
951  if (m_spacecraftPositionSolveType != Nothing) {
952  // Set the spacecraft position to an equation
953  SpicePosition *pSpicePos = pCamera->instrumentPosition();
954 
955  if (!m_bObservationMode) {
956  pSpicePos->SetPolynomialDegree(m_nSPKDegree); // Set the SPK polynomial fit degree
957  pSpicePos->SetPolynomial(m_nPositionType);
958  pSpicePos->SetPolynomialDegree(m_nsolveSPKDegree); // Update to the solve polynomial fit degree
959  }
960  else {
961  // Index of image to use for initial values is set already so set polynomial to initial values
962  if (iIndex >= 0) {
963  SpicePosition *pOpos = m_pCnet->Camera(iIndex)->instrumentPosition(); //Observation position
964  std::vector<double> posPoly1, posPoly2, posPoly3;
965  pOpos->GetPolynomial(posPoly1, posPoly2, posPoly3);
966  double baseTime = pOpos->GetBaseTime();
967  double timeScale = pOpos->GetTimeScale();
968  pSpicePos->SetPolynomialDegree(m_nsolveSPKDegree); // Set the SPK polynomial fit degree
969 // pSpicePos->SetPolynomial();
970  pSpicePos->SetOverrideBaseTime(baseTime, timeScale);
971  pSpicePos->SetPolynomial(posPoly1, posPoly2, posPoly3, m_nPositionType);
972  }
973  else {
974  // Index of image to use for inital observation values has not been assigned yet so use this image
975  pSpicePos->SetPolynomialDegree(m_nSPKDegree); // Set the SPK polynomial fit degree
976  pSpicePos->SetPolynomial(m_nPositionType);
977  pSpicePos->SetPolynomialDegree(m_nsolveSPKDegree); // Update to the solve polynomial fit degree
978  observationInitialValueIndex[oIndex] = i;
979  }
980  }
981  }
982  }
983 
984  Initialize();
985 
986  ComputeImageParameterWeights();
987 
988  // Compute the apriori lat/lons for each nonheld point
989  m_pCnet->ComputeApriori(); // original location
990 
991  InitializePointWeights(); // testing - moved from ::Initalize function
992  InitializePoints(); // New method to set apriori sigmas and surface points
993 
994  // Initialize solution parameters
995  //double sigmaXY, sigmaHat, sigmaX, sigmaY;
996  //sigmaXY = sigmaHat = sigmaX = sigmaY = 0.0;
997  m_nIteration = 1;
998 
999  clock_t t1 = clock();
1000 
1001  double dvtpv = 0.0;
1002  double dSigma0_previous = 0.0;
1003 
1004  Progress progress;
1005 
1006  for (;;) {
1007  printf("starting iteration %d\n", m_nIteration);
1008  clock_t iterationclock1 = clock();
1009 
1010  // send notification to UI indicating "new iteration"
1011  // UI.Notify(BundleEvent.NEW_ITERATION);
1012 
1013  // zero normals (after iteration 0)
1014  if (m_nIteration != 1) {
1015  if ( m_decompositionMethod == SPECIALK )
1016  m_Normals.clear();
1017  else if ( m_decompositionMethod == CHOLMOD )
1018  m_SparseNormals.zeroBlocks();
1019  }
1020 
1021  // form normal equations
1022 // clock_t formNormalsclock1 = clock();
1023 // printf("starting FormNormals\n");
1024 
1025  if (!formNormalEquations()) {
1026  m_bConverged = false;
1027  m_bError = true;
1028  break;
1029  }
1030 // clock_t formNormalsclock2 = clock();
1031 // double dFormNormalsTime = ((formNormalsclock2-formNormalsclock1)/(double)CLOCKS_PER_SEC);
1032 // printf("FormNormals Elapsed Time: %20.10lf\n",dFormNormalsTime);
1033 
1034  // solve system
1035 // clock_t Solveclock1 = clock();
1036 // printf("Starting Solve System\n");
1037 
1038  if (!solveSystem()) {
1039  printf("solve failed!\n");
1040  m_bConverged = false;
1041  m_bError = true;
1042  break;
1043  }
1044 
1045 // clock_t Solveclock2 = clock();
1046 // double dSolveTime = ((Solveclock2-Solveclock1)/(double)CLOCKS_PER_SEC);
1047 // printf("Solve Elapsed Time: %20.10lf\n",dSolveTime);
1048 
1049  // apply parameter corrections
1050 // clock_t Correctionsclock1 = clock();
1051  applyParameterCorrections();
1052 // clock_t Correctionsclock2 = clock();
1053 // double dCorrectionsTime = ((Correctionsclock2-Correctionsclock1)/(double)CLOCKS_PER_SEC);
1054 // printf("Corrections Elapsed Time: %20.10lf\n",dCorrectionsTime);
1055 
1056  // compute residuals
1057 // clock_t Residualsclock1 = clock();
1058 
1059  dvtpv = ComputeResiduals();
1060 // clock_t Residualsclock2 = clock();
1061 // double dResidualsTime = ((Residualsclock2-Residualsclock1)/(double)CLOCKS_PER_SEC);
1062 // printf("Residuals Elapsed Time: %20.10lf\n",dResidualsTime);
1063 
1064  // flag outliers
1065  if ( m_bOutlierRejection ) {
1066  ComputeRejectionLimit(); // compute outlier rejection limit
1067  FlagOutliers();
1068  }
1069 
1070  // variance of unit weight (also reference variance, variance factor, etc.)
1071  m_nDegreesOfFreedom =
1072  m_nObservations + (m_nConstrainedPointParameters + m_nConstrainedImageParameters) - m_nUnknownParameters;
1073 
1074  if (m_nDegreesOfFreedom > 0)
1075  m_dSigma0 = dvtpv / m_nDegreesOfFreedom;
1076  else if (m_bDeltack && m_nDegreesOfFreedom == 0)
1077  m_dSigma0 = dvtpv;
1078  else {
1079  QString msg = "Degrees of Freedom " + toString(m_nDegreesOfFreedom)
1080  + " is invalid (&lt;= 0)!";
1081  throw IException(IException::Io, msg, _FILEINFO_);
1082  }
1083 
1084  m_dSigma0 = sqrt(m_dSigma0);
1085 
1086  printf("Iteration: %d\nSigma0: %20.10lf\n", m_nIteration, m_dSigma0);
1087  printf("Observations: %d\nConstrained Parameters:%d\nUnknowns: %d\nDegrees of Freedom: %d\n",
1088  m_nObservations, m_nConstrainedPointParameters, m_nUnknownParameters, m_nDegreesOfFreedom);
1089 
1090  // check for convergence
1091  if ( !m_bDeltack ) {
1092  if (fabs(dSigma0_previous - m_dSigma0) <= m_dConvergenceThreshold) {
1093  //convergence detected
1094  if (m_maxLikelihoodIndex+1 < 3 && m_maxLikelihoodFlag[m_maxLikelihoodIndex+1]) { //if maximum likelihood tiers are being processed check to see if there's another tier to go //if there's another tier to go check the flag to see if it's enabled
1095  m_maxLikelihoodIndex++; //if there's another tier to go then continue with the next maximum likelihood model
1096  }
1097  else { //otherwise iteration are complete
1098  m_bLastIteration = true;
1099  m_bConverged = true;
1100  printf("Bundle has converged\n");
1101  break;
1102  }
1103  }
1104  }
1105  else {
1106  int nconverged = 0;
1107  int numimgparam = m_Image_Solution.size();
1108  for (int ij = 0; ij < numimgparam; ij++) {
1109  if (fabs(m_Image_Solution(ij)) > m_dConvergenceThreshold)
1110  break;
1111  else
1112  nconverged++;
1113  }
1114 
1115  if ( nconverged == numimgparam ) {
1116  m_bConverged = true;
1117  m_bLastIteration = true;
1118  printf("Deltack Bundle has converged\n");
1119  break;
1120  }
1121  }
1122 
1123  printf("Maximum Likelihood Tier: %d\n",m_maxLikelihoodIndex);
1124  if (m_maxLikelihoodFlag[m_maxLikelihoodIndex]) { //if maximum likelihood estimation is being used
1125  //at the end of every iteration
1126  // reset the tweaking contant to the desired quantile of the |residual| distribution
1127  m_wFunc[m_maxLikelihoodIndex]->setTweakingConstant(m_cumPro->value(m_maxLikelihoodQuan[m_maxLikelihoodIndex]));
1128  // print meadians of residuals
1129  m_maxLikelihoodMedianR2Residuals = m_cumPro->value(0.5);
1130  printf("Median of R^2 residuals: %lf\n",m_maxLikelihoodMedianR2Residuals);
1131  //restart the dynamic calculation of the cumulative probility distribution of |R^2 residuals| --so it will be up to date for the next iteration
1132  m_cumPro->setQuantiles(101);
1133  }
1134 
1135  clock_t iterationclock2 = clock();
1136  double dIterationTime = ((iterationclock2 - iterationclock1) / (double)CLOCKS_PER_SEC);
1137  printf("End of Iteration %d\nElapsed Time: %20.10lf\n", m_nIteration, dIterationTime);
1138 
1139  // send notification to UI indicating "new iteration"
1140  // UI.Notify(BundleEvent.END_ITERATION);
1141 
1142  // check for maximum iterations
1143  if (m_nIteration >= m_nMaxIterations) {
1144  m_bMaxIterationsReached = true;
1145  break;
1146  }
1147 
1148  // restart the dynamic calculation of the cumulative probility distribution of residuals (in unweighted pixels) --so it will be up to date for the next iteration
1149  if (!m_bConverged)
1150  m_cumProRes->setQuantiles(101);
1151 
1152  // if we're using CHOLMOD and still going, release cholmod_factor (if we don't, memory leaks will occur),
1153  // otherwise we need it for error propagation
1154  if ( m_decompositionMethod == CHOLMOD ) {
1155  if (!m_bConverged || (m_bConverged && !m_bErrorPropagation))
1156  cholmod_free_factor(&m_L, &m_cm);
1157  }
1158 
1159  SpecialKIterationSummary();
1160 
1161  m_nIteration++;
1162 
1163  dSigma0_previous = m_dSigma0;
1164  }
1165 
1166  if ( m_bConverged && m_bErrorPropagation ) {
1167  clock_t terror1 = clock();
1168  printf("\nStarting Error Propagation");
1169  errorPropagation();
1170  printf("\n\nError Propagation Complete\n");
1171  clock_t terror2 = clock();
1172  m_dElapsedTimeErrorProp = ((terror2 - terror1) / (double)CLOCKS_PER_SEC);
1173  }
1174 
1175  clock_t t2 = clock();
1176  m_dElapsedTime = ((t2 - t1) / (double)CLOCKS_PER_SEC);
1177 
1178  WrapUp();
1179 
1180  printf("\nGenerating report files\n");
1181  Output();
1182 
1183  printf("\nBundle complete\n");
1184 
1185  SpecialKIterationSummary();
1186 
1187  return true;
1188 
1189  QString msg = "Need to return something here, or just change the whole darn thing? [";
1190 // msg += IString(tol) + "] in less than [";
1191 // msg += IString(m_nMaxIterations) + "] iterations";
1192  throw IException(IException::User, msg, _FILEINFO_);
1193  }
1194 
1195 
1199  bool BundleAdjust::formNormalEquations() {
1200  if ( m_decompositionMethod == CHOLMOD )
1201  return formNormalEquations_CHOLMOD();
1202  else
1203  return formNormalEquations_SPECIALK();
1204 
1205  return false;
1206  }
1207 
1208 
1212  bool BundleAdjust::solveSystem() {
1213  if ( m_decompositionMethod == CHOLMOD )
1214  return solveSystem_CHOLMOD();
1215  else
1216  return solveSystem_SPECIALK();
1217 
1218  return false;
1219  }
1220 
1221 
1225  bool BundleAdjust::formNormalEquations_CHOLMOD() {
1226 // if (m_pProgressBar != NULL)
1227 // {
1228 // m_pProgressBar->SetText("Forming Normal Equations...");
1229 // m_pProgressBar->SetMaximumSteps(m_pCnet->Size());
1230 // m_pProgressBar->CheckStatus();
1231 // }
1232  bool bStatus = false;
1233 
1234  m_nObservations = 0;
1235  m_nConstrainedPointParameters = 0;
1236 
1237  static matrix<double> coeff_image;
1238  static matrix<double> coeff_point3D(2, 3);
1239  static vector<double> coeff_RHS(2);
1240  static symmetric_matrix<double, upper> N22(3); // 3x3 upper triangular
1241 // static compressed_matrix< double> N12(m_nRank, 3); // image parameters x 3 (should this be compressed? We only make one, so probably not)
1242 // static SparseBlockColumnMatrix N12;
1244  static vector<double> n2(3); // 3x1 vector
1245  compressed_vector<double> n1(m_nRank); // image parameters x 1
1246 // vector<double> nj(m_nRank); // image parameters x 1
1247 
1248  m_nj.resize(m_nRank);
1249 
1250  coeff_image.resize(2, m_nNumImagePartials);
1251  //N12.resize(m_nRank, 3);
1252 
1253  // clear N12, n1, and nj
1254  N12.clear();
1255  n1.clear();
1256  m_nj.clear();
1257 
1258  // clear static matrices
1259 // coeff_image.clear();
1260  coeff_point3D.clear();
1261  coeff_RHS.clear();
1262  N22.clear();
1263  n2.clear();
1264 
1265  // loop over 3D points
1266  int nGood3DPoints = 0;
1267  int nRejected3DPoints = 0;
1268  int nPointIndex = 0;
1269  int nImageIndex;
1270  int n3DPoints = m_pCnet->GetNumPoints();
1271 
1272 // char buf[1056];
1273 // sprintf(buf,"\n\t Points:%10d\n", n3DPoints);
1274 // m_fp_log << buf;
1275 // printf("%s", buf);
1276 
1277  printf("\n\n");
1278 
1279  for (int i = 0; i < n3DPoints; i++) {
1280 
1281  const ControlPoint *point = m_pCnet->GetPoint(i);
1282 
1283  if ( point->IsIgnored() )
1284  continue;
1285 
1286  if( point->IsRejected() ) {
1287  nRejected3DPoints++;
1288 // sprintf(buf, "\tRejected %s - 3D Point %d of %d RejLimit = %lf\n", point.Id().toAscii().data(),nPointIndex,n3DPoints,m_dRejectionLimit);
1289 // m_fp_log << buf;
1290 
1291  nPointIndex++;
1292  continue;
1293  }
1294 
1295  // send notification to UI indicating index of point currently being processed
1296  // m_nProcessedPoint = i+1;
1297  // UI.Notify(BundleEvent.NEW_POINT_PROCESSED);
1298 
1299  if ( i != 0 ) {
1300  N22.clear();
1301 // N12.clear();
1302  N12.wipe();
1303  n2.clear();
1304  }
1305 
1306  int nMeasures = point->GetNumMeasures();
1307  // loop over measures for this point
1308  for (int j = 0; j < nMeasures; j++) {
1309 
1310  const ControlMeasure *measure = point->GetMeasure(j);
1311  if ( measure->IsIgnored() )
1312  continue;
1313 
1314  // flagged as "JigsawFail" implies this measure has been rejected
1315  // TODO IsRejected is obsolete -- replace code or add to ControlMeasure
1316  if (measure->IsRejected())
1317  continue;
1318 
1319  // printf(" Processing Measure %d of %d\n", j,nMeasures);
1320 
1321  // fill non-zero indices for this point - do we have to do this?
1322  // see BundleDistanceConstraints.java for code snippet (line 926)
1323 
1324  // Determine the image index
1325  nImageIndex = m_pSnList->serialNumberIndex(measure->GetCubeSerialNumber());
1326  if ( m_bObservationMode )
1327  nImageIndex = ImageIndex(nImageIndex)/m_nNumImagePartials;
1328 
1329  bStatus = ComputePartials_DC(coeff_image, coeff_point3D, coeff_RHS,
1330  *measure, *point);
1331 
1332 // std::cout << coeff_image << std::endl;
1333 // std::cout << coeff_point3D << std::endl;
1334 // std::cout << coeff_RHS << std::endl;
1335 
1336  if ( !bStatus )
1337  continue; // this measure should be flagged as rejected
1338 
1339  // update number of observations
1340  m_nObservations += 2;
1341 
1342  formNormals1_CHOLMOD(N22, N12, n1, n2, coeff_image, coeff_point3D,
1343  coeff_RHS, nImageIndex);
1344  } // end loop over this points measures
1345 
1346  formNormals2_CHOLMOD(N22, N12, n2, m_nj, nPointIndex, i);
1347  nPointIndex++;
1348 
1349 // if (m_pProgressBar != NULL)
1350 // m_pProgressBar->CheckStatus();
1351 
1352  nGood3DPoints++;
1353 
1354  } // end loop over 3D points
1355 
1356  // finally, form the reduced normal equations
1357  formNormals3_CHOLMOD(n1, m_nj);
1358 
1359 // std::cout << m_Normals << std::endl;
1360 // m_SparseNormals.print(std::cout);
1361 
1362  // update number of unknown parameters
1363  m_nUnknownParameters = m_nRank + 3 * nGood3DPoints;
1364 
1365  return bStatus;
1366 }
1367 
1368 
1372  bool BundleAdjust::formNormals1_CHOLMOD(symmetric_matrix<double, upper>&N22,
1373  SparseBlockColumnMatrix& N12, compressed_vector<double>& n1,
1374  vector<double>& n2, matrix<double>& coeff_image,
1375  matrix<double>& coeff_point3D, vector<double>& coeff_RHS,
1376  int nImageIndex) {
1377  int i;
1378 
1379  static vector<double> n1_image(m_nNumImagePartials);
1380  n1_image.clear();
1381 
1382  // form N11 (normals for photo)
1383  static symmetric_matrix<double, upper> N11(m_nNumImagePartials);
1384  N11.clear();
1385 
1386 // std::cout << "image" << std::endl << coeff_image << std::endl;
1387 // std::cout << "point" << std::endl << coeff_point3D << std::endl;
1388 // std::cout << "rhs" << std::endl << coeff_RHS << std::endl;
1389 
1390  N11 = prod(trans(coeff_image), coeff_image);
1391 
1392 // std::cout << "N11" << std::endl << N11 << std::endl;
1393 
1394  int t = m_nNumImagePartials * nImageIndex;
1395 
1396  // insert submatrix at column, row
1397  m_SparseNormals.insertMatrixBlock(nImageIndex, nImageIndex,
1398  m_nNumImagePartials, m_nNumImagePartials );
1399 
1400  (*(*m_SparseNormals[nImageIndex])[nImageIndex]) += N11;
1401 
1402 // std::cout << (*(*m_SparseNormals[nImageIndex])[nImageIndex]) << std::endl;
1403 
1404  // form N12_Image
1405  static matrix<double> N12_Image(m_nNumImagePartials, 3);
1406  N12_Image.clear();
1407 
1408  N12_Image = prod(trans(coeff_image), coeff_point3D);
1409 
1410 
1411 // printf("N12 before insert\n");
1412 // std::cout << N12 << std::endl;
1413 
1414 // std::cout << "N12_Image" << std::endl << N12_Image << std::endl;
1415 
1416  // insert N12_Image into N12
1417 // for (i = 0; i < m_nNumImagePartials; i++)
1418 // for (j = 0; j < 3; j++)
1419 // N12(i + t, j) += N12_Image(i, j);
1420  N12.insertMatrixBlock(nImageIndex, m_nNumImagePartials, 3);
1421  *N12[nImageIndex] += N12_Image;
1422 
1423 // printf("N12\n");
1424 // std::cout << N12 << std::endl;
1425 
1426  // form n1
1427  n1_image = prod(trans(coeff_image), coeff_RHS);
1428 
1429 // std::cout << "n1_image" << std::endl << n1_image << std::endl;
1430 
1431  // insert n1_image into n1
1432  for (i = 0; i < m_nNumImagePartials; i++)
1433  n1(i + t) += n1_image(i);
1434 
1435  // form N22
1436  N22 += prod(trans(coeff_point3D), coeff_point3D);
1437 
1438 // std::cout << "N22" << std::endl << N22 << std::endl;
1439 
1440  // form n2
1441  n2 += prod(trans(coeff_point3D), coeff_RHS);
1442 
1443 // std::cout << "n2" << std::endl << n2 << std::endl;
1444 
1445  return true;
1446  }
1447 
1448 
1452  bool BundleAdjust::formNormals2_CHOLMOD(symmetric_matrix<double, upper>&N22,
1453  SparseBlockColumnMatrix& N12, vector<double>& n2, vector<double>& nj,
1454  int nPointIndex, int i) {
1455 
1456  bounded_vector<double, 3>& NIC = m_NICs[nPointIndex];
1457  SparseBlockRowMatrix& Q = m_Qs_CHOLMOD[nPointIndex];
1458 
1459  NIC.clear();
1460  Q.zeroBlocks();
1461 
1462  // weighting of 3D point parameters
1463 // const ControlPoint *point = m_pCnet->GetPoint(i);
1464  ControlPoint *point = m_pCnet->GetPoint(i); //TODO: what about this const business, regarding SetAdjustedSurfacePoint below???
1465 
1466  bounded_vector<double, 3>& weights = m_Point_Weights[nPointIndex];
1467  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
1468 
1469 // std::cout << "Point" << point->GetId() << "weights" << std::endl << weights << std::endl;
1470 
1471 // std::cout << "corrections" << std::endl << corrections << std::endl;
1472 
1473  if (weights[0] > 0.0) {
1474  N22(0, 0) += weights[0];
1475  n2(0) += (-weights[0] * corrections(0));
1476  m_nConstrainedPointParameters++;
1477  }
1478 
1479  if (weights[1] > 0.0) {
1480  N22(1, 1) += weights[1];
1481  n2(1) += (-weights[1] * corrections(1));
1482  m_nConstrainedPointParameters++;
1483  }
1484 
1485  if (weights[2] > 0.0) {
1486  N22(2, 2) += weights[2];
1487  n2(2) += (-weights[2] * corrections(2));
1488  m_nConstrainedPointParameters++;
1489  }
1490 
1491  // std::cout << "N22 before inverse" << std::endl << N22 << std::endl;
1492  // invert N22
1493  Invert_3x3(N22);
1494  // std::cout << "N22 after inverse" << std::endl << N22 << std::endl;
1495 
1496  // save upper triangular covariance matrix for error propagation
1497  // TODO: The following method does not exist yet (08-13-2010)
1498  SurfacePoint SurfacePoint = point->GetAdjustedSurfacePoint();
1499  SurfacePoint.SetSphericalMatrix(N22);
1500  point->SetAdjustedSurfacePoint(SurfacePoint);
1501 // point->GetAdjustedSurfacePoint().SetSphericalMatrix(N22);
1502 
1503 // TODO Test to make sure spherical matrix is truly set. Try to read it back
1504 
1505  // Next 3 lines obsolete because only the matrix is stored and sigmas are calculated from it.
1506 // point->SetSigmaLatitude(N22(0,0));
1507 // point->SetSigmaLongitude(N22(1,1));
1508 // point->SetSigmaRadius(N22(2,2));
1509 
1510  // form Q (this is N22{-1} * N12{T})
1511 // clock_t FormQ1 = clock();
1512 // Q = prod(N22, trans(N12));
1513  product_ATransB(N22, N12, Q);
1514 // clock_t FormQ2 = clock();
1515 // double dFormQTime = ((FormQ2-FormQ1)/(double)CLOCKS_PER_SEC);
1516 // printf("FormQ Elapsed Time: %20.10lf\n",dFormQTime);
1517 
1518 // std::cout << "Q: " << Q << std::endl;
1519 // Q.print();
1520 
1521  // form product of N22(inverse) and n2; store in NIC
1522 // clock_t FormNIC1 = clock();
1523  NIC = prod(N22, n2);
1524 // clock_t FormNIC2 = clock();
1525 // double dFormNICTime = ((FormNIC2-FormNIC1)/(double)CLOCKS_PER_SEC);
1526 // printf("FormNIC Elapsed Time: %20.10lf\n",dFormNICTime);
1527 
1528  // accumulate -R directly into reduced normal equations
1529 // clock_t AccumIntoNormals1 = clock();
1530 // m_Normals -= prod(N12,Q);
1531 // printf("starting AmultAdd_CNZRows\n");
1532 // AmultAdd_CNZRows(-1.0, N12, Q, m_Normals);
1533  AmultAdd_CNZRows_CHOLMOD(-1.0, N12, Q);
1534 // clock_t AccumIntoNormals2 = clock();
1535 // double dAccumIntoNormalsTime = ((AccumIntoNormals2-AccumIntoNormals1)/(double)CLOCKS_PER_SEC);
1536 // printf("Accum Into Normals Elapsed Time: %20.10lf\n",dAccumIntoNormalsTime);
1537 
1538  // accumulate -nj
1539 // clock_t Accum_nj_1 = clock();
1540 // m_nj -= prod(trans(Q),n2);
1541  transA_NZ_multAdd_CHOLMOD(-1.0, Q, n2, m_nj);
1542 // clock_t Accum_nj_2 = clock();
1543 // double dAccumnjTime = ((Accum_nj_2-Accum_nj_1)/(double)CLOCKS_PER_SEC);
1544 // printf("Accum nj Elapsed Time: %20.10lf\n",dAccumnjTime);
1545 
1546  return true;
1547  }
1548 
1549 
1554  bool BundleAdjust::formNormals3_CHOLMOD(compressed_vector<double>& n1,
1555  vector<double>& nj) {
1556 
1557  // std::cout << m_dImageParameterWeights << std::endl;
1558 
1559  m_nConstrainedImageParameters = 0;
1560 
1561  int n = 0;
1562 
1563  for ( int i = 0; i < m_SparseNormals.size(); i++ ) {
1564  matrix<double>* diagonalBlock = m_SparseNormals.getBlock(i,i);
1565  if ( !diagonalBlock )
1566  continue;
1567 
1568  for (int j = 0; j < m_nNumImagePartials; j++) {
1569  if (m_dImageParameterWeights[j] > 0.0) {
1570  (*diagonalBlock)(j,j) += m_dImageParameterWeights[j];
1571  m_nj[n] -= m_dImageParameterWeights[j] * m_Image_Corrections[n];
1572  m_nConstrainedImageParameters++;
1573  }
1574 
1575  n++;
1576  }
1577  }
1578 
1579  // add n1 to nj
1580  m_nj += n1;
1581 
1582  return true;
1583  }
1584 
1585 
1589  bool BundleAdjust::formNormalEquations_SPECIALK() {
1590 // if (m_pProgressBar != NULL)
1591 // {
1592 // m_pProgressBar->SetText("Forming Normal Equations...");
1593 // m_pProgressBar->SetMaximumSteps(m_pCnet->Size());
1594 // m_pProgressBar->CheckStatus();
1595 // }
1596  bool bStatus = false;
1597 
1598  m_nObservations = 0;
1599  m_nConstrainedPointParameters = 0;
1600 
1601  static matrix<double> coeff_image;
1602  static matrix<double> coeff_point3D(2, 3);
1603  static vector<double> coeff_RHS(2);
1604  static symmetric_matrix<double, upper> N22(3); // 3x3 upper triangular
1605  static matrix< double> N12(m_nRank, 3); // image parameters x 3 (should this be compressed? We only make one, so probably not)
1606  static vector<double> n2(3); // 3x1 vector
1607  compressed_vector<double> n1(m_nRank); // image parameters x 1
1608 
1609  m_nj.resize(m_nRank);
1610 
1611  coeff_image.resize(2, m_nNumImagePartials);
1612  N12.resize(m_nRank, 3);
1613 
1614  // clear N12, n1, and nj
1615  N12.clear();
1616  n1.clear();
1617  m_nj.clear();
1618 
1619  // clear static matrices
1620  coeff_point3D.clear();
1621  coeff_RHS.clear();
1622  N22.clear();
1623  n2.clear();
1624 
1625  // loop over 3D points
1626  int nGood3DPoints = 0;
1627  int nRejected3DPoints = 0;
1628  int nPointIndex = 0;
1629  int nImageIndex;
1630  int n3DPoints = m_pCnet->GetNumPoints();
1631 
1632 // char buf[1056];
1633 // sprintf(buf,"\n\t Points:%10d\n", n3DPoints);
1634 // m_fp_log << buf;
1635 // printf("%s", buf);
1636 
1637  for (int i = 0; i < n3DPoints; i++) {
1638  const ControlPoint *point = m_pCnet->GetPoint(i);
1639 
1640  if ( point->IsIgnored() )
1641  continue;
1642 
1643  if( point->IsRejected() ) {
1644  nRejected3DPoints++;
1645 // sprintf(buf, "\tRejected %s - 3D Point %d of %d RejLimit = %lf\n", point.Id().toAscii().data(),nPointIndex,n3DPoints,m_dRejectionLimit);
1646 // m_fp_log << buf;
1647 
1648  nPointIndex++;
1649  continue;
1650  }
1651 
1652  // send notification to UI indicating index of point currently being processed
1653  // m_nProcessedPoint = i+1;
1654  // UI.Notify(BundleEvent.NEW_POINT_PROCESSED);
1655 
1656  if ( i != 0 ) {
1657  N22.clear();
1658  N12.clear();
1659  n2.clear();
1660  }
1661 
1662  // loop over measures for this point
1663  int nMeasures = point->GetNumMeasures();
1664  for (int j = 0; j < nMeasures; j++) {
1665  const ControlMeasure *measure = point->GetMeasure(j);
1666  if ( measure->IsIgnored() )
1667  continue;
1668 
1669  // flagged as "JigsawFail" implies this measure has been rejected
1670  // TODO IsRejected is obsolete -- replace code or add to ControlMeasure
1671  if (measure->IsRejected())
1672  continue;
1673 
1674  // printf(" Processing Measure %d of %d\n", j,nMeasures);
1675 
1676  // fill non-zero indices for this point - do we have to do this?
1677  // see BundleDistanceConstraints.java for code snippet (line 926)
1678 
1679  // Determine the image index
1680  nImageIndex = m_pSnList->serialNumberIndex(measure->GetCubeSerialNumber());
1681  if ( m_bObservationMode )
1682  nImageIndex = ImageIndex(nImageIndex)/m_nNumImagePartials;
1683 
1684  bStatus = ComputePartials_DC(coeff_image, coeff_point3D, coeff_RHS,
1685  *measure, *point);
1686 
1687 // std::cout << coeff_image << std::endl;
1688 // std::cout << coeff_point3D << std::endl;
1689 // std::cout << coeff_RHS << std::endl;
1690 
1691  if ( !bStatus )
1692  continue; // this measure should be flagged as rejected
1693 
1694  // update number of observations
1695  m_nObservations += 2;
1696 
1697  formNormals1_SPECIALK(N22, N12, n1, n2, coeff_image, coeff_point3D,
1698  coeff_RHS, nImageIndex);
1699  } // end loop over this points measures
1700 
1701  formNormals2_SPECIALK(N22, N12, n2, m_nj, nPointIndex, i);
1702  nPointIndex++;
1703 
1704 // if (m_pProgressBar != NULL)
1705 // m_pProgressBar->CheckStatus();
1706 
1707  nGood3DPoints++;
1708 
1709  } // end loop over 3D points
1710 
1711  // finally, form the reduced normal equations
1712  formNormals3_SPECIALK(n1, m_nj);
1713 
1714 // std::cout << m_Normals << std::endl;
1715 // m_SparseNormals.print();
1716 
1717  // update number of unknown parameters
1718  m_nUnknownParameters = m_nRank + 3 * nGood3DPoints;
1719 
1720  return bStatus;
1721  }
1722 
1723 
1727  bool BundleAdjust::formNormals1_SPECIALK(symmetric_matrix<double, upper>&N22,
1728  matrix<double>& N12, compressed_vector<double>& n1, vector<double>& n2,
1729  matrix<double>& coeff_image, matrix<double>& coeff_point3D,
1730  vector<double>& coeff_RHS, int nImageIndex) {
1731  int i, j;
1732 
1733  static vector<double> n1_image(m_nNumImagePartials);
1734  n1_image.clear();
1735 
1736  // form N11 (normals for photo)
1737  static symmetric_matrix<double, upper> N11(m_nNumImagePartials);
1738  N11.clear();
1739 
1740 // std::cout << "image" << std::endl << coeff_image << std::endl;
1741 // std::cout << "point" << std::endl << coeff_point3D << std::endl;
1742 // std::cout << "rhs" << std::endl << coeff_RHS << std::endl;
1743 
1744  N11 = prod(trans(coeff_image), coeff_image);
1745 
1746 // std::cout << "N11" << std::endl << N11 << std::endl;
1747 
1748  // insert into reduced normal equations
1749  int t = m_nNumImagePartials * nImageIndex;
1750  for (i = 0; i < m_nNumImagePartials; i++)
1751  for (j = i; j < m_nNumImagePartials; j++)
1752  m_Normals(i + t, j + t) += N11(i, j);
1753 
1754  // form N12_Image
1755  static matrix<double> N12_Image(m_nNumImagePartials, 3);
1756  N12_Image.clear();
1757 
1758  N12_Image = prod(trans(coeff_image), coeff_point3D);
1759 
1760 
1761 // printf("N12 before insert\n");
1762 // std::cout << N12 << std::endl;
1763 
1764 // std::cout << "N12_Image" << std::endl << N12_Image << std::endl;
1765 
1766  // insert N12_Image into N12
1767  for (i = 0; i < m_nNumImagePartials; i++)
1768  for (j = 0; j < 3; j++)
1769  N12(i + t, j) += N12_Image(i, j);
1770 
1771 // printf("N12\n");
1772 // std::cout << N12 << std::endl;
1773 
1774  // form n1
1775  n1_image = prod(trans(coeff_image), coeff_RHS);
1776 
1777 // std::cout << "n1_image" << std::endl << n1_image << std::endl;
1778 
1779  // insert n1_image into n1
1780  for (i = 0; i < m_nNumImagePartials; i++)
1781  n1(i + t) += n1_image(i);
1782 
1783  // form N22
1784  N22 += prod(trans(coeff_point3D), coeff_point3D);
1785 
1786 // std::cout << "N22" << std::endl << N22 << std::endl;
1787 
1788  // form n2
1789  n2 += prod(trans(coeff_point3D), coeff_RHS);
1790 
1791 // std::cout << "n2" << std::endl << n2 << std::endl;
1792 
1793  return true;
1794  }
1795 
1796 
1800  bool BundleAdjust::formNormals2_SPECIALK(symmetric_matrix<double, upper>&N22,
1801  matrix<double>& N12, vector<double>& n2, vector<double>& nj,
1802  int nPointIndex, int i) {
1803 
1804  bounded_vector<double, 3>& NIC = m_NICs[nPointIndex];
1805  compressed_matrix<double>& Q = m_Qs_SPECIALK[nPointIndex];
1806 
1807  NIC.clear();
1808  Q.clear();
1809 
1810  // weighting of 3D point parameters
1811  // const ControlPoint *point = m_pCnet->GetPoint(i);
1812  ControlPoint *point = m_pCnet->GetPoint(i); //TODO: what about this const business, regarding SetAdjustedSurfacePoint below???
1813 
1814  bounded_vector<double, 3>& weights = m_Point_Weights[nPointIndex];
1815  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
1816 
1817  // std::cout << "Point" << point->GetId() << "weights" << std::endl << weights << std::endl;
1818 
1819  // std::cout << "corrections" << std::endl << corrections << std::endl;
1820 
1821  if (weights[0] > 0.0) {
1822  N22(0, 0) += weights[0];
1823  n2(0) += (-weights[0] * corrections(0));
1824  m_nConstrainedPointParameters++;
1825  }
1826 
1827  if (weights[1] > 0.0) {
1828  N22(1, 1) += weights[1];
1829  n2(1) += (-weights[1] * corrections(1));
1830  m_nConstrainedPointParameters++;
1831  }
1832 
1833  if (weights[2] > 0.0) {
1834  N22(2, 2) += weights[2];
1835  n2(2) += (-weights[2] * corrections(2));
1836  m_nConstrainedPointParameters++;
1837  }
1838 
1839  // std::cout << "N22 before inverse" << std::endl << N22 << std::endl;
1840  // invert N22
1841  Invert_3x3(N22);
1842  // std::cout << "N22 after inverse" << std::endl << N22 << std::endl;
1843 
1844  // save upper triangular covariance matrix for error propagation
1845  // TODO: The following method does not exist yet (08-13-2010)
1846  SurfacePoint SurfacePoint = point->GetAdjustedSurfacePoint();
1847  SurfacePoint.SetSphericalMatrix(N22);
1848  point->SetAdjustedSurfacePoint(SurfacePoint);
1849  // point->GetAdjustedSurfacePoint().SetSphericalMatrix(N22);
1850 
1851  // TODO Test to make sure spherical matrix is truly set. Try to read it back
1852 
1853  // Next 3 lines obsolete because only the matrix is stored and sigmas are calculated from it.
1854  // point->SetSigmaLatitude(N22(0,0));
1855  // point->SetSigmaLongitude(N22(1,1));
1856  // point->SetSigmaRadius(N22(2,2));
1857 
1858  // form Q (this is N22{-1} * N12{T})
1859  // clock_t FormQ1 = clock();
1860  Q = prod(N22, trans(N12));
1861  // clock_t FormQ2 = clock();
1862  // double dFormQTime = ((FormQ2-FormQ1)/(double)CLOCKS_PER_SEC);
1863  // printf("FormQ Elapsed Time: %20.10lf\n",dFormQTime);
1864 
1865  // std::cout << "Q: " << Q << std::endl;
1866 
1867  // form product of N22(inverse) and n2; store in NIC
1868  // clock_t FormNIC1 = clock();
1869  NIC = prod(N22, n2);
1870  // clock_t FormNIC2 = clock();
1871  // double dFormNICTime = ((FormNIC2-FormNIC1)/(double)CLOCKS_PER_SEC);
1872  // printf("FormNIC Elapsed Time: %20.10lf\n",dFormNICTime);
1873 
1874  // accumulate -R directly into reduced normal equations
1875  // clock_t AccumIntoNormals1 = clock();
1876  // m_Normals -= prod(N12,Q);
1877  // printf("starting AmultAdd_CNZRows\n");
1878  AmultAdd_CNZRows_SPECIALK(-1.0, N12, Q, m_Normals);
1879  // clock_t AccumIntoNormals2 = clock();
1880  // double dAccumIntoNormalsTime = ((AccumIntoNormals2-AccumIntoNormals1)/(double)CLOCKS_PER_SEC);
1881  // printf("Accum Into Normals Elapsed Time: %20.10lf\n",dAccumIntoNormalsTime);
1882 
1883  // accumulate -nj
1884  // clock_t Accum_nj_1 = clock();
1885  // m_nj -= prod(trans(Q),n2);
1886  transA_NZ_multAdd_SPECIALK(-1.0, Q, n2, m_nj);
1887  // clock_t Accum_nj_2 = clock();
1888  // double dAccumnjTime = ((Accum_nj_2-Accum_nj_1)/(double)CLOCKS_PER_SEC);
1889  // printf("Accum nj Elapsed Time: %20.10lf\n",dAccumnjTime);
1890 
1891  return true;
1892  }
1893 
1894 
1899  bool BundleAdjust::formNormals3_SPECIALK(compressed_vector<double>& n1,
1900  vector<double>& nj) {
1901 
1902  // std::cout << m_dImageParameterWeights << std::endl;
1903 
1904  m_nConstrainedImageParameters = 0;
1905 
1906  int n = 0;
1907  do {
1908  for (int j = 0; j < m_nNumImagePartials; j++) {
1909  if (m_dImageParameterWeights[j] > 0.0) {
1910  m_Normals(n, n) += m_dImageParameterWeights[j];
1911  m_nj[n] -= m_dImageParameterWeights[j] * m_Image_Corrections[n];
1912  m_nConstrainedImageParameters++;
1913  }
1914 
1915  n++;
1916  }
1917 
1918  }
1919  while (n < m_nRank);
1920 
1921  // add n1 to nj
1922  m_nj += n1;
1923 
1924  return true;
1925  }
1926 
1927 
1931  bool BundleAdjust::InitializePointWeights() {
1932  // TODO: Get working as is then convert to use new classes (Angles, etc.) and xyz with radius constraints
1933 // Distance dAprioriXSigma;
1934 // Distance dAprioriYSigma;
1935 // Distance dAprioriZSigma;
1936 // double dWtLat = 0.0;
1937 // double dWtLong = 0.0;
1938 // double dWtRadius = 0.0;
1939  double d;
1940 
1941  int n3DPoints = m_pCnet->GetNumPoints();
1942  int nPointIndex = 0;
1943  for (int i = 0; i < n3DPoints; i++) {
1944  ControlPoint *point = m_pCnet->GetPoint(i);
1945  if (point->IsIgnored())
1946 // {
1947 // nPointIndex++;
1948  continue;
1949 // }
1950 
1951  SurfacePoint aprioriSurfacePoint = point->GetAprioriSurfacePoint();
1952 
1953  bounded_vector<double, 3>& weights = m_Point_Weights[nPointIndex];
1954  bounded_vector<double, 3>& apriorisigmas = m_Point_AprioriSigmas[nPointIndex];
1955 
1956 // std::cout << weights << std::endl;
1957 
1958  if (point->GetType() == ControlPoint::Fixed) {
1959  weights[0] = 1.0e+50;
1960  weights[1] = 1.0e+50;
1961  weights[2] = 1.0e+50;
1962  }
1963  else if (point->GetType() == ControlPoint::Free) {
1964  if( m_dGlobalLatitudeAprioriSigma > 0.0 ) {
1965  apriorisigmas[0] = m_dGlobalLatitudeAprioriSigma;
1966  d = m_dGlobalLatitudeAprioriSigma*m_dMTR;
1967  weights[0] = 1.0/(d*d);
1968  }
1969  if( m_dGlobalLongitudeAprioriSigma > 0.0 ) {
1970  apriorisigmas[1] = m_dGlobalLongitudeAprioriSigma;
1971  d = m_dGlobalLongitudeAprioriSigma*m_dMTR;
1972  weights[1] = 1.0/(d*d);
1973  }
1974  if (!m_bSolveRadii)
1975  weights[2] = 1.0e+50;
1976  else {
1977  if( m_dGlobalRadiusAprioriSigma > 0.0 ) {
1978  apriorisigmas[2] = m_dGlobalRadiusAprioriSigma;
1979  d = m_dGlobalRadiusAprioriSigma*0.001;
1980  weights[2] = 1.0/(d*d);
1981  }
1982  }
1983  }
1984  else if (point->GetType() == ControlPoint::Constrained) {
1985  if( point->IsLatitudeConstrained() ) {
1986  apriorisigmas[0] = point->GetAprioriSurfacePoint().GetLatSigmaDistance().meters();
1987  weights[0] = point->GetAprioriSurfacePoint().GetLatWeight();
1988  }
1989  else if( m_dGlobalLatitudeAprioriSigma > 0.0 ) {
1990  apriorisigmas[0] = m_dGlobalLatitudeAprioriSigma;
1991  d = m_dGlobalLatitudeAprioriSigma*m_dMTR;
1992  weights[0] = 1.0/(d*d);
1993  }
1994 
1995  if( point->IsLongitudeConstrained() ) {
1996  apriorisigmas[1] = point->GetAprioriSurfacePoint().GetLonSigmaDistance().meters();
1997  weights[1] = point->GetAprioriSurfacePoint().GetLonWeight();
1998  }
1999  else if( m_dGlobalLongitudeAprioriSigma > 0.0 ) {
2000  apriorisigmas[1] = m_dGlobalLongitudeAprioriSigma;
2001  d = m_dGlobalLongitudeAprioriSigma*m_dMTR;
2002  weights[1] = 1.0/(d*d);
2003  }
2004 
2005  if (!m_bSolveRadii)
2006  weights[2] = 1.0e+50;
2007  else {
2008  if( point->IsRadiusConstrained() ) {
2009  apriorisigmas[2] = point->GetAprioriSurfacePoint().GetLocalRadiusSigma().meters();
2010  weights[2] = point->GetAprioriSurfacePoint().GetLocalRadiusWeight();
2011  }
2012  else if( m_dGlobalRadiusAprioriSigma > 0.0 ) {
2013  apriorisigmas[2] = m_dGlobalRadiusAprioriSigma;
2014  d = m_dGlobalRadiusAprioriSigma*0.001;
2015  weights[2] = 1.0/(d*d);
2016  }
2017  }
2018  }
2019 
2020 // printf("LatWt: %20.10lf LonWt: %20.10lf RadWt: %20.10lf\n",weights[0],weights[1],weights[2]);
2021 
2022  // TODO: do we need the four lines below??????
2023  // 2011-05-19 KLE: NOOOO! this causes apriori sigmas to be set if the user has input
2024  // global point weights. This causes a mess in the adjustment and the output
2025  // net is corrupted with an invalid apriori covariance matrix
2026 // try {
2027 // aprioriSurfacePoint.SetSphericalSigmasDistance(Distance(apriorisigmas[0], Distance::Meters),
2028 // Distance(apriorisigmas[1], Distance::Meters),
2029 // Distance(apriorisigmas[2], Distance::Meters));
2030 // }
2031 // catch (iException &e) {
2032 // QString msg = "Required target radii not available for converting lat/lon sigmas from meters ";
2033 // msg += "for control point " + Isis::IString(point->GetId());
2034 // throw iException::Message(iException::Programmer, msg, _FILEINFO_);
2035 // }
2036 //
2037 // point->SetAprioriSurfacePoint(aprioriSurfacePoint);
2038  nPointIndex++;
2039  }
2040 
2041  return true;
2042  }
2043 
2044 
2050  void BundleAdjust::InitializePoints() {
2051  int n3DPoints = m_pCnet->GetNumPoints();
2052 
2053  for (int i = 0; i < n3DPoints; i++) {
2054  ControlPoint *point = m_pCnet->GetPoint(i);
2055 
2056  if (point->IsIgnored())
2057  continue;
2058 
2059  SurfacePoint aprioriSurfacePoint = point->GetAprioriSurfacePoint();
2060  point->SetAdjustedSurfacePoint(aprioriSurfacePoint);
2061  }
2062 
2063  }
2064 
2065 
2071  void BundleAdjust::product_AV(double alpha, bounded_vector<double,3>& v2,
2072  SparseBlockRowMatrix& Q, vector< double >& v1) {
2073 
2074  QMapIterator<int, matrix<double>*> iQ(Q);
2075 
2076  while ( iQ.hasNext() ) {
2077  iQ.next();
2078 
2079  int ncol = iQ.key();
2080 
2081  int t = ncol*m_nNumImagePartials;
2082 
2083  v2 += alpha * prod(*(iQ.value()),subrange(v1,t,t+m_nNumImagePartials));
2084  }
2085  }
2086 
2087 
2095  bool BundleAdjust::product_ATransB(symmetric_matrix <double,upper>& N22,
2097 
2098  QMapIterator<int, matrix<double>*> iN12(N12);
2099 
2100  while ( iN12.hasNext() ) {
2101  iN12.next();
2102 
2103  int ncol = iN12.key();
2104 
2105  // insert submatrix in Q at block "ncol"
2106  Q.insertMatrixBlock(ncol, 3, m_nNumImagePartials);
2107 
2108  *(Q[ncol]) = prod(N22,trans(*(iN12.value())));
2109  }
2110 
2111  return true;
2112  }
2113 
2114 
2122  void BundleAdjust::AmultAdd_CNZRows_CHOLMOD(double alpha,
2124 
2125  if (alpha == 0.0)
2126  return;
2127 
2128  // now multiply blocks and subtract from m_SparseNormals
2129  QMapIterator<int, matrix<double>*> iN12(N12);
2130  QMapIterator<int, matrix<double>*> iQ(Q);
2131 
2132  while ( iN12.hasNext() ) {
2133  iN12.next();
2134 
2135  int nrow = iN12.key();
2136 // matrix<double> a = *(iN12.value());
2137  matrix<double> *a = iN12.value();
2138 
2139  while ( iQ.hasNext() ) {
2140  iQ.next();
2141 
2142  int ncol = iQ.key();
2143  if ( nrow > ncol )
2144  continue;
2145 
2146  // insert submatrix at column, row
2147  m_SparseNormals.insertMatrixBlock(ncol, nrow,
2148  m_nNumImagePartials, m_nNumImagePartials );
2149 
2150  (*(*m_SparseNormals[ncol])[nrow]) -= prod(*a,*(iQ.value()));
2151  }
2152  iQ.toFront();
2153  }
2154  }
2155 
2156 
2163  void BundleAdjust::AmultAdd_CNZRows_SPECIALK(double alpha, matrix<double>& A, compressed_matrix<double>& B,
2164  symmetric_matrix<double, upper, column_major>& C)
2165  {
2166  if (alpha == 0.0)
2167  return;
2168 
2169  register int i, j, k, ii, jj;
2170  double d;
2171 
2172  int nColsA = A.size2();
2173 
2174  // create array of non-zero indices of matrix B
2175  std::vector<int> nz(B.nnz() / B.size1());
2176 
2177  // iterators for B
2178  typedef compressed_matrix<double>::iterator1 it_row;
2179  typedef compressed_matrix<double>::iterator2 it_col;
2180 
2181  it_row itr = B.begin1();
2182  int nIndex = 0;
2183  for (it_col itc = itr.begin(); itc != itr.end(); ++itc) {
2184  nz[nIndex] = itc.index2();
2185  nIndex++;
2186  }
2187 
2188  int nzlength = nz.size();
2189  for (i = 0; i < nzlength; ++i) {
2190  ii = nz[i];
2191  for (j = i; j < nzlength; ++j) {
2192  jj = nz[j];
2193  d = 0.0;
2194 
2195  for (k = 0; k < nColsA; ++k)
2196  d += A(ii, k) * B(k, jj);
2197 
2198  C(ii, jj) += alpha * d;
2199  }
2200  }
2201  }
2202 
2203 
2209  void BundleAdjust::transA_NZ_multAdd_CHOLMOD(double alpha,
2210  SparseBlockRowMatrix& Q, vector<double>& n2, vector<double>& m_nj) {
2211 
2212  if (alpha == 0.0)
2213  return;
2214 
2215  QMapIterator<int, matrix<double>*> iQ(Q);
2216 
2217  while ( iQ.hasNext() ) {
2218  iQ.next();
2219 
2220  int nrow = iQ.key();
2221  matrix<double>* m = iQ.value();
2222 
2223  vector<double> v = prod(trans(*m),n2);
2224 
2225  int t = nrow*m_nNumImagePartials;
2226 
2227  for( unsigned i = 0; i < v.size(); i++ )
2228  m_nj(t+i) += alpha*v(i);
2229  }
2230  }
2231 
2232 
2238  void BundleAdjust::transA_NZ_multAdd_SPECIALK(double alpha, compressed_matrix<double>& A,
2239  vector<double>& B, vector<double>& C) {
2240 
2241  if (alpha == 0.0)
2242  return;
2243 
2244  register int i, j, ii;
2245  double d;
2246 
2247  int nRowsA = A.size1();
2248 
2249  // create array of non-zero indices of matrix A
2250  std::vector<int> nz(A.nnz() / A.size1());
2251 
2252  typedef compressed_matrix<double>::iterator1 it_row;
2253  typedef compressed_matrix<double>::iterator2 it_col;
2254 
2255  it_row itr = A.begin1();
2256  int nIndex = 0;
2257  for (it_col itc = itr.begin(); itc != itr.end(); ++itc) {
2258  nz[nIndex] = itc.index2();
2259  nIndex++;
2260  }
2261 
2262  int nzlength = nz.size();
2263  for (i = 0; i < nzlength; ++i) {
2264  ii = nz[i];
2265  d = 0.0;
2266 
2267  for (j = 0; j < nRowsA; ++j)
2268  d += A(j, ii) * B(j);
2269 
2270  C(ii) += alpha * d;
2271  }
2272  }
2273 
2274 
2280  void BundleAdjust::AmulttransBNZ(matrix<double>& A,
2281  compressed_matrix<double>& B, matrix<double> &C, double alpha) {
2282 
2283  if ( alpha == 0.0 )
2284  return;
2285 
2286  register int i,j,k,kk;
2287  double d;
2288 
2289  int nRowsB = B.size1();
2290 
2291  // create array of non-zero indices of matrix B
2292  std::vector<int> nz(B.nnz() / nRowsB);
2293 
2294  typedef compressed_matrix<double>::iterator1 it_row;
2295  typedef compressed_matrix<double>::iterator2 it_col;
2296 
2297  it_row itr = B.begin1();
2298  int nIndex = 0;
2299  for (it_col itc = itr.begin(); itc != itr.end(); ++itc) {
2300  nz[nIndex] = itc.index2();
2301  nIndex++;
2302  }
2303 
2304  int nzlength = nz.size();
2305 
2306  int nRowsA = A.size1();
2307  int nColsC = C.size2();
2308 
2309  for ( i = 0; i < nRowsA; ++i ) {
2310  for (j = 0; j < nColsC; ++j) {
2311  d = 0;
2312 
2313  for (k = 0; k < nzlength; ++k) {
2314  kk = nz[k];
2315  d += A(i, kk) * B(j, kk);
2316  }
2317 
2318  C(i,j) += alpha * d;
2319  }
2320  }
2321 
2322  }
2323 
2324 
2330  void BundleAdjust::ANZmultAdd(compressed_matrix<double>& A,
2331  symmetric_matrix<double, upper, column_major>& B,
2332  matrix<double>& C, double alpha) {
2333 
2334  if ( alpha == 0.0 )
2335  return;
2336 
2337  register int i,j,k,kk;
2338  double d;
2339 
2340  int nRowsA = A.size1();
2341 
2342  // create array of non-zero indices of matrix A
2343  std::vector<int> nz(A.nnz() /nRowsA);
2344 
2345  typedef compressed_matrix<double>::iterator1 it_row;
2346  typedef compressed_matrix<double>::iterator2 it_col;
2347 
2348  it_row itr = A.begin1();
2349  int nIndex = 0;
2350  for (it_col itc = itr.begin(); itc != itr.end(); ++itc) {
2351  nz[nIndex] = itc.index2();
2352  nIndex++;
2353  }
2354 
2355  int nzlength = nz.size();
2356 
2357  int nColsC = C.size2();
2358  for ( i = 0; i < nRowsA; ++i ) {
2359  for ( j = 0; j < nColsC; ++j ) {
2360  d = 0;
2361 
2362  for ( k = 0; k < nzlength; ++k ) {
2363  kk = nz[k];
2364  d += A(i, kk) * B(kk, j);
2365  }
2366 
2367  C(i, j) += alpha * d;
2368  }
2369  }
2370 
2371  }
2372 
2373 
2378  bool BundleAdjust::solveSystem_CHOLMOD() {
2379 
2380  // load cholmod triplet
2381  if ( !loadCholmodTriplet() ) {
2382  QString msg = "CHOLMOD: Failed to load Triplet matrix";
2383  throw IException(IException::Programmer, msg, _FILEINFO_);
2384  }
2385 
2386  // convert triplet to sparse matrix
2387 // FILE * pFile1;
2388 // pFile1 = fopen ("//work//users//kedmundson//Normals.txt" , "w");
2389  m_N = cholmod_triplet_to_sparse(m_pTriplet, m_pTriplet->nnz, &m_cm);
2390 // cholmod_write_sparse(pFile1, m_N, 0, 0, &m_cm);
2391 // fclose(pFile1);
2392 
2393  // analyze matrix
2394  //clock_t t1 = clock();
2395  m_L = cholmod_analyze(m_N, &m_cm); // should we analyze just 1st iteration?
2396  //clock_t t2 = clock();
2397  //double delapsedtime = ((t2-t1)/(double)CLOCKS_PER_SEC);
2398  //printf("cholmod Analyze Elapsed Time: %20.10lf\n",delapsedtime);
2399 
2400  // create cholmod cholesky factor (LDLT?)
2401  //t1 = clock();
2402  cholmod_factorize(m_N, m_L, &m_cm);
2403  //t2 = clock();
2404  //delapsedtime = ((t2-t1)/(double)CLOCKS_PER_SEC);
2405  //printf("cholmod Factorize Elapsed Time: %20.10lf\n",delapsedtime);
2406 
2407  // check for "matrix not positive definite" error
2408  if ( m_cm.status == CHOLMOD_NOT_POSDEF ) {
2409  QString msg = "matrix NOT positive-definite: failure at column "
2410  + m_L->minor;
2411  throw IException(IException::User, msg, _FILEINFO_);
2412  }
2413 
2414 // FILE * pFile2;
2415 // pFile2 = fopen ("//work1//kedmundson//factor.txt" , "w");
2416 // cholmod_sparse* factor = cholmod_factor_to_sparse(L, &c);
2417 // cholmod_write_sparse(pFile2, factor, 0, 0, &c);
2418 // fclose(pFile2);
2419 
2420  // cholmod solution and right-hand side vectors
2421  cholmod_dense *x, *b;
2422 
2423  // initialize right-hand side vector
2424  b = cholmod_zeros (m_N->nrow, 1, m_N->xtype, &m_cm);
2425 
2426  // copy right-hand side vector into b
2427  double *px = (double*)b->x;
2428  for ( int i = 0; i < m_nRank; i++ )
2429  px[i] = m_nj[i];
2430 
2431 // FILE * pFile3;
2432 // pFile3 = fopen ("//work1//kedmundson//rhs.txt" , "w");
2433 // cholmod_write_dense(pFile3, b, 0, &c);
2434 // fclose(pFile3);
2435 
2436  // cholmod solve
2437  //t1 = clock();
2438  x = cholmod_solve (CHOLMOD_A, m_L, b, &m_cm) ;
2439  //t2 = clock();
2440  //delapsedtime = ((t2-t1)/(double)CLOCKS_PER_SEC);
2441  //printf("cholmod Solution Elapsed Time: %20.10lf\n",delapsedtime);
2442 
2443 // FILE * pFile4;
2444 // pFile4 = fopen ("//work//users//kedmundson//solution.txt" , "w");
2445 // cholmod_write_dense(pFile4, x, 0, &m_cm);
2446 // fclose(pFile4);
2447 
2448  // copy solution vector x out into m_Image_Solution
2449  double *sx = (double*)x->x;
2450  for ( int i = 0; i < m_nRank; i++ )
2451  m_Image_Solution[i] = sx[i];
2452 
2453  // free cholmod structures
2454  cholmod_free_sparse(&m_N, &m_cm); // necessary?
2455  cholmod_free_dense(&b, &m_cm);
2456  cholmod_free_dense(&x, &m_cm);
2457 
2458  return true;
2459  }
2460 
2461 
2466  bool BundleAdjust::loadCholmodTriplet() {
2467  //printf("Starting CholMod conversion to triplet\n");
2468  double d;
2469 
2470  if ( m_nIteration == 1 ) {
2471  int nelements = m_SparseNormals.numberOfElements();
2472  //printf("Matrix rank: %d # of Triplet elements: %d", m_nRank,nelements);
2473  m_pTriplet = cholmod_allocate_triplet(m_nRank, m_nRank, nelements,
2474  -1, CHOLMOD_REAL, &m_cm);
2475 
2476  if ( !m_pTriplet ) {
2477  printf("Triplet allocation failure");
2478  return false;
2479  }
2480 
2481  m_pTriplet->nnz = 0;
2482  }
2483 
2484  int* Ti = (int*) m_pTriplet->i;
2485  int* Tj = (int*) m_pTriplet->j;
2486  double* v = (double*)m_pTriplet->x;
2487 
2488  int nentries = 0;
2489 
2490  int nblockcolumns = m_SparseNormals.size();
2491  for ( int ncol = 0; ncol < nblockcolumns; ncol++ ) {
2492 
2493  SparseBlockColumnMatrix* sbc = m_SparseNormals[ncol];
2494 
2495  if ( !sbc ) {
2496  printf("SparseBlockColumnMatrix retrieval failure at column %d", ncol);
2497  return false;
2498  }
2499 
2500  QMapIterator<int, matrix<double>*> it(*sbc);
2501 
2502  while ( it.hasNext() ) {
2503  it.next();
2504 
2505  int nrow = it.key();
2506 
2507  matrix<double>* m = it.value();
2508  if ( !m ) {
2509  printf("matrix block retrieval failure at column %d, row %d", ncol,nrow);
2510  printf("Total # of block columns: %d", nblockcolumns);
2511  printf("Total # of blocks: %d", m_SparseNormals.numberOfBlocks());
2512  return false;
2513  }
2514 
2515  if ( ncol == nrow ) { // diagonal block (upper-triangular)
2516  for ( unsigned ii = 0; ii < m->size1(); ii++ ) {
2517  for (unsigned jj = ii; jj < m->size2(); jj++) {
2518  d = m->at_element(ii,jj);
2519  int ncolindex = jj+ncol*m_nNumImagePartials;
2520  int nrowindex = ii+nrow*m_nNumImagePartials;
2521 
2522  if ( m_nIteration == 1 ) {
2523  Ti[nentries] = ncolindex;
2524  Tj[nentries] = nrowindex;
2525  m_pTriplet->nnz++;
2526  }
2527 
2528 // printf("UT - writing to row: %d column: %d\n", ncolindex, nrowindex);
2529  v[nentries] = d;
2530 
2531  nentries++;
2532  }
2533  }
2534 // printf("\n");
2535  }
2536  else { // off-diagonal block (square)
2537  for ( unsigned ii = 0; ii < m->size1(); ii++ ) {
2538  for ( unsigned jj = 0; jj < m->size2(); jj++ ) {
2539  d = m->at_element(ii,jj);
2540  int ncolindex = jj+ncol*m_nNumImagePartials;
2541  int nrowindex = ii+nrow*m_nNumImagePartials;
2542 
2543  if ( m_nIteration ==1 ) {
2544  Ti[nentries] = nrowindex;
2545  Tj[nentries] = ncolindex;
2546  m_pTriplet->nnz++;
2547  }
2548 
2549  v[nentries] = d;
2550 
2551 // printf(" writing to row: %d column: %d\n", ncolindex, nrowindex);
2552 
2553  nentries++;
2554  }
2555  }
2556 // printf("\n");
2557  }
2558  }
2559  }
2560 
2561  return true;
2562  }
2563 
2564 
2569  bool BundleAdjust::solveSystem_SPECIALK() {
2570  // decomposition (this is UTDU - need to test row vs column major
2571  // storage and access, and use of matrix iterators)
2572 // clock_t CholeskyUtDUclock1 = clock();
2573 // printf("Starting Cholesky\n");
2574 // cholesky_decompose(m_Normals);
2575  if ( !CholeskyUT_NOSQR() )
2576  return false;
2577 // clock_t CholeskyUtDUclock2 = clock();
2578 // double dCholeskyTime = ((CholeskyUtDUclock2-CholeskyUtDUclock1)/(double)CLOCKS_PER_SEC);
2579 // printf("Cholesky Elapsed Time: %20.10lf\n",dCholeskyTime);
2580 
2581 // cholesky_solve(m_Normals, m_nj);
2582 
2583  // solve via back-substitution
2584 // clock_t BackSubclock1 = clock();
2585 // printf("Starting Back Substitution\n");
2586  if (!CholeskyUT_NOSQR_BackSub(m_Normals, m_Image_Solution, m_nj))
2587  return false;
2588 // clock_t BackSubclock2 = clock();
2589 // double dBackSubTime = ((BackSubclock1-BackSubclock2)/(double)CLOCKS_PER_SEC);
2590 // printf("Back Substitution Elapsed Time: %20.10lf\n",dBackSubTime);
2591 
2592 // std::cout << m_Image_Solution << std::endl;
2593 
2594  return true;
2595  }
2596 
2597 
2602  bool BundleAdjust::CholeskyUT_NOSQR() {
2603  int i, j, k;
2604  double sum, divisor;
2605  double den;
2606  double d1, d2;
2607 
2608  int nRows = m_Normals.size1();
2609 // comment here
2610 // for( i = 0; i < nRows; i++ )
2611 // {
2612 // for( j = i; j < nRows; j++ )
2613 // {
2614 // printf("%lf ",m_Normals(i,j));
2615 // }
2616 // printf("\n");
2617 // }
2618 // comment here
2619  for (i = 0; i < nRows; i++) {
2620 // printf("Cholesky Row %d of %d\n",i+1,nRows);
2621  sum = 0.0;
2622 
2623  for (j = 0; j < i; j++) {
2624 // sum += m_Normals(j,i-j) * m_Normals(j,i-j) * m_Normals(j,0); // old way
2625 
2626  d1 = m_Normals(j, i);
2627  if (d1 == 0.0)
2628  continue;
2629  sum += d1 * d1 * m_Normals(j, j); // new way
2630  }
2631 
2632 // m_Normals(i,0) -= sum; // old
2633  m_Normals(i, i) -= sum; // new
2634 
2635  // check for divide by 0
2636 // den = m_Normals(i,0); // old
2637  den = m_Normals(i, i); // new
2638  if (fabs(den) < 1e-100)
2639  return false;
2640 
2641  divisor = 1.0 / den;
2642 
2643  for (j = (i + 1); j < nRows; j++) {
2644  sum = 0.0;
2645 
2646  for (k = 0; k < i; k++) {
2647 // sum += m_Normals(k,j-k) * m_Normals(k,i-k) * m_Normals(k,0); // old
2648 
2649  d1 = m_Normals(k, j);
2650  if (d1 == 0.0)
2651  continue;
2652 
2653  d2 = m_Normals(k, i);
2654  if (d2 == 0.0)
2655  continue;
2656 
2657  sum += d1 * d2 * m_Normals(k, k); // new
2658  }
2659 
2660 // m_Normals(i,j-i) = (m_Normals(i,j-i) - sum) * divisor; // old
2661  m_Normals(i, j) = (m_Normals(i, j) - sum) * divisor; // new
2662  }
2663 
2664  // decompose right-hand side
2665  sum = 0.0;
2666  for (k = 0; k < i; k++) {
2667  d1 = m_nj(k);
2668  if (d1 == 0.0)
2669  continue;
2670 
2671  d2 = m_Normals(k, i);
2672  if (d2 == 0.0)
2673  continue;
2674 
2675  sum += d1 * d2 * m_Normals(k, k);
2676  }
2677 
2678  m_nj(i) = (m_nj(i) - sum) * divisor;
2679  }
2680 
2681  return true;
2682  }
2683 
2684 
2689  bool BundleAdjust::CholeskyUT_NOSQR_BackSub(symmetric_matrix<double, upper, column_major>& m,
2690  vector<double>& s, vector<double>& rhs) {
2691  int i, j;
2692  double sum;
2693  double d1, d2;
2694 
2695  int nRows = m.size1();
2696 
2697  s(nRows - 1) = rhs(nRows - 1);
2698 
2699  for (i = nRows - 2; i >= 0; i--) {
2700  sum = 0.0;
2701 
2702  for (j = i + 1; j < nRows; j++) {
2703  d1 = m(i, j);
2704  if (d1 == 0.0)
2705  continue;
2706 
2707  d2 = s(j);
2708  if (d2 == 0.0)
2709  continue;
2710 
2711  sum += d1 * d2;
2712  }
2713 
2714  s(i) = rhs(i) - sum;
2715  }
2716 
2717 // std::cout << s << std::endl;
2718 
2719  return true;
2720  }
2721 
2722 
2727  bool BundleAdjust::CholeskyUT_NOSQR_Inverse() {
2728  int i, j, k;
2729  double div, sum;
2730  double colk, tmpkj, tmpkk;
2731 
2732  // create temporary copy, inverse will be stored in m_Normals
2733  symmetric_matrix<double, upper, column_major> tmp = m_Normals;
2734 // symmetric_matrix<double,lower> tmp = m_Normals;
2735 
2736  // solution vector
2737  vector<double> s(m_nRank);
2738 
2739  // initialize column vector
2740  vector<double> column(m_nRank);
2741  column.clear();
2742  column(0) = 1.0;
2743 
2744  for (i = 0; i < m_nRank; i++) {
2745  // set current column of identity
2746  column.clear();
2747  column(i) = 1.0;
2748 
2749  // factorize current column of identity matrix
2750  for (j = 0; j < m_nRank; j++) {
2751  div = 1.0 / tmp(j, j);
2752  sum = 0.0;
2753 
2754  for (k = 0; k < j; k++) {
2755  colk = column(k);
2756  tmpkj = tmp(k, j);
2757  tmpkk = tmp(k, k);
2758 
2759  if (colk == 0.0 || tmpkj == 0.0 || tmpkk == 0.0)
2760  continue;
2761 
2762  sum += colk * tmpkj * tmpkk;
2763  }
2764 
2765  column(j) = (column(j) - sum) * div;
2766  }
2767 
2768  // back-substitution
2769  if (!CholeskyUT_NOSQR_BackSub(tmp, s, column))
2770  return false;
2771 
2772  // store solution in corresponding column of inverse (replacing column in
2773  // m_Normals)
2774  for (j = 0; j <= i; j++)
2775  m_Normals(j, i) = s(j);
2776  }
2777 
2778  return true;
2779  }
2780 
2781 
2786  bool BundleAdjust::cholmod_Inverse() {
2787  int i, j;
2788 
2789  // allocate matrix inverse
2790  m_Normals.resize(m_nRank);
2791 
2792  cholmod_dense *x; // solution vector
2793  cholmod_dense *b; // right-hand side (column vectors of identity)
2794 
2795  b = cholmod_zeros ( m_nRank, 1, CHOLMOD_REAL, &m_cm ) ;
2796  double* pb = (double*)b->x;
2797 
2798  double* px = NULL;
2799 
2800  for ( i = 0; i < m_nRank; i++ ) {
2801  if ( i > 0 )
2802  pb[i-1] = 0.0;
2803  pb[i] = 1.0;
2804 
2805  x = cholmod_solve ( CHOLMOD_A, m_L, b, &m_cm ) ;
2806  px = (double*)x->x;
2807 
2808  // store solution in corresponding column of inverse (replacing column in
2809  // m_Normals)
2810  for (j = 0; j <= i; j++)
2811  m_Normals(j, i) = px[j];
2812 
2813  cholmod_free_dense(&x,&m_cm);
2814  }
2815 
2816  //
2817  //std::cout << m_Normals;
2818  //
2819 
2820  cholmod_free_dense(&b,&m_cm);
2821 
2822  return true;
2823  }
2824 
2825 
2831  bool BundleAdjust::Invert_3x3(symmetric_matrix<double, upper>& m) {
2832  double det;
2833  double den;
2834 
2835  symmetric_matrix<double, upper> c = m;
2836 
2837  den = m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1))
2838  - m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0))
2839  + m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0));
2840 
2841  // check for divide by zero
2842  if (fabs(den) < 1.0e-100)
2843  return false;
2844 
2845  det = 1.0 / den;
2846 
2847  m(0, 0) = (c(1, 1) * c(2, 2) - c(1, 2) * c(2, 1)) * det;
2848  m(0, 1) = (c(0, 2) * c(2, 1) - c(0, 1) * c(2, 2)) * det;
2849  m(0, 2) = (c(0, 1) * c(1, 2) - c(0, 2) * c(1, 1)) * det;
2850  m(1, 1) = (c(0, 0) * c(2, 2) - c(0, 2) * c(2, 0)) * det;
2851  m(1, 2) = (c(0, 2) * c(1, 0) - c(0, 0) * c(1, 2)) * det;
2852  m(2, 2) = (c(0, 0) * c(1, 1) - c(0, 1) * c(1, 0)) * det;
2853 
2854  return true;
2855  }
2856 
2857 
2861  bool BundleAdjust::ComputePartials_DC(matrix<double>& coeff_image, matrix<double>& coeff_point3D,
2862  vector<double>& coeff_RHS, const ControlMeasure &measure,
2863  const ControlPoint &point) {
2864 
2865  // additional vectors
2866  std::vector<double> d_lookB_WRT_LAT;
2867  std::vector<double> d_lookB_WRT_LON;
2868  std::vector<double> d_lookB_WRT_RAD;
2869 
2870  Camera *pCamera = NULL;
2871 
2872  double dMeasuredx, dComputedx, dMeasuredy, dComputedy;
2873  double deltax, deltay;
2874  double dObservationSigma;
2875  double dObservationWeight;
2876 
2877  pCamera = measure.Camera();
2878 
2879  // clear partial derivative matrices and vectors
2880  coeff_image.clear();
2881  coeff_point3D.clear();
2882  coeff_RHS.clear();
2883 
2884  // no need to call SetImage for framing camera ( CameraType = 0 )
2885  if (pCamera->GetCameraType() != 0) {
2886  // Set the Spice to the measured point
2887  // but, can this be simplified???
2888  pCamera->SetImage(measure.GetSample(), measure.GetLine());
2889  }
2890 
2891  //Compute the look vector in instrument coordinates based on time of observation and apriori lat/lon/radius
2892  if (!(pCamera->GroundMap()->GetXY(point.GetAdjustedSurfacePoint(), &dComputedx, &dComputedy))) {
2893  QString msg = "Unable to map apriori surface point for measure ";
2894  msg += measure.GetCubeSerialNumber() + " on point " + point.GetId() + " into focal plane";
2895  throw IException(IException::User, msg, _FILEINFO_);
2896  }
2897 
2898  // partials for fixed point w/r lat, long, radius in Body-Fixed
2899  d_lookB_WRT_LAT = pCamera->GroundMap()->PointPartial(point.GetAdjustedSurfacePoint(),
2900  CameraGroundMap::WRT_Latitude);
2901  d_lookB_WRT_LON = pCamera->GroundMap()->PointPartial(point.GetAdjustedSurfacePoint(),
2902  CameraGroundMap::WRT_Longitude);
2903  d_lookB_WRT_RAD = pCamera->GroundMap()->PointPartial(point.GetAdjustedSurfacePoint(),
2904  CameraGroundMap::WRT_Radius);
2905 
2906 // std::cout << "d_lookB_WRT_LAT" << d_lookB_WRT_LAT << std::endl;
2907 // std::cout << "d_lookB_WRT_LON" << d_lookB_WRT_LON << std::endl;
2908 // std::cout << "d_lookB_WRT_RAD" << d_lookB_WRT_RAD << std::endl;
2909 
2910  int nIndex = 0;
2911 
2912  if (m_spacecraftPositionSolveType != Nothing) {
2913 // SpicePosition* pInstPos = pCamera->instrumentPosition();
2914 
2915  // Add the partial for the x coordinate of the position (differentiating
2916  // point(x,y,z) - spacecraftPosition(x,y,z) in J2000
2917  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
2918  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_X, icoef,
2919  &coeff_image(0, nIndex),
2920  &coeff_image(1, nIndex));
2921  nIndex++;
2922  }
2923 
2924 // std::cout << coeff_image << std::endl;
2925 
2926  // Add the partial for the y coordinate of the position
2927  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
2928  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_Y, icoef,
2929  &coeff_image(0, nIndex),
2930  &coeff_image(1, nIndex));
2931  nIndex++;
2932  }
2933 
2934  // Add the partial for the z coordinate of the position
2935  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
2936  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_Z, icoef,
2937  &coeff_image(0, nIndex),
2938  &coeff_image(1, nIndex));
2939  nIndex++;
2940  }
2941 
2942  }
2943 
2944  if (m_cmatrixSolveType != None) {
2945 
2946  // Add the partials for ra
2947  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
2948  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_RightAscension,
2949  icoef, &coeff_image(0, nIndex),
2950  &coeff_image(1, nIndex));
2951  nIndex++;
2952  }
2953 
2954  // Add the partials for dec
2955  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
2956  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Declination,
2957  icoef, &coeff_image(0, nIndex),
2958  &coeff_image(1, nIndex));
2959  nIndex++;
2960  }
2961 
2962  // Add the partial for twist if necessary
2963  if (m_bSolveTwist) {
2964  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
2965  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Twist,
2966  icoef, &coeff_image(0, nIndex),
2967  &coeff_image(1, nIndex));
2968  nIndex++;
2969  }
2970  }
2971  }
2972 
2973  // partials for 3D point
2974  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_LAT, &coeff_point3D(0, 0),
2975  &coeff_point3D(1, 0));
2976  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_LON, &coeff_point3D(0, 1),
2977  &coeff_point3D(1, 1));
2978 
2979  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_RAD, &coeff_point3D(0, 2),
2980  &coeff_point3D(1, 2));
2981 
2982 // std::cout << coeff_point3D << std::endl;
2983  // right-hand side (measured - computed)
2984  dMeasuredx = measure.GetFocalPlaneMeasuredX();
2985  dMeasuredy = measure.GetFocalPlaneMeasuredY();
2986 
2987  deltax = dMeasuredx - dComputedx;
2988  deltay = dMeasuredy - dComputedy;
2989 
2990  coeff_RHS(0) = deltax;
2991  coeff_RHS(1) = deltay;
2992 
2993  m_cumProRes->addObs(deltax/pCamera->PixelPitch());
2994  m_cumProRes->addObs(deltay/pCamera->PixelPitch());
2995 
2996  dObservationSigma = 1.4 * pCamera->PixelPitch();
2997  dObservationWeight = 1.0 / dObservationSigma;
2998 
2999  if (m_maxLikelihoodFlag[m_maxLikelihoodIndex]) { //if maximum likelihood estimation is being used
3000  double residualR2ZScore = sqrt(deltax*deltax + deltay*deltay)/dObservationSigma/sqrt(2.0);
3001  m_cumPro->addObs(residualR2ZScore); //dynamically build the cumulative probability distribution of the R^2 residual Z Scores
3002  //double tempScaler = m_wFunc[m_maxLikelihoodIndex]->sqrtWeightScaler(residualR2ZScore);
3003  //if ( tempScaler == 0.0) printf("ZeroScaler\n");
3004  //if ( tempScaler < 0.0) printf("NegativeScaler\n");
3005  dObservationWeight *= m_wFunc[m_maxLikelihoodIndex]->sqrtWeightScaler(residualR2ZScore);
3006  }
3007 
3008 // std::cout << "Measuredx " << dMeasuredx << " Measuredy = " << dMeasuredy << std::endl;
3009 // std::cout << "dComputedx " << dComputedx << " dComputedy = " << dComputedy << std::endl;
3010 // std::cout << coeff_image << std::endl;
3011 // std::cout << coeff_point3D << std::endl;
3012 // std::cout << dMeasuredx << " " << dComputedx << std::endl << dMeasuredy << " " << dComputedy << std::endl;
3013 // std::cout << coeff_RHS << std::endl;
3014 
3015  // multiply coefficients by observation weight
3016  coeff_image *= dObservationWeight;
3017  coeff_point3D *= dObservationWeight;
3018  coeff_RHS *= dObservationWeight;
3019 
3020  m_Statsx.AddData(deltax);
3021  m_Statsy.AddData(deltay);
3022 
3023  return true;
3024  }
3025 
3026 
3030  /*
3031  bool BundleAdjust::ComputePartials(matrix<double>& coeff_image, matrix<double>& coeff_point3D,
3032  vector<double>& coeff_RHS, const ControlMeasure &measure,
3033  const ControlPoint &point) {
3034 
3035  // additional vectors
3036 // double pB[3]; // Point on surface
3037 // std::vector<double> sB(3); // Spacecraft position in body-fixed coordinates
3038 // std::vector<double> lookB(3); // "look" vector in body-fixed coordinates
3039 // std::vector<double> lookC(3); // "look" vector in camera coordinates
3040 // std::vector<double> lookJ(3); // "look" vector in J2000 coordinates
3041 // std::vector<double> d_lookJ;
3042 // std::vector<double> d_lookC;
3043  std::vector<double> d_lookB_WRT_LAT;
3044  std::vector<double> d_lookB_WRT_LON;
3045  std::vector<double> d_lookB_WRT_RAD;
3046 
3047 // std::vector<double> TC; // platform to camera (constant rotation matrix)
3048 // std::vector<double> TB; // J2000 to platform (time-based rotation matrix)
3049 // std::vector<double> CJ; // J2000 to Camera (product of TB and TC)
3050 
3051  Camera *pCamera = NULL;
3052 // double fl;
3053 
3054  double dMeasuredx, dComputedx, dMeasuredy, dComputedy;
3055  double deltax, deltay;
3056  double dObservationSigma;
3057  // Compute fixed point in body-fixed coordinates km
3058 // latrec_c((double) point->GetAdjustedSurfacePoint().GetLocalRadius().kilometers(),
3059 // (double) point->GetAdjustedSurfacePoint().GetLongitude().radians(),
3060 // (double) point->GetAdjustedSurfacePoint().GetLatitude().radians(),
3061 // pB);
3062 
3063  double dObservationWeight;
3064 
3065  // auxiliary variables
3066 // double NX_C,NY_C,D_C;
3067 // double NX,NY;
3068 // double a1,a2,a3;
3069 // double z1,z2,z3,z4;
3070 
3071 // double dTime = -1.0;
3072 
3073  // partials for fixed point w/r lat, long, radius in Body-Fixed (?)
3074  // need to verify this
3075  // For now move entire point partial below. Maybe later be more efficient ----DC
3076  // and split the GetdXYdPoint method of CameraGroundMap into PointPartial part
3077  // and the rest like Ken has it.
3078 
3079 // d_lookB_WRT_LAT = PointPartial(point,WRT_Latitude);
3080 // d_lookB_WRT_LON = PointPartial(point,WRT_Longitude);
3081 // d_lookB_WRT_RAD = PointPartial(point,WRT_Radius);
3082 
3083  pCamera = measure.Camera();
3084 
3085  // Compute fixed point in body-fixed coordinates
3086 
3087 // printf("Lat: %20.10lf Long: %20.10lf Radius: %20.10lf\n",point.UniversalLatitude(),point.UniversalLongitude(),point.Radius());
3088 
3089 // latrec_c( point.Radius() * 0.001,
3090 // (point.UniversalLongitude() * DEG2RAD),
3091 // (point.UniversalLatitude() * DEG2RAD),
3092 // pB);
3093 
3094  // clear partial derivative matrices and vectors
3095  coeff_image.clear();
3096  coeff_point3D.clear();
3097  coeff_RHS.clear();
3098 
3099  // Get focal length with direction
3100 // fl = pCamera->DistortionMap()->UndistortedFocalPlaneZ();
3101 
3102  // no need to call SetImage for framing camera ( CameraType = 0 )
3103  if (pCamera->GetCameraType() != 0) {
3104  // Set the Spice to the measured point
3105  // but, can this be simplified???
3106  pCamera->SetImage(measure.GetSample(), measure.GetLine());
3107  }
3108 
3109  //Compute the look vector in instrument coordinates based on time of observation and apriori lat/lon/radius
3110  if (!(pCamera->GroundMap()->GetXY(point.GetAdjustedSurfacePoint(), &dComputedx, &dComputedy))) {
3111  QString msg = "Unable to map apriori surface point for measure ";
3112  msg += measure.GetCubeSerialNumber() + " on point " + point.GetId() + " into focal plane";
3113  throw iException::Message(iException::User, msg, _FILEINFO_);
3114  }
3115 
3116  // partials for fixed point w/r lat, long, radius in Body-Fixed
3117  d_lookB_WRT_LAT = pCamera->GroundMap()->PointPartial(point.GetAdjustedSurfacePoint(),
3118  CameraGroundMap::WRT_Latitude);
3119  d_lookB_WRT_LON = pCamera->GroundMap()->PointPartial(point.GetAdjustedSurfacePoint(),
3120  CameraGroundMap::WRT_Longitude);
3121  d_lookB_WRT_RAD = pCamera->GroundMap()->PointPartial(point.GetAdjustedSurfacePoint(),
3122  CameraGroundMap::WRT_Radius);
3123 
3124 // std::cout << "d_lookB_WRT_LAT" << d_lookB_WRT_LAT << std::endl;
3125 // std::cout << "d_lookB_WRT_LON" << d_lookB_WRT_LON << std::endl;
3126 // std::cout << "d_lookB_WRT_RAD" << d_lookB_WRT_RAD << std::endl;
3127 
3128 
3129  // SpiceRotation* pBodyRot = pCamera->bodyRotation();
3130 
3131  // "InstumentPosition()->Coordinate()" returns the instrument coordinate in J2000;
3132  // then the body rotation "ReferenceVector" rotates that into body-fixed coordinates
3133 // sB = pBodyRot->ReferenceVector(pCamera->instrumentPosition()->Coordinate());
3134 
3135 // lookB[0] = pB[0] - sB[0];
3136 // lookB[1] = pB[1] - sB[1];
3137 // lookB[2] = pB[2] - sB[2];
3138 
3139  // get look vector in the camera frame
3140 // lookJ = pBodyRot->J2000Vector( lookB );
3141 
3142 // SpiceRotation* pInstRot = pCamera->instrumentRotation();
3143 // lookC = pInstRot->ReferenceVector(lookJ);
3144 
3145  // get J2000 to camera rotation matrix
3146 // CJ = pCamera->instrumentRotation()->Matrix();
3147 
3148 // std::cout << CJ << std::endl;
3149 
3150  // collinearity auxiliaries
3151 // NX_C = CJ[0]*lookJ[0] + CJ[1]*lookJ[1] + CJ[2]*lookJ[2];
3152 // NY_C = CJ[3]*lookJ[0] + CJ[4]*lookJ[1] + CJ[5]*lookJ[2];
3153 // D_C = CJ[6]*lookJ[0] + CJ[7]*lookJ[1] + CJ[8]*lookJ[2];
3154 // a1 = fl/D_C;
3155 // a2 = NX_C/D_C;
3156 // a3 = NY_C/D_C;
3157 
3158  int nIndex = 0;
3159 
3160  if (m_spacecraftPositionSolveType != Nothing) {
3161 // SpicePosition* pInstPos = pCamera->instrumentPosition();
3162 
3163  // Add the partial for the x coordinate of the position (differentiating
3164  // point(x,y,z) - spacecraftPosition(x,y,z) in J2000
3165 // coeff_image(0,nIndex) = a1 * (CJ[6]*a2 - CJ[0]);
3166 // coeff_image(1,nIndex) = a1 * (CJ[6]*a3 - CJ[3]);
3167 
3168  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
3169  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_X, icoef, &coeff_image(0, nIndex), &coeff_image(1, nIndex));
3170  nIndex++;
3171  }
3172 
3173 // std::cout << coeff_image << std::endl;
3174 // if ( m_spacecraftPositionSolveType > PositionOnly ) {
3175 // dTime = pInstPos->EphemerisTime() - pInstPos->GetBaseTime();
3176 // dTime = dTime/pInstRot->GetTimeScale();
3177 //
3178 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3179 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3180 // nIndex++;
3181 //
3182 // if ( m_spacecraftPositionSolveType == PositionVelocityAcceleration ) {
3183 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3184 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3185 // nIndex++;
3186 // }
3187 // }
3188 
3189  // Add the partial for the y coordinate of the position
3190 // coeff_image(0,nIndex) = a1 * (CJ[7]*a2 - CJ[1]);
3191 // coeff_image(1,nIndex) = a1 * (CJ[7]*a3 - CJ[4]);
3192  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
3193  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_Y, icoef, &coeff_image(0, nIndex), &coeff_image(1, nIndex));
3194  nIndex++;
3195  }
3196 
3197 // if ( m_spacecraftPositionSolveType > PositionOnly ) {
3198 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3199 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3200 // nIndex++;
3201 //
3202 // if ( m_spacecraftPositionSolveType == PositionVelocityAcceleration ) {
3203 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3204 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3205 // nIndex++;
3206 // }
3207 // }
3208 //
3209  // Add the partial for the z coordinate of the position
3210 // coeff_image(0,nIndex) = a1 * (CJ[8]*a2 - CJ[2]);
3211 // coeff_image(1,nIndex) = a1 * (CJ[8]*a3 - CJ[5]);
3212  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
3213  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_Z, icoef, &coeff_image(0, nIndex), &coeff_image(1, nIndex));
3214  nIndex++;
3215  }
3216 
3217 // if ( m_spacecraftPositionSolveType > PositionOnly ) {
3218 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3219 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3220 // nIndex++;
3221 //
3222 // if ( m_spacecraftPositionSolveType == PositionVelocityAcceleration ) {
3223 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3224 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3225 // nIndex++;
3226 // }
3227 // }
3228  }
3229 //
3230  if (m_cmatrixSolveType != None) {
3231 // TC = pInstRot->ConstantMatrix();
3232 // TB = pInstRot->TimeBasedMatrix();
3233 //
3234 // dTime = pInstRot->EphemerisTime() - pInstRot->GetBaseTime();
3235 // dTime = dTime/pInstRot->GetTimeScale();
3236 //
3237 // // additional collinearity auxiliaries
3238 // NX = TB[0]*lookJ[0] + TB[1]*lookJ[1] + TB[2]*lookJ[2];
3239 // NY = TB[3]*lookJ[0] + TB[4]*lookJ[1] + TB[5]*lookJ[2];
3240 
3241  // Add the partials for ra
3242  for (int icoef = 0; icoef < m_nNumberCameraCoefSolved; icoef++) {
3243 // if( icoef == 0 )
3244 // {
3245 // z1 = -TB[1]*lookJ[0]+TB[0]*lookJ[1];
3246 // z2 = -TB[4]*lookJ[0]+TB[3]*lookJ[1];
3247 // z3 = -TB[7]*lookJ[0]+TB[6]*lookJ[1];
3248 // z4 = TC[6]*z1+TC[7]*z2+TC[8]*z3;
3249 //
3250 // coeff_image(0,nIndex) = a1*(TC[0]*z1+TC[1]*z2+TC[2]*z3 - z4*a2);
3251 // coeff_image(1,nIndex) = a1*(TC[3]*z1+TC[4]*z2+TC[5]*z3 - z4*a3);
3252 // nIndex++;
3253 // }
3254 // else
3255 // {
3256 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3257 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3258 // nIndex++;
3259 // }
3260  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_RightAscension, icoef, &coeff_image(0, nIndex), &coeff_image(1, nIndex));
3261  nIndex++;
3262  }
3263 
3264 
3265  // Add the partials for dec
3266  for (int icoef = 0; icoef < m_nNumberCameraCoefSolved; icoef++) {
3267 // if( icoef == 0 )
3268 // {
3269 // d_lookC = pInstRot->ToReferencePartial(lookJ,SpiceRotation::WRT_Declination, icoef);
3270 // coeff_image(0,nIndex) = fl * LowDHigh(lookC,d_lookC,0);
3271 // coeff_image(1,nIndex) = fl * LowDHigh(lookC,d_lookC,1);
3272 // nIndex++;
3273 // }
3274 // else
3275 // {
3276 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3277 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3278 // nIndex++;
3279 // }
3280  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Declination, icoef, &coeff_image(0, nIndex), &coeff_image(1, nIndex));
3281  nIndex++;
3282  }
3283 
3284  // Add the partial for twist if necessary
3285  if (m_bSolveTwist) {
3286 // z1 = TC[6]*NY-TC[7]*NX;
3287 //
3288  for (int icoef = 0; icoef < m_nNumberCameraCoefSolved; icoef++) {
3289 // if( icoef == 0 )
3290 // {
3291 // coeff_image(0,nIndex) = a1*(((TC[0]*NY-TC[1]*NX) - z1*a2));
3292 // coeff_image(1,nIndex) = a1*(((TC[3]*NY-TC[4]*NX) - z1*a3));
3293 // nIndex++;
3294 // }
3295 // else
3296 // {
3297 // coeff_image(0,nIndex) = coeff_image(0,nIndex-1) * dTime;
3298 // coeff_image(1,nIndex) = coeff_image(1,nIndex-1) * dTime;
3299 // nIndex++;
3300 // }
3301  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Twist, icoef, &coeff_image(0, nIndex), &coeff_image(1, nIndex));
3302  nIndex++;
3303  }
3304  }
3305  }
3306 
3307  // partials for 3D point
3308 // d_lookJ = pBodyRot->J2000Vector(d_lookB_WRT_LAT);
3309 // d_lookC = pInstRot->ReferenceVector(d_lookJ);
3310 
3311 // coeff_point3D(0,0) = fl * LowDHigh(lookC,d_lookC,0);
3312 // coeff_point3D(1,0) = fl * LowDHigh(lookC,d_lookC,1);
3313 //
3314 // d_lookJ = pBodyRot->J2000Vector(d_lookB_WRT_LON);
3315 // d_lookC = pInstRot->ReferenceVector(d_lookJ);
3316 //
3317 // coeff_point3D(0,1) = fl * LowDHigh(lookC,d_lookC,0);
3318 // coeff_point3D(1,1) = fl * LowDHigh(lookC,d_lookC,1);
3319 //
3320 // d_lookJ = pBodyRot->J2000Vector(d_lookB_WRT_RAD);
3321 // d_lookC = pInstRot->ReferenceVector(d_lookJ);
3322 //
3323 // coeff_point3D(0,2) = fl * LowDHigh(lookC,d_lookC,0);
3324 // coeff_point3D(1,2) = fl * LowDHigh(lookC,d_lookC,1);
3325 
3326  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_LAT, &coeff_point3D(0, 0),
3327  &coeff_point3D(1, 0));
3328  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_LON, &coeff_point3D(0, 1),
3329  &coeff_point3D(1, 1));
3330 
3331  // test added to check old test case that didn't solve for radius
3332  // if (m_bSolveRadii || m_strSolutionMethod == "SPARSE")
3333  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_RAD, &coeff_point3D(0, 2),
3334  &coeff_point3D(1, 2));
3335 
3336 // std::cout << coeff_point3D << std::endl;
3337  // right-hand side (measured - computed)
3338  dMeasuredx = measure.GetFocalPlaneMeasuredX();
3339 // dComputedx = lookC[0] * fl / lookC[2];
3340 
3341  dMeasuredy = measure.GetFocalPlaneMeasuredY();
3342 // dComputedy = lookC[1] * fl / lookC[2];
3343 
3344  deltax = dMeasuredx - dComputedx;
3345  deltay = dMeasuredy - dComputedy;
3346 
3347  coeff_RHS(0) = deltax;
3348  coeff_RHS(1) = deltay;
3349 
3350  dObservationSigma = 1.4 * pCamera->PixelPitch();
3351  dObservationWeight = 1.0 / dObservationSigma;
3352 
3353 // std::cout << "Measuredx " << dMeasuredx << " Measuredy = " << dMeasuredy << std::endl;
3354 // std::cout << "dComputedx " << dComputedx << " dComputedy = " << dComputedy << std::endl;
3355 // std::cout << coeff_image << std::endl;
3356 // std::cout << coeff_point3D << std::endl;
3357 // std::cout << dMeasuredx << " " << dComputedx << std::endl << dMeasuredy << " " << dComputedy << std::endl;
3358 // std::cout << coeff_RHS << std::endl;
3359 
3360  // multiply coefficients by observation weight
3361  coeff_image *= dObservationWeight;
3362  coeff_point3D *= dObservationWeight;
3363  coeff_RHS *= dObservationWeight;
3364 
3365  m_Statsx.AddData(deltax);
3366  m_Statsy.AddData(deltay);
3367 
3368  return true;
3369  }
3370  */
3371 
3372 
3385  double BundleAdjust::Solve() {
3386  double averageError;
3387  std::vector<int> observationInitialValueIndex; // image index for observation inital values
3388  int iIndex = -1; // image index for initial spice for an observation
3389  int oIndex = -1; // Index of current observation
3390 
3391  ComputeNumberPartials();
3392 
3393  ComputeImageParameterWeights();
3394 
3395 // InitializePoints();
3396 
3397  if (m_bObservationMode)
3398  observationInitialValueIndex.assign(m_pObsNumList->observationSize(), -1);
3399 
3400  for (int i = 0; i < Images(); i++) {
3401  Camera *pCamera = m_pCnet->Camera(i);
3402 
3403  if (m_bObservationMode) {
3404  oIndex = i;
3405  oIndex = m_pObsNumList->observationNumberMapIndex(oIndex); // get observation index for this image
3406  iIndex = observationInitialValueIndex[oIndex]; // get image index for initial observation values
3407  }
3408 
3409  if (m_cmatrixSolveType != None) {
3410  // For observations, find the index of the first image and use its polynomial for the observation
3411  // initial coefficient values. Initialize indices to -1
3412 
3413  // Fit the camera pointing to an equation
3414  SpiceRotation *pSpiceRot = pCamera->instrumentRotation();
3415 
3416  if (!m_bObservationMode) {
3417  pSpiceRot->SetPolynomialDegree(m_nCKDegree); // Set the ck polynomial fit degree
3418  pSpiceRot->SetPolynomial(m_nPointingType);
3419  pSpiceRot->SetPolynomialDegree(m_nsolveCKDegree); // Update to the solve polynomial fit degree
3420  }
3421  else {
3422  // Index of image to use for initial values is set already so set polynomial to initial values
3423  if (iIndex >= 0) {
3424  SpiceRotation *pOrot = m_pCnet->Camera(iIndex)->instrumentRotation(); //Observation rotation
3425  std::vector<double> anglePoly1, anglePoly2, anglePoly3;
3426  pOrot->GetPolynomial(anglePoly1, anglePoly2, anglePoly3);
3427  double baseTime = pOrot->GetBaseTime();
3428  double timeScale = pOrot->GetTimeScale();
3429  pSpiceRot->SetPolynomialDegree(m_nsolveCKDegree); // Update to the solve polynomial fit degree
3430  pSpiceRot->SetOverrideBaseTime(baseTime, timeScale);
3431  pSpiceRot->SetPolynomial(anglePoly1, anglePoly2, anglePoly3, m_nPointingType);
3432  }
3433  else {
3434  // Index of image to use for inital observation values has not been assigned yet so use this image
3435  pSpiceRot->SetPolynomialDegree(m_nCKDegree);
3436  pSpiceRot->SetPolynomial(m_nPointingType);
3437  pSpiceRot->SetPolynomialDegree(m_nsolveCKDegree); // Update to the solve polynomial fit degree
3438  observationInitialValueIndex[oIndex] = i;
3439  }
3440  }
3441  }
3442 
3443  if (m_spacecraftPositionSolveType != Nothing) {
3444  // Set the spacecraft position to an equation
3445  SpicePosition *pSpicePos = pCamera->instrumentPosition();
3446 
3447  if (!m_bObservationMode) {
3448  pSpicePos->SetPolynomialDegree(m_nSPKDegree); // Set the SPK polynomial fit degree
3449  pSpicePos->SetPolynomial(m_nPositionType);
3450  pSpicePos->SetPolynomialDegree(m_nsolveSPKDegree); // Update to the solve polynomial fit degree
3451  }
3452  else {
3453  // Index of image to use for initial values is set already so set polynomial to initial values
3454  if (iIndex >= 0) {
3455  SpicePosition *pOpos = m_pCnet->Camera(iIndex)->instrumentPosition(); //Observation position
3456  std::vector<double> posPoly1, posPoly2, posPoly3;
3457  pOpos->GetPolynomial(posPoly1, posPoly2, posPoly3);
3458  double baseTime = pOpos->GetBaseTime();
3459  double timeScale = pOpos->GetTimeScale();
3460  pSpicePos->SetPolynomialDegree(m_nsolveSPKDegree); // Set the SPK polynomial fit degree
3461  pSpicePos->SetOverrideBaseTime(baseTime, timeScale);
3462  pSpicePos->SetPolynomial(posPoly1, posPoly2, posPoly3, m_nPositionType);
3463  }
3464  else {
3465  // Index of image to use for inital observation values has not been assigned yet so use this image
3466  pSpicePos->SetPolynomialDegree(m_nSPKDegree); // Set the SPK polynomial fit degree
3467  pSpicePos->SetPolynomial(m_nPositionType);
3468  pSpicePos->SetPolynomialDegree(m_nsolveSPKDegree); // Update to the solve polynomial fit degree
3469  observationInitialValueIndex[oIndex] = i;
3470  }
3471  }
3472  }
3473  }
3474 
3475  // Compute the apriori lat/lons for each nonheld point
3476  m_pCnet->ComputeApriori();
3477 
3478  // Initialize solution parameters
3479  double sigmaXY, sigmaHat, sigmaX, sigmaY;
3480  sigmaXY = sigmaHat = sigmaX = sigmaY = 0.;
3481  m_nIteration = -1;
3482 
3483  clock_t t1 = clock();
3484 
3485  // Create the basis function and prep for a least squares solution
3486  m_nBasisColumns = BasisColumns();
3487  BasisFunction basis("Bundle", m_nBasisColumns, m_nBasisColumns);
3488  if (m_strSolutionMethod == "OLDSPARSE") {
3489  m_pLsq = new Isis::LeastSquares(basis, true,
3490  m_pCnet->GetNumValidMeasures() * 2, m_nBasisColumns, true);
3491  SetParameterWeights();
3492  }
3493  else
3494  m_pLsq = new Isis::LeastSquares(basis);
3495 
3496  // set size of partial derivative vectors
3497  m_dxKnowns.resize(m_nBasisColumns);
3498  m_dyKnowns.resize(m_nBasisColumns);
3499 
3500  double dprevious_Sigma0 = 10;
3501  m_dSigma0 = 0.0;
3502 
3503  Progress progress;
3504 
3505  while (m_nIteration < m_nMaxIterations) {
3506  m_nIteration++;
3507 
3508  m_pCnet->ComputeResiduals();
3509  m_dError = m_pCnet->GetMaximumResidual();
3510  averageError = m_pCnet->AverageResidual();
3511 
3512  // kle testing - print residual(?) statistics
3513 // printf("Iteration #%d\n\tAverage Error: %lf\n\tSigmaXY: %lf\n\tSigmaHat: %lf\n\tSigmaX: %lf\n\tSigmaY: %lf\n",
3514 // m_nIteration, averageError, sigmaXY, sigmaHat, sigmaX, sigmaY);
3515 
3516 // if (m_bPrintSummary)
3517  IterationSummary(averageError, sigmaXY, sigmaHat, sigmaX, sigmaY);
3518 
3519  // these vectors hold statistics for right-hand sides (observed - computed)
3520  m_Statsx.Reset();
3521  m_Statsy.Reset();
3522 
3523  // these vectors hold statistics for true residuals
3524  m_Statsrx.Reset();
3525  m_Statsry.Reset();
3526  m_Statsrxy.Reset();
3527 
3528  if ( m_nIteration == 0 )
3529  sigmaHat = 10.0;
3530 
3531  // we've converged
3532  if (fabs(dprevious_Sigma0 - m_dSigma0) <= m_dConvergenceThreshold) {
3533  clock_t t2 = clock();
3534 
3535  m_bConverged = true;
3536 
3537  m_dElapsedTime = ((t2 - t1) / (double)CLOCKS_PER_SEC);
3538 
3539  // retrieve vectors of image and point parameter corrections
3540  GetSparseParameterCorrections();
3541 
3542  if (m_bErrorPropagation) {
3543  progress.SetText("Performing Error Propagation...");
3544 
3545  // printf("start error prop\n");
3546  clock_t terror1 = clock();
3547  if (m_pLsq->SparseErrorPropagation())
3548  SetPostBundleSigmas();
3549  clock_t terror2 = clock();
3550  m_dElapsedTimeErrorProp = ((terror2 - terror1) / (double)CLOCKS_PER_SEC);
3551  // printf("end error prop\n");
3552  }
3553 
3554  ComputeBundleStatistics();
3555  Output();
3556 
3557  return m_dError;
3558  }
3559 
3560  dprevious_Sigma0 = m_dSigma0;
3561 
3562  if ( m_nIteration > 0 )
3563  m_pLsq->Reset();
3564 
3565  // Loop through the control net and add the partials for each point
3566  // need generic 'AddPartials' function which calls necessary partials
3567  // function dependent on sensor, i.e., frame, pushframe, linescan, radar?
3568  int nObjectPoints = m_pCnet->GetNumPoints();
3569  for (int i = 0; i < nObjectPoints; i++)
3570  AddPartials(i);
3571 
3572  // Try to solve the iteration
3573  try {
3574  if (m_strSolutionMethod == "SVD") {
3575  m_pLsq->Solve(Isis::LeastSquares::SVD);
3576  }
3577  else if (m_strSolutionMethod == "QRD") {
3578  m_pLsq->Solve(Isis::LeastSquares::QRD);
3579  }
3580  // next is the old SPARSE solution
3581  else {
3582 
3583  int zeroColumn = m_pLsq->Solve(Isis::LeastSquares::SPARSE);
3584 
3585  if (zeroColumn != 0) {
3586  QString msg;
3587  int imageColumns = Observations() * m_nNumImagePartials;
3588  if (zeroColumn <= imageColumns) {
3589  msg = "Solution matrix has a column of zeros which probably ";
3590  msg += "indicates an image with no points. Running the program, ";
3591  msg += "cnetcheck, before jigsaw should catch these problems.";
3592  }
3593  else {
3594  msg = "Solution matrix has a column of zeros which probably ";
3595  msg += "indicates a point with no measures. Running the program, ";
3596  msg += "cnetcheck, before jigsaw should catch these problems.";
3597  }
3598  throw IException(IException::Unknown, msg, _FILEINFO_);
3599  }
3600  }
3601  }
3602  catch (IException &e) {
3603  QString msg = "Unable to solve in BundleAdjust, ";
3604  msg += "Iteration " + toString(m_nIteration) + " of ";
3605  msg += toString(m_nMaxIterations) + ", Sigma0 = ";
3606  msg += toString(m_dConvergenceThreshold);
3607  throw IException(IException::Unknown, msg, _FILEINFO_);
3608  }
3609 
3610  // Ok take the results and put them back into the camera blobs
3611  Update(basis);
3612 
3613  // get residuals and load into statistics vectors
3614  std::vector<double> residuals = m_pLsq->Residuals();
3615  int nresiduals = residuals.size();
3616  for (int i = 0; i < nresiduals; i++) {
3617  m_Statsrx.AddData(residuals[i]);
3618  m_Statsry.AddData(residuals[i+1]);
3619  i++;
3620  }
3621 
3622  m_Statsrxy.AddData(&residuals[0], nresiduals);
3623 
3624  m_nObservations = m_pLsq->Knowns();
3625  m_nUnknownParameters = m_nBasisColumns;
3626 
3627  //Compute stats for residuals
3628  double drms_rx = sqrt(m_Statsrx.SumSquare() / (m_nObservations / 2));
3629  double drms_ry = sqrt(m_Statsry.SumSquare() / (m_nObservations / 2));
3630  double drms_rxy = sqrt(m_Statsrxy.SumSquare() / m_nObservations);
3631  double davg_rxy = m_Statsrxy.Average();
3632  printf("avg rxy: %20.10lf\nrms x: %20.10lf\nrms y: %20.10lf\nrms xy: %20.10lf\n", davg_rxy, drms_rx, drms_ry, drms_rxy);
3633 
3634  sigmaXY = sqrt((m_Statsx.SumSquare() + m_Statsy.SumSquare()) / m_pLsq->Knowns());
3635  m_nDegreesOfFreedom = m_pLsq->GetDegreesOfFreedom();
3636  sigmaHat = (m_nObservations - m_nBasisColumns) ?
3637  (sqrt((m_Statsx.SumSquare() + m_Statsy.SumSquare()) / m_nDegreesOfFreedom))
3638  : 0.;
3639 
3640  m_dSigma0 = m_pLsq->GetSigma0();
3641 
3642  printf("Observations: %d Unknowns: %d\n", m_nObservations, m_nUnknownParameters);
3643  printf("SigmaHat: %20.10lf Sigma0: %20.10lf\n", sigmaHat, m_dSigma0);
3644 
3645  sigmaX = m_Statsx.TotalPixels() ?
3646  sqrt(m_Statsx.SumSquare() / m_Statsx.TotalPixels()) : 0.;
3647  sigmaY = m_Statsy.TotalPixels() ?
3648  sqrt(m_Statsy.SumSquare() / m_Statsy.TotalPixels()) : 0.;
3649  }
3650 
3651  QString msg = "Did not converge to Sigma0 criteria [";
3652  msg += toString(m_dConvergenceThreshold) + "] in less than [";
3653  msg += toString(m_nMaxIterations) + "] iterations";
3654  throw IException(IException::User, msg, _FILEINFO_);
3655  }
3656 
3657 
3663  void BundleAdjust::GetSparseParameterCorrections() {
3664 
3665  int nValidPoints = m_pCnet->GetNumValidPoints();
3666  int nTotalPoints = m_pCnet->GetNumPoints();
3667  int nPointCorrections = 3 * nValidPoints;
3668  m_Point_Corrections.resize(nValidPoints);
3669 
3670  m_dEpsilons = m_pLsq->GetEpsilons();
3671  int nCorrections = m_dEpsilons.size();
3672  int nImageCorrections = nCorrections - nPointCorrections;
3673  m_Image_Corrections.resize(nImageCorrections);
3674 
3675  // fill image corrections
3676  for( int i = 0; i < nImageCorrections; i++ )
3677  m_Image_Corrections[i] = m_dEpsilons[i];
3678 
3679  // fill point corrections
3680  int nindex = nImageCorrections;
3681  int nPointIndex = 0;
3682  for ( int i = 0; i < nTotalPoints; i++ ) {
3683 
3684  const ControlPoint *point = m_pCnet->GetPoint(i);
3685  if ( point->IsIgnored() )
3686  continue;
3687 
3688  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
3689 
3690  corrections[0] = m_dEpsilons[nindex];
3691  corrections[1] = m_dEpsilons[nindex+1];
3692  corrections[2] = m_dEpsilons[nindex+2];
3693 
3694  nindex += 3;
3695  nPointIndex++;
3696  }
3697  }
3698 
3699 
3703  void BundleAdjust::AddPartials(int nPointIndex) {
3704  const ControlPoint *point = m_pCnet->GetPoint(nPointIndex);
3705 
3706  if (point->IsIgnored())
3707  return;
3708 
3709  // pointers to partial derivative vectors
3710  // ***** can this be a 2xm gmm sparse matrix?
3711  // ***** or 2 1xm gmm sparse vectors?
3712  double *px = &m_dxKnowns[0];
3713  double *py = &m_dyKnowns[0];
3714 
3715  // additional vectors
3716  std::vector<double> d_lookB_WRT_LAT;
3717  std::vector<double> d_lookB_WRT_LON;
3718  std::vector<double> d_lookB_WRT_RAD;
3719 
3720  std::vector<double> TC; // platform to camera (constant rotation matrix)
3721  std::vector<double> TB; // J2000 to platform (time-based rotation matrix)
3722  std::vector<double> CJ; // J2000 to Camera (product of TB and TC)
3723 
3724  Camera *pCamera = NULL;
3725 
3726  int nIndex;
3727  double dMeasuredx, dMeasuredy;
3728  double deltax, deltay;
3729  double dObservationSigma;
3730  double dObservationWeight;
3731 
3732  // partials for fixed point w/r lat, long, radius in Body-Fixed km
3733  d_lookB_WRT_LAT = point->GetMeasure(0)->Camera()->GroundMap()->PointPartial(
3734  point->GetAdjustedSurfacePoint(),
3735  CameraGroundMap::WRT_Latitude);
3736  d_lookB_WRT_LON = point->GetMeasure(0)->Camera()->GroundMap()->PointPartial(
3737  point->GetAdjustedSurfacePoint(),
3738  CameraGroundMap::WRT_Longitude);
3739 
3740  // Test to match old test run that didn't solve for radius
3741  if (m_bSolveRadii || m_strSolutionMethod == "OLDSPARSE")
3742  d_lookB_WRT_RAD = point->GetMeasure(0)->Camera()->GroundMap()->PointPartial(
3743  point->GetAdjustedSurfacePoint(),
3744  CameraGroundMap::WRT_Radius);
3745 
3746 // std::cout << "d_lookB_WRT_LAT" << d_lookB_WRT_LAT << std::endl;
3747 // std::cout << "d_lookB_WRT_LON" << d_lookB_WRT_LON << std::endl;
3748 // std::cout << "d_lookB_WRT_RAD" << d_lookB_WRT_RAD << std::endl;
3749 
3750  int nObservations = point->GetNumMeasures();
3751  for (int i = 0; i < nObservations; i++) {
3752  const ControlMeasure *measure = point->GetMeasure(i);
3753  if (measure->IsIgnored())
3754  continue;
3755 
3756  // zero partial derivative vectors
3757  memset(px, 0, m_nBasisColumns * sizeof(double));
3758  memset(py, 0, m_nBasisColumns * sizeof(double));
3759 
3760  pCamera = measure->Camera();
3761 
3762  // no need to call SetImage for framing camera ( CameraType = 0 )
3763  if (pCamera->GetCameraType() != 0) {
3764  // Set the Spice to the measured point
3765  // but, can this be simplified???
3766  if (!pCamera->SetImage(measure->GetSample(), measure->GetLine()))
3767  printf("\n***Call to Camera::SetImage failed - need to handle this***\n");
3768  }
3769 
3770  //Compute the look vector in instrument coordinates based on time of observation and apriori lat/lon/radius
3771  double dComputedx, dComputedy;
3772  if (!(pCamera->GroundMap()->GetXY(point->GetAdjustedSurfacePoint(), &dComputedx, &dComputedy))) {
3773  QString msg = "Unable to map apriori surface point for measure ";
3774  msg += measure->GetCubeSerialNumber() + " on point " + point->GetId() + " into focal plane";
3775  throw IException(IException::User, msg, _FILEINFO_);
3776  }
3777 
3778  // Determine the image index
3779  nIndex = m_pSnList->serialNumberIndex(measure->GetCubeSerialNumber());
3780  nIndex = ImageIndex(nIndex);
3781 
3782  if (m_spacecraftPositionSolveType != Nothing) {
3783 
3784  // Add the partial for the x coordinate of the position (differentiating
3785  // point(x,y,z) - spacecraftPosition(x,y,z) in J2000
3786 
3787  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
3788  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_X, icoef,
3789  &px[nIndex], &py[nIndex]);
3790  nIndex++;
3791  }
3792 
3793  // Add the partial for the y coordinate of the position
3794  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
3795  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_Y, icoef, &px[nIndex], &py[nIndex]);
3796  nIndex++;
3797  }
3798 
3799  // Add the partial for the z coordinate of the position
3800  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
3801  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_Z, icoef, &px[nIndex], &py[nIndex]);
3802  nIndex++;
3803  }
3804  }
3805 
3806  if (m_cmatrixSolveType != None) {
3807 
3808  // Add the partials for ra
3809  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
3810  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_RightAscension, icoef, &px[nIndex], &py[nIndex]);
3811  nIndex++;
3812  }
3813 
3814  // Add the partials for dec
3815  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
3816  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Declination, icoef, &px[nIndex], &py[nIndex]);
3817  nIndex++;
3818  }
3819 
3820  // Add the partial for twist if necessary
3821  if (m_bSolveTwist) {
3822  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
3823  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Twist, icoef, &px[nIndex], &py[nIndex]);
3824  nIndex++;
3825  }
3826  }
3827  }
3828 
3829  // partials for 3D point
3830  if (point->GetType() != ControlPoint::Fixed ||
3831  m_strSolutionMethod == "SPECIALK" ||
3832  m_strSolutionMethod == "SPARSE" ||
3833  m_strSolutionMethod == "OLDSPARSE") {
3834  nIndex = PointIndex(nPointIndex);
3835  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_LAT, &px[nIndex],
3836  &py[nIndex]);
3837  nIndex++;
3838  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_LON, &px[nIndex],
3839  &py[nIndex]);
3840  nIndex++;
3841 
3842  // test added to check old test case that didn't solve for radii
3843  if (m_bSolveRadii || m_strSolutionMethod == "OLDSPARSE")
3844  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_RAD, &px[nIndex],
3845  &py[nIndex]);
3846 
3847  }
3848  // right-hand side (measured - computed)
3849  dMeasuredx = measure->GetFocalPlaneMeasuredX();
3850  dMeasuredy = measure->GetFocalPlaneMeasuredY();
3851 
3852  deltax = dMeasuredx - dComputedx;
3853  deltay = dMeasuredy - dComputedy;
3854 
3855  dObservationSigma = 1.4 * pCamera->PixelPitch();
3856  dObservationWeight = 1.0 / (dObservationSigma * dObservationSigma);
3857 
3858 // std::cout << "yKnowns = ";
3859 // for (int i=0; i<m_dyKnowns.size(); i++)
3860 // std::cout << " " << m_dyKnowns[i] << std::endl;
3861 // std::cout << std::endl;
3862 // std::cout << "deltax and deltay = " << deltax << " " << deltay << " " << dObservationWeight << std::endl;
3863 
3864 
3865 
3866  m_pLsq->AddKnown(m_dxKnowns, deltax, dObservationWeight);
3867  m_pLsq->AddKnown(m_dyKnowns, deltay, dObservationWeight);
3868 
3869  m_Statsx.AddData(deltax);
3870  m_Statsy.AddData(deltay);
3871  }
3872  }
3873 
3874 
3878  /*
3879  void BundleAdjust::AddPartials(int nPointIndex) {
3880  const ControlPoint *point = m_pCnet->GetPoint(nPointIndex);
3881 
3882  if (point->IsIgnored())
3883  return;
3884 
3885  // pointers to partial derivative vectors
3886  // ***** can this be a 2xm gmm sparse matrix?
3887  // ***** or 2 1xm gmm sparse vectors?
3888  double *px = &m_dxKnowns[0];
3889  double *py = &m_dyKnowns[0];
3890 
3891  // additional vectors
3892 // double pB[3]; // Point on surface
3893  std::vector<double> sB(3); // Spacecraft position in body-fixed coordinates
3894  std::vector<double> lookB(3); // "look" vector in body-fixed coordinates
3895  std::vector<double> lookC(3); // "look" vector in camera coordinates
3896  std::vector<double> lookJ(3); // "look" vector in J2000 coordinates
3897  std::vector<double> d_lookJ;
3898  std::vector<double> d_lookC;
3899  std::vector<double> d_lookB_WRT_LAT;
3900  std::vector<double> d_lookB_WRT_LON;
3901  std::vector<double> d_lookB_WRT_RAD;
3902 
3903  std::vector<double> TC; // platform to camera (constant rotation matrix)
3904  std::vector<double> TB; // J2000 to platform (time-based rotation matrix)
3905  std::vector<double> CJ; // J2000 to Camera (product of TB and TC)
3906 
3907  Camera *pCamera = NULL;
3908 // double fl;
3909 
3910  int nIndex;
3911 // double dMeasuredx,dComputedx,dMeasuredy,dComputedy;
3912  double dMeasuredx, dMeasuredy;
3913  double deltax, deltay;
3914  double dObservationSigma;
3915  double dObservationWeight;
3916 
3917  // auxiliary variables
3918 // double NX_C, NY_C, D_C;
3919 // double NX, NY;
3920 // double a1, a2, a3;
3921 // double z1, z2, z3, z4;
3922 
3923 // double dTime = -1.0;
3924 
3925  // partials for fixed point w/r lat, long, radius in Body-Fixed km
3926  d_lookB_WRT_LAT = point->GetMeasure(0)->Camera()->GroundMap()->PointPartial(
3927  point->GetAdjustedSurfacePoint(),
3928  CameraGroundMap::WRT_Latitude);
3929  d_lookB_WRT_LON = point->GetMeasure(0)->Camera()->GroundMap()->PointPartial(
3930  point->GetAdjustedSurfacePoint(),
3931  CameraGroundMap::WRT_Longitude);
3932 
3933  // Test to match old test run that didn't solve for radius
3934  if (m_bSolveRadii || m_strSolutionMethod == "SPARSE")
3935  d_lookB_WRT_RAD = point->GetMeasure(0)->Camera()->GroundMap()->PointPartial(
3936  point->GetAdjustedSurfacePoint(),
3937  CameraGroundMap::WRT_Radius);
3938 
3939 // std::cout << "d_lookB_WRT_LAT" << d_lookB_WRT_LAT << std::endl;
3940 // std::cout << "d_lookB_WRT_LON" << d_lookB_WRT_LON << std::endl;
3941 // std::cout << "d_lookB_WRT_RAD" << d_lookB_WRT_RAD << std::endl;
3942 
3943  // Compute fixed point in body-fixed coordinates km
3944 // latrec_c((double) point->GetAdjustedSurfacePoint().GetLocalRadius().kilometers(),
3945 // (double) point->GetAdjustedSurfacePoint().GetLongitude().radians(),
3946 // (double) point->GetAdjustedSurfacePoint().GetLatitude().radians(),
3947 // pB);
3948 
3949  int nObservations = point->GetNumMeasures();
3950  for (int i = 0; i < nObservations; i++) {
3951  const ControlMeasure *measure = point->GetMeasure(i);
3952  if (measure->IsIgnored())
3953  continue;
3954 
3955 
3956  // zero partial derivative vectors
3957  memset(px, 0, m_nBasisColumns * sizeof(double));
3958  memset(py, 0, m_nBasisColumns * sizeof(double));
3959 
3960  pCamera = measure->Camera();
3961 
3962  // Get focal length with direction
3963 // fl = pCamera->DistortionMap()->UndistortedFocalPlaneZ();
3964 
3965  // no need to call SetImage for framing camera ( CameraType = 0 )
3966  if (pCamera->GetCameraType() != 0) {
3967  // Set the Spice to the measured point
3968  // but, can this be simplified???
3969  if (!pCamera->SetImage(measure->GetSample(), measure->GetLine()))
3970  printf("\n***Call to Camera::SetImage failed - need to handle this***\n");
3971  }
3972 
3973  //Compute the look vector in instrument coordinates based on time of observation and apriori lat/lon/radius
3974  double dComputedx, dComputedy;
3975  if (!(pCamera->GroundMap()->GetXY(point->GetAdjustedSurfacePoint(), &dComputedx, &dComputedy))) {
3976  QString msg = "Unable to map apriori surface point for measure ";
3977  msg += measure->GetCubeSerialNumber() + " on point " + point->GetId() + " into focal plane";
3978  throw iException::Message(iException::User, msg, _FILEINFO_);
3979  }
3980 
3981  // May need to do back of planet test here TODO
3982 // SpiceRotation *pBodyRot = pCamera->bodyRotation();
3983 
3984  // "InstumentPosition()->Coordinate()" returns the instrument coordinate in J2000;
3985  // then the body rotation "ReferenceVector" rotates that into body-fixed coordinates
3986 // sB = pBodyRot->ReferenceVector(pCamera->instrumentPosition()->Coordinate());
3987 
3988 // lookB[0] = pB[0] - sB[0];
3989 // lookB[1] = pB[1] - sB[1];
3990 // lookB[2] = pB[2] - sB[2];
3991 
3992  // get look vector in the camera frame
3993 // lookJ = pBodyRot->J2000Vector(lookB);
3994 // SpiceRotation *pInstRot = pCamera->instrumentRotation();
3995 // lookC = pInstRot->ReferenceVector(lookJ);
3996 
3997  // get J2000 to camera rotation matrix
3998 // CJ = pCamera->instrumentRotation()->Matrix();
3999 
4000  // collinearity auxiliaries
4001 // NX_C = CJ[0] * lookJ[0] + CJ[1] * lookJ[1] + CJ[2] * lookJ[2];
4002 // NY_C = CJ[3] * lookJ[0] + CJ[4] * lookJ[1] + CJ[5] * lookJ[2];
4003 // D_C = CJ[6] * lookJ[0] + CJ[7] * lookJ[1] + CJ[8] * lookJ[2];
4004 // a1 = fl / D_C;
4005 // a2 = NX_C / D_C;
4006 // a3 = NY_C / D_C;
4007 
4008  // Determine the image index
4009  nIndex = m_pSnList->serialNumberIndex(measure->GetCubeSerialNumber());
4010  nIndex = ImageIndex(nIndex);
4011 
4012  if (m_spacecraftPositionSolveType != Nothing) {
4013 // SpicePosition *pInstPos = pCamera->instrumentPosition();
4014 
4015  // Add the partial for the x coordinate of the position (differentiating
4016  // point(x,y,z) - spacecraftPosition(x,y,z) in J2000
4017  // ***TODO*** check derivative with scale added to dTime
4018 // px[nIndex] = a1 * (CJ[6] * a2 - CJ[0]);
4019 // py[nIndex] = a1 * (CJ[6] * a3 - CJ[3]);
4020 
4021  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
4022  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_X, icoef,
4023  &px[nIndex], &py[nIndex]);
4024  nIndex++;
4025  }
4026 
4027 // nIndex++;
4028 
4029 // if (m_spacecraftPositionSolveType > PositionOnly) {
4030 // dTime = pInstPos->EphemerisTime() - pInstPos->GetBaseTime();
4031 // dTime = dTime / pInstPos->GetTimeScale();
4032 
4033 // px[nIndex] = px[nIndex-1] * dTime;
4034 // py[nIndex] = py[nIndex-1] * dTime;
4035 // nIndex++;
4036 
4037 // if (m_spacecraftPositionSolveType == PositionVelocityAcceleration) {
4038 // px[nIndex] = px[nIndex-1] * dTime;
4039 // py[nIndex] = py[nIndex-1] * dTime;
4040 // nIndex++;
4041 // }
4042 // }
4043 
4044  // Add the partial for the y coordinate of the position
4045  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
4046  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_Y, icoef, &px[nIndex], &py[nIndex]);
4047  nIndex++;
4048  }
4049 // px[nIndex] = a1 * (CJ[7] * a2 - CJ[1]);
4050 // py[nIndex] = a1 * (CJ[7] * a3 - CJ[4]);
4051 // nIndex++;
4052 
4053 // if (m_spacecraftPositionSolveType > PositionOnly) {
4054 // px[nIndex] = px[nIndex-1] * dTime;
4055 // py[nIndex] = py[nIndex-1] * dTime;
4056 // nIndex++;
4057 
4058 // if (m_spacecraftPositionSolveType == PositionVelocityAcceleration) {
4059 // px[nIndex] = px[nIndex-1] * dTime;
4060 // py[nIndex] = py[nIndex-1] * dTime;
4061 // nIndex++;
4062 // }
4063 // }
4064 
4065  // Add the partial for the z coordinate of the position
4066 // px[nIndex] = a1 * (CJ[8] * a2 - CJ[2]);
4067 // py[nIndex] = a1 * (CJ[8] * a3 - CJ[5]);
4068  for (int icoef = 0; icoef < m_spacecraftPositionSolveType; icoef++) {
4069  pCamera->GroundMap()->GetdXYdPosition(SpicePosition::WRT_Z, icoef, &px[nIndex], &py[nIndex]);
4070  nIndex++;
4071  }
4072 // nIndex++;
4073 
4074 // if (m_spacecraftPositionSolveType > PositionOnly) {
4075 // px[nIndex] = px[nIndex-1] * dTime;
4076 // py[nIndex] = py[nIndex-1] * dTime;
4077 
4078 // nIndex++;
4079 
4080 // if (m_spacecraftPositionSolveType == PositionVelocityAcceleration) {
4081 // px[nIndex] = px[nIndex-1] * dTime;
4082 // py[nIndex] = py[nIndex-1] * dTime;
4083 // nIndex++;
4084 // }
4085 // }
4086  }
4087 
4088  if (m_cmatrixSolveType != None) {
4089 
4090 // TC = pInstRot->ConstantMatrix();
4091 // TB = pInstRot->TimeBasedMatrix();
4092 
4093 // dTime = pInstRot->EphemerisTime() - pInstRot->GetBaseTime();
4094 // dTime = dTime / pInstRot->GetTimeScale();
4095 
4096  // additional collinearity auxiliaries
4097 // NX = TB[0] * lookJ[0] + TB[1] * lookJ[1] + TB[2] * lookJ[2];
4098 // NY = TB[3] * lookJ[0] + TB[4] * lookJ[1] + TB[5] * lookJ[2];
4099 
4100 
4101  // Add the partials for ra
4102  for (int icoef = 0; icoef < m_nNumberCameraCoefSolved; icoef++) {
4103  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_RightAscension, icoef, &px[nIndex], &py[nIndex]);
4104 
4105 // if (icoef == 0) {
4106 // z1 = -TB[1] * lookJ[0] + TB[0] * lookJ[1];
4107 // z2 = -TB[4] * lookJ[0] + TB[3] * lookJ[1];
4108 // z3 = -TB[7] * lookJ[0] + TB[6] * lookJ[1];
4109 // z4 = TC[6] * z1 + TC[7] * z2 + TC[8] * z3;
4110 
4111 // px[nIndex] = a1 * (TC[0] * z1 + TC[1] * z2 + TC[2] * z3 - z4 * a2);
4112 // py[nIndex] = a1 * (TC[3] * z1 + TC[4] * z2 + TC[5] * z3 - z4 * a3);
4113 // }
4114 // else {
4115 // px[nIndex] = px[nIndex-1] * dTime;
4116 // py[nIndex] = py[nIndex-1] * dTime;
4117 // }
4118 
4119  nIndex++;
4120  }
4121 
4122  // Add the partials for dec
4123  for (int icoef = 0; icoef < m_nNumberCameraCoefSolved; icoef++) {
4124  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Declination, icoef, &px[nIndex], &py[nIndex]);
4125 // if( icoef == 0 ) {
4126 // d_lookC = pInstRot->ToReferencePartial(lookJ,SpiceRotation::WRT_Declination, icoef);
4127 // px[nIndex] = fl * LowDHigh(lookC,d_lookC,0);
4128 // py[nIndex] = fl * LowDHigh(lookC,d_lookC,1);
4129 // }
4130 // else {
4131 // px[nIndex] = px[nIndex-1] * dTime;
4132 // py[nIndex] = py[nIndex-1] * dTime;
4133 // }
4134 //
4135 // double z1 = -TB[1]*lookJ[0]+TB[0]*lookJ[1];
4136 // double z2 = -TB[4]*lookJ[0]+TB[3]*lookJ[1];
4137 // double z3 = -TB[7]*lookJ[0]+TB[6]*lookJ[1];
4138 
4139 // t1 = a1*(TC[0]*z1+TC[1]*z2+TC[2]*z3 - (TC[6]*z1+TC[7]*z2+TC[8]*z3)*a2);
4140 // t2 = a1*(TC[3]*z1+TC[4]*z2+TC[5]*z3 - (TC[6]*z1+TC[7]*z2+TC[8]*z3)*a3);
4141 
4142 // printf("xKnowns[%d]: %lf t1: %lf\n", nIndex,m_dxKnowns[nIndex],t1);
4143 // printf("yKnowns[%d]: %lf t2: %lf\n", nIndex,m_dyKnowns[nIndex],t2);
4144  nIndex++;
4145  }
4146 
4147  // Add the partial for twist if necessary
4148  if (m_bSolveTwist) {
4149 
4150 // z1 = TC[6] * NY - TC[7] * NX;
4151 
4152  for (int icoef = 0; icoef < m_nNumberCameraCoefSolved; icoef++) {
4153  pCamera->GroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Twist, icoef, &px[nIndex], &py[nIndex]);
4154 
4155 // if (icoef == 0) {
4156 // px[nIndex] = a1 * (((TC[0] * NY - TC[1] * NX) - z1 * a2));
4157 // py[nIndex] = a1 * (((TC[3] * NY - TC[4] * NX) - z1 * a3));
4158 // }
4159 // else {
4160 // px[nIndex] = px[nIndex-1] * dTime;
4161 // py[nIndex] = py[nIndex-1] * dTime;
4162 // }
4163 
4164  nIndex++;
4165  }
4166  // nIndex = (Images() - m_nHeldImages) * m_nNumImagePartials;
4167  }
4168  }
4169 
4170  // partials for 3D point
4171  if (point->GetType() != ControlPoint::Fixed ||
4172  m_strSolutionMethod == "SPECIALK" ||
4173  m_strSolutionMethod == "SPARSE") {
4174  nIndex = PointIndex(nPointIndex);
4175  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_LAT, &px[nIndex],
4176  &py[nIndex]);
4177  nIndex++;
4178  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_LON, &px[nIndex],
4179  &py[nIndex]);
4180  nIndex++;
4181 
4182  // test added to check old test case that didn't solve for radii
4183  if (m_bSolveRadii || m_strSolutionMethod == "SPARSE")
4184  pCamera->GroundMap()->GetdXYdPoint(d_lookB_WRT_RAD, &px[nIndex],
4185  &py[nIndex]);
4186 
4187 // d_lookJ = pBodyRot->J2000Vector(d_lookB_WRT_LAT);
4188 // d_lookC = pInstRot->ReferenceVector(d_lookJ);
4189 //
4190 // px[nIndex] = fl * LowDHigh(lookC,d_lookC,0);
4191 // py[nIndex] = fl * LowDHigh(lookC,d_lookC,1);
4192 // nIndex++;
4193 //
4194 // d_lookJ = pBodyRot->J2000Vector(d_lookB_WRT_LON);
4195 // d_lookC = pInstRot->ReferenceVector(d_lookJ);
4196 //
4197 // px[nIndex] = fl * LowDHigh(lookC,d_lookC,0);
4198 // py[nIndex] = fl * LowDHigh(lookC,d_lookC,1);
4199 // nIndex++;
4200 //
4201 // d_lookJ = pBodyRot->J2000Vector(d_lookB_WRT_RAD);
4202 // d_lookC = pInstRot->ReferenceVector(d_lookJ);
4203 //
4204 // px[nIndex] = fl * LowDHigh(lookC,d_lookC,0);
4205 // py[nIndex] = fl * LowDHigh(lookC,d_lookC,1);
4206 //
4207  }
4208  // right-hand side (measured - computed)
4209  dMeasuredx = measure->GetFocalPlaneMeasuredX();
4210  // dComputedx = lookC[0] * fl / lookC[2];
4211 
4212  dMeasuredy = measure->GetFocalPlaneMeasuredY();
4213  // dComputedy = lookC[1] * fl / lookC[2];
4214 
4215  deltax = dMeasuredx - dComputedx;
4216  deltay = dMeasuredy - dComputedy;
4217 
4218  dObservationSigma = 1.4 * pCamera->PixelPitch();
4219  dObservationWeight = 1.0 / (dObservationSigma * dObservationSigma);
4220  // dObservationWeight = 1.0 / dObservationSigma;
4221 
4222  // test to match old runs
4223  // dObservationWeight = 1.0;
4224 
4225 // std::cout << "yKnowns = ";
4226 // for (int i=0; i<m_dyKnowns.size(); i++)
4227 // std::cout << " " << m_dyKnowns[i] << std::endl;
4228 // std::cout << std::endl;
4229 // std::cout << "deltax and deltay = " << deltax << " " << deltay << " " << dObservationWeight << std::endl;
4230 
4231 
4232 
4233  m_pLsq->AddKnown(m_dxKnowns, deltax, dObservationWeight);
4234  m_pLsq->AddKnown(m_dyKnowns, deltay, dObservationWeight);
4235 
4236  m_Statsx.AddData(deltax);
4237  m_Statsy.AddData(deltay);
4238  }
4239  }
4240 */
4241 
4242 
4253  int BundleAdjust::Triangulation(bool bDoApproximation) {
4254  int nSuccessfullyTriangulated = 0;
4255 
4256  // Loop over all points in control net
4257  // We will triangulate all points, ultimately using this as a rudimentary means of outlier detection.
4258  // if the point is control, we triangulate but don't update the coordinates
4259  int nControlNetPoints = m_pCnet->GetNumPoints();
4260  for (int i = 0; i < nControlNetPoints; i++) {
4261  const ControlPoint *point = m_pCnet->GetPoint(i);
4262 
4263  if (point->IsIgnored())
4264  return nSuccessfullyTriangulated;
4265 
4266  if (bDoApproximation) {
4267  ApproximatePoint_ClosestApproach(*point, i);
4268 // if( !ApproximatePoint_ClosestApproach() )
4269  // mark point somehow to ignore it
4270  }
4271 
4272  // triangulate point
4273  TriangulatePoint(*point);
4274 // if( !TriangulatePoint(point) )
4275 // {
4276 // flag point to ignore
4277 // }
4278 
4279  nSuccessfullyTriangulated++;
4280  }
4281 
4282  return nSuccessfullyTriangulated;
4283  }
4284 
4285 
4295  bool BundleAdjust::TriangulatePoint(const ControlPoint &rPoint) {
4296  return true;
4297  }
4298 
4308  bool BundleAdjust::ApproximatePoint_ClosestApproach(const ControlPoint &rPoint, int nIndex) {
4309  ControlMeasure measure1, measure2;
4310  Camera *pCamera1 = 0;
4311  Camera *pCamera2 = 0;
4312  CameraDistortionMap *pDistortionMap1 = 0;
4313  CameraDistortionMap *pDistortionMap2 = 0;
4314  CameraFocalPlaneMap *pFocalPlaneMap1 = 0;
4315  double BaseVector[3];
4316  double Camera1Position[3]; // note: units are body-fixed in kilometers
4317  double Camera2Position[3]; // note: units are body-fixed in kilometers
4318  double Camera1LookVector[3];
4319  double Camera2LookVector[3];
4320  double Camera1XCamera2[3];
4321  double ClosestPoint1[3];
4322  double ClosestPoint2[3];
4323  double AveragePoint[3];
4324  double d;
4325  double blabla;
4326 
4327  int nClosetApproaches = 0;
4328 
4329 // const char* buf = rPoint.Id().toAscii().data();
4330 
4331  // loop over observations (in Astro Terms "measures")
4332  int nObservations = rPoint.GetNumMeasures();
4333  for (int i = 0; i < nObservations - 1; i++) {
4334  measure1 = *rPoint.GetMeasure(i);
4335  if (measure1.IsIgnored())
4336  continue;
4337 
4338  // get camera and distortion map for observation i
4339  pCamera1 = measure1.Camera();
4340  if (!pCamera1)
4341  continue;
4342 
4343  pDistortionMap1 = pCamera1->DistortionMap();
4344  if (!pDistortionMap1)
4345  continue;
4346 
4347  pFocalPlaneMap1 = pCamera1->FocalPlaneMap();
4348  if (!pFocalPlaneMap1)
4349  continue;
4350 
4351  pCamera1->SetImage(measure1.GetSample(), measure1.GetLine());
4352 
4353  pCamera1->instrumentPosition(Camera1Position);
4354 
4355 // double TCD = pCamera1->targetCenterDistance();
4356 
4357  Camera1LookVector[0] = pDistortionMap1->UndistortedFocalPlaneX();
4358  Camera1LookVector[1] = pDistortionMap1->UndistortedFocalPlaneY();
4359  Camera1LookVector[2] = pDistortionMap1->UndistortedFocalPlaneZ();
4360 
4361  // normalize vector (make into a unit vector)
4362  d = Camera1LookVector[0] * Camera1LookVector[0] +
4363  Camera1LookVector[1] * Camera1LookVector[1] +
4364  Camera1LookVector[2] * Camera1LookVector[2];
4365 
4366  if (d <= 0.0)
4367  return false;
4368 
4369  d = sqrt(d);
4370 
4371  Camera1LookVector[0] /= d;
4372  Camera1LookVector[1] /= d;
4373  Camera1LookVector[2] /= d;
4374 
4375  // rotate into J2000
4376  std::vector<double> dummy1(3);
4377  dummy1[0] = Camera1LookVector[0];
4378  dummy1[1] = Camera1LookVector[1];
4379  dummy1[2] = Camera1LookVector[2];
4380  dummy1 = pCamera1->instrumentRotation()->J2000Vector(dummy1);
4381 
4382  // rotate into body-fixed
4383  dummy1 = pCamera1->bodyRotation()->ReferenceVector(dummy1);
4384 
4385  Camera1LookVector[0] = dummy1[0];
4386  Camera1LookVector[1] = dummy1[1];
4387  Camera1LookVector[2] = dummy1[2];
4388 
4389  // Get the look vector in the camera frame and the instrument rotation
4390 // lookJ = cam->bodyRotation()->J2000Vector( lookB );
4391 // SpiceRotation *instRot = cam->instrumentRotation();
4392 // lookC = instRot->ReferenceVector( lookJ);
4393 
4394  for (int j = i + 1; j < nObservations; j++) {
4395  measure2 = *rPoint.GetMeasure(j);
4396  if (measure2.IsIgnored())
4397  continue;
4398 
4399  pCamera2 = measure2.Camera();
4400  if (!pCamera2)
4401  continue;
4402 
4403  pDistortionMap2 = pCamera2->DistortionMap();
4404  if (!pDistortionMap2)
4405  continue;
4406 
4407  pCamera2->SetImage(measure2.GetSample(), measure2.GetLine());
4408 
4409  pCamera2->instrumentPosition(Camera2Position);
4410 
4411  Camera2LookVector[0] = pDistortionMap2->UndistortedFocalPlaneX();
4412  Camera2LookVector[1] = pDistortionMap2->UndistortedFocalPlaneY();
4413  Camera2LookVector[2] = pDistortionMap2->UndistortedFocalPlaneZ();
4414 
4415  // normalize vector (make into a unit vector)
4416  d = Camera2LookVector[0] * Camera2LookVector[0] +
4417  Camera2LookVector[1] * Camera2LookVector[1] +
4418  Camera2LookVector[2] * Camera2LookVector[2];
4419 
4420  if (d <= 0.0)
4421  return false;
4422 
4423  d = sqrt(d);
4424 
4425  Camera2LookVector[0] /= d;
4426  Camera2LookVector[1] /= d;
4427  Camera2LookVector[2] /= d;
4428 
4429  // rotate into J2000
4430  dummy1[0] = Camera2LookVector[0];
4431  dummy1[1] = Camera2LookVector[1];
4432  dummy1[2] = Camera2LookVector[2];
4433  dummy1 = pCamera2->instrumentRotation()->J2000Vector(dummy1);
4434 
4435  // rotate into body-fixed
4436  dummy1 = pCamera2->bodyRotation()->ReferenceVector(dummy1);
4437 
4438  Camera2LookVector[0] = dummy1[0];
4439  Camera2LookVector[1] = dummy1[1];
4440  Camera2LookVector[2] = dummy1[2];
4441 
4442  // base vector between Camera1 and Camera2
4443  BaseVector[0] = Camera2Position[0] - Camera1Position[0];
4444  BaseVector[1] = Camera2Position[1] - Camera1Position[1];
4445  BaseVector[2] = Camera2Position[2] - Camera1Position[2];
4446 
4447  // cross product of Camera1LookVector and Camera2LookVector (SPICE routine)
4448  vcrss_c(Camera1LookVector, Camera2LookVector, Camera1XCamera2);
4449 
4450  // magnitude^^2 of cross product
4451  double dmag2 = Camera1XCamera2[0] * Camera1XCamera2[0] +
4452  Camera1XCamera2[1] * Camera1XCamera2[1] +
4453  Camera1XCamera2[2] * Camera1XCamera2[2];
4454 
4455  // if dmag2 == 0 (or smaller than some epsilon?), then lines are parallel and we're done
4456  if (dmag2 == 0.0)
4457  return false;
4458 
4459  SpiceDouble dMatrix[3][3];
4460  dMatrix[0][0] = BaseVector[0];
4461  dMatrix[0][1] = BaseVector[1];
4462  dMatrix[0][2] = BaseVector[2];
4463  dMatrix[1][0] = Camera2LookVector[0];
4464  dMatrix[1][1] = Camera2LookVector[1];
4465  dMatrix[1][2] = Camera2LookVector[2];
4466  dMatrix[2][0] = Camera1XCamera2[0];
4467  dMatrix[2][1] = Camera1XCamera2[1];
4468  dMatrix[2][2] = Camera1XCamera2[2];
4469 
4470  blabla = (double)det_c(dMatrix);
4471 
4472  double t1 = blabla / dmag2;
4473 
4474 // printf("blabla = %lf dmag2 = %lf t1 = %lf\n",blabla,dmag2,t1);
4475 
4476  dMatrix[1][0] = Camera1LookVector[0];
4477  dMatrix[1][1] = Camera1LookVector[1];
4478  dMatrix[1][2] = Camera1LookVector[2];
4479 
4480  blabla = (double)det_c(dMatrix);
4481 
4482  double t2 = blabla / dmag2;
4483 
4484 // printf("blabla = %lf dmag2 = %lf t1 = %lf\n",blabla,dmag2,t2);
4485 // printf("i=%d j=%d\n",i,j);
4486 
4487 // printf("look1: %20.10lf %20.10lf %20.10lf\n",Camera1LookVector[0],Camera1LookVector[1],Camera1LookVector[2]);
4488 // printf("look2: %20.10lf %20.10lf %20.10lf\n",Camera2LookVector[0],Camera2LookVector[1],Camera2LookVector[2]);
4489 
4490  ClosestPoint1[0] = Camera1Position[0] + t1 * Camera1LookVector[0];
4491  ClosestPoint1[1] = Camera1Position[1] + t1 * Camera1LookVector[1];
4492  ClosestPoint1[2] = Camera1Position[2] + t1 * Camera1LookVector[2];
4493 
4494  ClosestPoint2[0] = Camera2Position[0] + t2 * Camera2LookVector[0];
4495  ClosestPoint2[1] = Camera2Position[1] + t2 * Camera2LookVector[1];
4496  ClosestPoint2[2] = Camera2Position[2] + t2 * Camera2LookVector[2];
4497 
4498  AveragePoint[0] = (ClosestPoint1[0] + ClosestPoint2[0]) * 0.5;
4499  AveragePoint[1] = (ClosestPoint1[1] + ClosestPoint2[1]) * 0.5;
4500  AveragePoint[2] = (ClosestPoint1[2] + ClosestPoint2[2]) * 0.5;
4501 
4502  nClosetApproaches++;
4503  }
4504  }
4505 
4506 // AveragePoint[0] /= nClosetApproaches;
4507 // AveragePoint[1] /= nClosetApproaches;
4508 // AveragePoint[2] /= nClosetApproaches;
4509 
4510  // convert from body-fixed XYZ to lat,long,radius
4511 // SpiceDouble rectan[3];
4512 // rectan[0] = AveragePoint[0];
4513 // rectan[1] = AveragePoint[1];
4514 // rectan[2] = AveragePoint[2];
4515 
4516  SpiceDouble lat, lon, rad;
4517  reclat_c(AveragePoint, &rad, &lon, &lat);
4518 
4519 // double avglat = rPoint.UniversalLatitude();
4520 // double avglon = rPoint.UniversalLongitude();
4521 // double avgrad = rPoint.Radius();
4522 
4523  // set the apriori control net value to the closest approach version
4524  m_pCnet->GetPoint(nIndex)->SetAdjustedSurfacePoint(
4525  SurfacePoint(
4526  Latitude(lat, Angle::Radians),
4527  Longitude(lon, Angle::Radians),
4528  Distance(rad, Distance::Kilometers)));
4529 
4530  // Compute fixed point in body-fixed coordinates
4531  double pB[3];
4532  latrec_c((double) rPoint.GetAdjustedSurfacePoint().GetLocalRadius().kilometers(),
4533  (double) rPoint.GetAdjustedSurfacePoint().GetLongitude().radians(),
4534  (double) rPoint.GetAdjustedSurfacePoint().GetLatitude().radians(),
4535  pB);
4536 
4537 // printf("%s: %lf %lf %lf\n",rPoint.Id().toAscii().data(), AveragePoint[0],AveragePoint[1],AveragePoint[2]);
4538 // printf(" %lf %lf %lf\n", avglat,avglon,avgrad);
4539 // printf(" %lf %lf %lf\n", lat,lon,rad);
4540 // printf(" %lf %lf %lf\n",pB[0],pB[1],pB[2]);
4541 
4542  return true;
4543  }
4544 
4545 
4549  void BundleAdjust::applyParameterCorrections() {
4550  if ( m_decompositionMethod == CHOLMOD )
4551  return applyParameterCorrections_CHOLMOD();
4552  else
4553  return applyParameterCorrections_SPECIALK();
4554  }
4555 
4556 
4560  void BundleAdjust::applyParameterCorrections_CHOLMOD() {
4561 // std::cout << "image corrections: " << m_Image_Corrections << std::endl;
4562 // std::cout << " image solution: " << m_Image_Solution << std::endl;
4563 
4564  int index;
4565  int currentindex = -1;
4566  bool bsameindex = false;
4567 
4568  // Update selected spice for each image
4569  int nImages = Images();
4570  for (int i = 0; i < nImages; i++) {
4571 
4572  if ( m_nHeldImages > 0 )
4573  if ((m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i))))
4574  continue;
4575 
4576  Camera *pCamera = m_pCnet->Camera(i);
4577  index = ImageIndex(i);
4578  if( index == currentindex )
4579  bsameindex = true;
4580  else
4581  bsameindex = false;
4582 
4583  currentindex = index;
4584 
4585  if (m_spacecraftPositionSolveType != Nothing) {
4586  SpicePosition *pInstPos = pCamera->instrumentPosition();
4587  std::vector<double> coefX(m_nNumberCamPosCoefSolved),
4588  coefY(m_nNumberCamPosCoefSolved),
4589  coefZ(m_nNumberCamPosCoefSolved);
4590  pInstPos->GetPolynomial(coefX, coefY, coefZ);
4591 
4592 // printf("X0:%20.10lf X1:%20.10lf X2:%20.10lf\n",abcX[0],abcX[1],abcX[2]);
4593 
4594  // Update the X coordinate coefficient(s) and sum parameter correction
4595  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
4596  coefX[icoef] += m_Image_Solution(index);
4597  if ( !bsameindex )
4598  m_Image_Corrections(index) += m_Image_Solution(index);
4599  index++;
4600  }
4601 
4602  // Update the Y coordinate coefficient(s)
4603  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
4604  coefY[icoef] += m_Image_Solution(index);
4605  if ( !bsameindex )
4606  m_Image_Corrections(index) += m_Image_Solution(index);
4607  index++;
4608  }
4609 
4610  // Update the Z coordinate coefficient(s)
4611  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
4612  coefZ[icoef] += m_Image_Solution(index);
4613  if ( !bsameindex )
4614  m_Image_Corrections(index) += m_Image_Solution(index);
4615  index++;
4616  }
4617 
4618  pInstPos->SetPolynomial(coefX, coefY, coefZ, m_nPositionType);
4619  }
4620 
4621  if (m_cmatrixSolveType != None) {
4622  SpiceRotation *pInstRot = pCamera->instrumentRotation();
4623  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved),
4624  coefDEC(m_nNumberCamAngleCoefSolved),
4625  coefTWI(m_nNumberCamAngleCoefSolved);
4626  pInstRot->GetPolynomial(coefRA, coefDEC, coefTWI);
4627 
4628  // Update right ascension coefficient(s)
4629  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
4630  coefRA[icoef] += m_Image_Solution(index);
4631  if ( !bsameindex )
4632  m_Image_Corrections(index) += m_Image_Solution(index);
4633  index++;
4634  }
4635 
4636  // Update declination coefficient(s)
4637  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
4638  coefDEC[icoef] += m_Image_Solution(index);
4639  if ( !bsameindex )
4640  m_Image_Corrections(index) += m_Image_Solution(index);
4641  index++;
4642  }
4643 
4644  if (m_bSolveTwist) {
4645  // Update twist coefficient(s)
4646  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
4647  coefTWI[icoef] += m_Image_Solution(index);
4648  if ( !bsameindex )
4649  m_Image_Corrections(index) += m_Image_Solution(index);
4650  index++;
4651  }
4652  }
4653 
4654  pInstRot->SetPolynomial(coefRA, coefDEC, coefTWI, m_nPointingType);
4655  }
4656  }
4657 
4658  // Update lat/lon for each control point
4659  double dLatCorr, dLongCorr, dRadCorr;
4660  int nPointIndex = 0;
4661  int nObjectPoints = m_pCnet->GetNumPoints();
4662  for (int i = 0; i < nObjectPoints; i++) {
4663  ControlPoint *point = m_pCnet->GetPoint(i);
4664  if (point->IsIgnored())
4665  continue;
4666 
4667  if( point->IsRejected() ) {
4668  nPointIndex++;
4669  continue;
4670  }
4671 
4672  // get NIC, Q, and correction vector for this point
4673  bounded_vector<double, 3>& NIC = m_NICs[nPointIndex];
4674  SparseBlockRowMatrix& Q = m_Qs_CHOLMOD[nPointIndex];
4675  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
4676 
4677 // printf("Q\n");
4678 // std::cout << Q << std::endl;
4679 
4680 // printf("NIC\n");
4681 // std::cout << NIC << std::endl;
4682 
4683 // std::cout << m_Image_Solution << std::endl;
4684 
4685  // subtract product of Q and nj from NIC
4686 // NIC -= prod(Q, m_Image_Solution);
4687  product_AV(-1.0, NIC, Q, m_Image_Solution);
4688 
4689  // get point parameter corrections
4690  dLatCorr = NIC(0);
4691  dLongCorr = NIC(1);
4692  dRadCorr = NIC(2);
4693 
4694 // printf("Point %s Corrections\n Latitude: %20.10lf\nLongitude: %20.10lf\n Radius: %20.10lf\n",point->GetId().toAscii().data(),dLatCorr, dLongCorr, dRadCorr);
4695 // std::cout <<"Point " << point->GetId().toAscii().data() << " Corrections\n" << "Latitude: " << dLatCorr << std::endl << "Longitude: " << dLongCorr << std::endl << "Radius: " << dRadCorr << std::endl;
4696 
4697  double dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
4698  double dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
4699  double dRad = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
4700 
4701  dLat += RAD2DEG * dLatCorr;
4702  dLon += RAD2DEG * dLongCorr;
4703 
4704  // Make sure updated values are still in valid range.
4705  // TODO What is the valid lon range?
4706  if (dLat < -90.0) {
4707  dLat = -180.0 - dLat;
4708  dLon = dLon + 180.0;
4709  }
4710  if (dLat > 90.0) {
4711  dLat = 180.0 - dLat;
4712  dLon = dLon + 180.0;
4713  }
4714  while (dLon > 360.0) dLon = dLon - 360.0;
4715  while (dLon < 0.0) dLon = dLon + 360.0;
4716 
4717  dRad += 1000.*dRadCorr;
4718 
4719 // std::cout << corrections << std::endl;
4720 
4721  // sum and save corrections
4722  corrections(0) += dLatCorr;
4723  corrections(1) += dLongCorr;
4724  corrections(2) += dRadCorr;
4725 
4726 // std::cout << corrections << std::endl;
4727 
4728  SurfacePoint surfacepoint = point->GetAdjustedSurfacePoint();
4729 
4730  surfacepoint.SetSphericalCoordinates(Latitude(dLat, Angle::Degrees),
4731  Longitude(dLon, Angle::Degrees),
4732  Distance(dRad, Distance::Meters));
4733 
4734  point->SetAdjustedSurfacePoint(surfacepoint);
4735 
4736  nPointIndex++;
4737 
4738  // testing
4739  // Compute fixed point in body-fixed coordinates
4740 // double pB[3];
4741 // latrec_c( dRad * 0.001,
4742 // (dLon * DEG2RAD),
4743 // (dLat * DEG2RAD),
4744 // pB);
4745 // printf("%s %lf %lf %lf\n",point->Id().toAscii().data(),pB[0],pB[1],pB[2]);
4746  } // end loop over point corrections
4747  }
4748 
4749 
4753  void BundleAdjust::applyParameterCorrections_SPECIALK() {
4754 // std::cout << "image corrections: " << m_Image_Corrections << std::endl;
4755 // std::cout << " image solution: " << m_Image_Solution << std::endl;
4756 
4757  int index;
4758  int currentindex = -1;
4759  bool bsameindex = false;
4760 
4761  // Update selected spice for each image
4762  int nImages = Images();
4763  for (int i = 0; i < nImages; i++) {
4764 
4765  if ( m_nHeldImages > 0 )
4766  if ((m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i))))
4767  continue;
4768 
4769  Camera *pCamera = m_pCnet->Camera(i);
4770  index = ImageIndex(i);
4771  if( index == currentindex )
4772  bsameindex = true;
4773  else
4774  bsameindex = false;
4775 
4776  currentindex = index;
4777 
4778  if (m_spacecraftPositionSolveType != Nothing) {
4779  SpicePosition *pInstPos = pCamera->instrumentPosition();
4780  std::vector<double> coefX(m_nNumberCamPosCoefSolved),
4781  coefY(m_nNumberCamPosCoefSolved),
4782  coefZ(m_nNumberCamPosCoefSolved);
4783  pInstPos->GetPolynomial(coefX, coefY, coefZ);
4784 
4785 // printf("X0:%20.10lf X1:%20.10lf X2:%20.10lf\n",abcX[0],abcX[1],abcX[2]);
4786 
4787  // Update the X coordinate coefficient(s) and sum parameter correction
4788  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
4789  coefX[icoef] += m_Image_Solution(index);
4790  if ( !bsameindex )
4791  m_Image_Corrections(index) += m_Image_Solution(index);
4792  index++;
4793  }
4794 
4795  // Update the Y coordinate coefficient(s)
4796  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
4797  coefY[icoef] += m_Image_Solution(index);
4798  if ( !bsameindex )
4799  m_Image_Corrections(index) += m_Image_Solution(index);
4800  index++;
4801  }
4802 
4803  // Update the Z coordinate coefficient(s)
4804  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
4805  coefZ[icoef] += m_Image_Solution(index);
4806  if ( !bsameindex )
4807  m_Image_Corrections(index) += m_Image_Solution(index);
4808  index++;
4809  }
4810 
4811  pInstPos->SetPolynomial(coefX, coefY, coefZ, m_nPositionType);
4812  }
4813 
4814  if (m_cmatrixSolveType != None) {
4815  SpiceRotation *pInstRot = pCamera->instrumentRotation();
4816  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved),
4817  coefDEC(m_nNumberCamAngleCoefSolved),
4818  coefTWI(m_nNumberCamAngleCoefSolved);
4819  pInstRot->GetPolynomial(coefRA, coefDEC, coefTWI);
4820 
4821  // Update right ascension coefficient(s)
4822  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
4823  coefRA[icoef] += m_Image_Solution(index);
4824  if ( !bsameindex )
4825  m_Image_Corrections(index) += m_Image_Solution(index);
4826  index++;
4827  }
4828 
4829  // Update declination coefficient(s)
4830  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
4831  coefDEC[icoef] += m_Image_Solution(index);
4832  if ( !bsameindex )
4833  m_Image_Corrections(index) += m_Image_Solution(index);
4834  index++;
4835  }
4836 
4837  if (m_bSolveTwist) {
4838  // Update twist coefficient(s)
4839  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
4840  coefTWI[icoef] += m_Image_Solution(index);
4841  if ( !bsameindex )
4842  m_Image_Corrections(index) += m_Image_Solution(index);
4843  index++;
4844  }
4845  }
4846 
4847  pInstRot->SetPolynomial(coefRA, coefDEC, coefTWI, m_nPointingType);
4848  }
4849  }
4850 
4851  // Update lat/lon for each control point
4852  double dLatCorr, dLongCorr, dRadCorr;
4853  int nPointIndex = 0;
4854  int nObjectPoints = m_pCnet->GetNumPoints();
4855  for (int i = 0; i < nObjectPoints; i++) {
4856  ControlPoint *point = m_pCnet->GetPoint(i);
4857  if (point->IsIgnored())
4858  continue;
4859 
4860  if( point->IsRejected() ) {
4861  nPointIndex++;
4862  continue;
4863  }
4864 
4865  // get NIC, Q, and correction vector for this point
4866  bounded_vector<double, 3>& NIC = m_NICs[nPointIndex];
4867  compressed_matrix<double>& Q = m_Qs_SPECIALK[nPointIndex];
4868  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
4869 
4870 // printf("Q\n");
4871 // std::cout << Q << std::endl;
4872 
4873 // printf("NIC\n");
4874 // std::cout << NIC << std::endl;
4875 
4876 // std::cout << m_Image_Solution << std::endl;
4877 
4878  // subtract product of Q and nj from NIC
4879  NIC -= prod(Q, m_Image_Solution);
4880 
4881  // get point parameter corrections
4882  dLatCorr = NIC(0);
4883  dLongCorr = NIC(1);
4884  dRadCorr = NIC(2);
4885 
4886 // printf("Point %s Corrections\n Latitude: %20.10lf\nLongitude: %20.10lf\n Radius: %20.10lf\n",point->GetId().toAscii().data(),dLatCorr, dLongCorr, dRadCorr);
4887 // std::cout <<"Point " << point->GetId().toAscii().data() << " Corrections\n" << "Latitude: " << dLatCorr << std::endl << "Longitude: " << dLongCorr << std::endl << "Radius: " << dRadCorr << std::endl;
4888 
4889  double dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
4890  double dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
4891  double dRad = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
4892 
4893  dLat += RAD2DEG * dLatCorr;
4894  dLon += RAD2DEG * dLongCorr;
4895 
4896  // Make sure updated values are still in valid range.
4897  // TODO What is the valid lon range?
4898  if (dLat < -90.0) {
4899  dLat = -180.0 - dLat;
4900  dLon = dLon + 180.0;
4901  }
4902  if (dLat > 90.0) {
4903  dLat = 180.0 - dLat;
4904  dLon = dLon + 180.0;
4905  }
4906  while (dLon > 360.0) dLon = dLon - 360.0;
4907  while (dLon < 0.0) dLon = dLon + 360.0;
4908 
4909  dRad += 1000.*dRadCorr;
4910 
4911 // std::cout << corrections << std::endl;
4912 
4913  // sum and save corrections
4914  corrections(0) += dLatCorr;
4915  corrections(1) += dLongCorr;
4916  corrections(2) += dRadCorr;
4917 
4918 // std::cout << corrections << std::endl;
4919 
4920  SurfacePoint surfacepoint = point->GetAdjustedSurfacePoint();
4921 
4922  surfacepoint.SetSphericalCoordinates(Latitude(dLat, Angle::Degrees),
4923  Longitude(dLon, Angle::Degrees),
4924  Distance(dRad, Distance::Meters));
4925 
4926  point->SetAdjustedSurfacePoint(surfacepoint);
4927 
4928  nPointIndex++;
4929 
4930  // testing
4931  // Compute fixed point in body-fixed coordinates
4932 // double pB[3];
4933 // latrec_c( dRad * 0.001,
4934 // (dLon * DEG2RAD),
4935 // (dLat * DEG2RAD),
4936 // pB);
4937 // printf("%s %lf %lf %lf\n",point->Id().toAscii().data(),pB[0],pB[1],pB[2]);
4938  } // end loop over point corrections
4939  }
4940 
4941 
4951  double BundleAdjust::ComputeResiduals() {
4952  double vtpv = 0.0;
4953  double vtpv_control = 0.0;
4954  double vtpv_image = 0.0;
4955  double dWeight;
4956  double v, vx, vy;
4957 
4958  // clear residual stats vectors
4959  m_Statsrx.Reset();
4960  m_Statsry.Reset();
4961  m_Statsrxy.Reset();
4962 
4963 // m_drms_rx = sqrt(m_Statsrx.SumSquare()/(m_nObservations/2));
4964 // m_drms_ry = sqrt(m_Statsry.SumSquare()/(m_nObservations/2));
4965 // m_drms_rxy = sqrt(m_Statsrxy.SumSquare()/m_nObservations);
4966 
4967  // vtpv for image coordinates
4968  int nObjectPoints = m_pCnet->GetNumPoints();
4969  for (int i = 0; i < nObjectPoints; i++) {
4970  ControlPoint *point = m_pCnet->GetPoint(i);
4971  if (point->IsIgnored())
4972  continue;
4973 
4974  point->ComputeResiduals();
4975 
4976  int nMeasures = point->GetNumMeasures();
4977  for (int j = 0; j < nMeasures; j++) {
4978  const ControlMeasure *measure = point->GetMeasure(j);
4979  if (measure->IsIgnored())
4980  continue;
4981 
4982  dWeight = 1.4 * (measure->Camera())->PixelPitch();
4983  dWeight = 1.0 / dWeight;
4984  dWeight *= dWeight;
4985 
4986  vx = measure->GetFocalPlaneMeasuredX() - measure->GetFocalPlaneComputedX();
4987  vy = measure->GetFocalPlaneMeasuredY() - measure->GetFocalPlaneComputedY();
4988 
4989  // std::cout << "vx vy" << vx << " " << vy << std::endl;
4990 
4991  // if rejected, don't include in statistics
4992  if (measure->IsRejected())
4993  continue;
4994 
4995  m_Statsrx.AddData(vx);
4996  m_Statsry.AddData(vy);
4997  m_Statsrxy.AddData(vx);
4998  m_Statsrxy.AddData(vy);
4999 
5000 // printf("Point: %s rx: %20.10lf ry: %20.10lf\n",point->Id().toAscii().data(),rx,ry);
5001 
5002  vtpv += vx * vx * dWeight + vy * vy * dWeight;
5003  }
5004  }
5005 
5006 // std::cout << "vtpv image = " << vtpv << std::endl;
5007 // std::cout << "dWeight = " << dWeight << std::endl;
5008 
5009  // add vtpv from constrained 3D points
5010  int nPointIndex = 0;
5011  for (int i = 0; i < nObjectPoints; i++) {
5012  const ControlPoint *point = m_pCnet->GetPoint(i);
5013  if ( point->IsIgnored() )
5014  continue;
5015 
5016  // get weight and correction vector for this point
5017  bounded_vector<double, 3>& weights = m_Point_Weights[nPointIndex];
5018  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
5019 
5020  //printf("Point: %s PointIndex: %d Loop(i): %d\n",point->GetId().toAscii().data(),nPointIndex,i);
5021  //std::cout << weights << std::endl;
5022  //std::cout << corrections << std::endl;
5023 
5024  if( weights[0] > 0.0 )
5025  vtpv_control += corrections[0] * corrections[0] * weights[0];
5026  if( weights[1] > 0.0 )
5027  vtpv_control += corrections[1] * corrections[1] * weights[1];
5028  if( weights[2] > 0.0 )
5029  vtpv_control += corrections[2] *corrections[2] * weights[2];
5030 
5031  nPointIndex++;
5032  }
5033 
5034 // std::cout << "vtpv control = " << vtpv_control << std::endl;
5035 
5036  // add vtpv from constrained image parameters
5037  int n = 0;
5038  do {
5039  for (int j = 0; j < m_nNumImagePartials; j++) {
5040  if (m_dImageParameterWeights[j] > 0.0) {
5041  v = m_Image_Corrections[n];
5042  vtpv_image += v * v * m_dImageParameterWeights[j];
5043  }
5044 
5045  n++;
5046  }
5047 
5048  }
5049  while (n < m_nRank);
5050 
5051 // std::cout << "vtpv_image = " << vtpv_image << std::endl;
5052 
5053  vtpv = vtpv + vtpv_control + vtpv_image;
5054 
5055  // Compute rms for all image coordinate residuals
5056  // separately for x, y, then x and y together
5057  m_drms_rx = m_Statsrx.Rms();
5058  m_drms_ry = m_Statsry.Rms();
5059  m_drms_rxy = m_Statsrxy.Rms();
5060 
5061  return vtpv;
5062  }
5063 
5064 
5069  bool BundleAdjust::WrapUp() {
5070  // compute residuals in pixels
5071 
5072  // vtpv for image coordinates
5073  int nObjectPoints = m_pCnet->GetNumPoints();
5074  for (int i = 0; i < nObjectPoints; i++) {
5075  ControlPoint *point = m_pCnet->GetPoint(i);
5076  if (point->IsIgnored())
5077  continue;
5078 
5079  point->ComputeResiduals();
5080  }
5081 
5082  ComputeBundleStatistics();
5083 
5084  return true;
5085  }
5086 
5087 
5092  bool BundleAdjust::ComputeBundleStatistics() {
5093  int nImages = Images();
5094  int nMeasures;
5095  int nImageIndex;
5096  double vsample;
5097  double vline;
5098 
5099  m_rmsImageSampleResiduals.resize(nImages);
5100  m_rmsImageLineResiduals.resize(nImages);
5101  m_rmsImageResiduals.resize(nImages);
5102 
5103  // load image coordinate residuals into statistics vectors
5104  int nObservation = 0;
5105  int nObjectPoints = m_pCnet->GetNumPoints();
5106  for (int i = 0; i < nObjectPoints; i++) {
5107 
5108  const ControlPoint *point = m_pCnet->GetPoint(i);
5109  if ( point->IsIgnored() )
5110  continue;
5111 
5112  if ( point->IsRejected() )
5113  continue;
5114 
5115  nMeasures = point->GetNumMeasures();
5116  for (int j = 0; j < nMeasures; j++) {
5117 
5118  const ControlMeasure *measure = point->GetMeasure(j);
5119  if ( measure->IsIgnored() )
5120  continue;
5121 
5122  if ( measure->IsRejected() )
5123  continue;
5124 
5125  vsample = fabs(measure->GetSampleResidual());
5126  vline = fabs(measure->GetLineResidual());
5127 
5128  // Determine the image index
5129  nImageIndex = m_pSnList->serialNumberIndex(measure->GetCubeSerialNumber());
5130 
5131  // add residuals to pertinent vector
5132  m_rmsImageSampleResiduals[nImageIndex].AddData(vsample);
5133  m_rmsImageLineResiduals[nImageIndex].AddData(vline);
5134  m_rmsImageResiduals[nImageIndex].AddData(vline);
5135  m_rmsImageResiduals[nImageIndex].AddData(vsample);
5136 
5137  nObservation++;
5138  }
5139  }
5140 
5141  if( m_bErrorPropagation )
5142  {
5143  m_rmsImageXSigmas.resize(nImages);
5144  m_rmsImageYSigmas.resize(nImages);
5145  m_rmsImageZSigmas.resize(nImages);
5146  m_rmsImageRASigmas.resize(nImages);
5147  m_rmsImageDECSigmas.resize(nImages);
5148  m_rmsImageTWISTSigmas.resize(nImages);
5149 
5150  // compute stats for point sigmas
5151  Statistics sigmaLatitude;
5152  Statistics sigmaLongitude;
5153  Statistics sigmaRadius;
5154 
5155  double dSigmaLat, dSigmaLong, dSigmaRadius;
5156 
5157  int nPoints = m_pCnet->GetNumPoints();
5158  for ( int i = 0; i < nPoints; i++ ) {
5159 
5160  const ControlPoint *point = m_pCnet->GetPoint(i);
5161  if ( point->IsIgnored() )
5162  continue;
5163 
5164  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
5165  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
5166  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
5167 
5168  sigmaLatitude.AddData(dSigmaLat);
5169  sigmaLongitude.AddData(dSigmaLong);
5170  sigmaRadius.AddData(dSigmaRadius);
5171 
5172  if ( i > 0 ) {
5173  if ( dSigmaLat > m_dmaxSigmaLatitude ) {
5174  m_dmaxSigmaLatitude = dSigmaLat;
5175  m_idMaxSigmaLatitude = point->GetId();
5176  }
5177  if ( dSigmaLong > m_dmaxSigmaLongitude ) {
5178  m_dmaxSigmaLongitude = dSigmaLong;
5179  m_idMaxSigmaLongitude = point->GetId();
5180  }
5181  if ( m_bSolveRadii ) {
5182  if ( dSigmaRadius > m_dmaxSigmaRadius ) {
5183  m_dmaxSigmaRadius = dSigmaRadius;
5184  m_idMaxSigmaRadius = point->GetId();
5185  }
5186  }
5187  if ( dSigmaLat < m_dminSigmaLatitude ) {
5188  m_dminSigmaLatitude = dSigmaLat;
5189  m_idMinSigmaLatitude = point->GetId();
5190  }
5191  if ( dSigmaLong < m_dminSigmaLongitude ) {
5192  m_dminSigmaLongitude = dSigmaLong;
5193  m_idMinSigmaLongitude = point->GetId();
5194  }
5195  if ( m_bSolveRadii ) {
5196  if ( dSigmaRadius < m_dminSigmaRadius ) {
5197  m_dminSigmaRadius = dSigmaRadius;
5198  m_idMinSigmaRadius = point->GetId();
5199  }
5200  }
5201  }
5202  else {
5203  m_dmaxSigmaLatitude = dSigmaLat;
5204  m_dmaxSigmaLongitude = dSigmaLong;
5205 
5206  m_dminSigmaLatitude = dSigmaLat;
5207  m_dminSigmaLongitude = dSigmaLong;
5208 
5209  if ( m_bSolveRadii ) {
5210  m_dmaxSigmaRadius = dSigmaRadius;
5211  m_dminSigmaRadius = dSigmaRadius;
5212  }
5213  }
5214  }
5215 
5216  m_drms_sigmaLat = sigmaLatitude.Rms();
5217  m_drms_sigmaLon = sigmaLongitude.Rms();
5218  m_drms_sigmaRad = sigmaRadius.Rms();
5219  }
5220 
5221  return true;
5222  }
5223 
5224 
5229  bool BundleAdjust::ComputeRejectionLimit() {
5230  double vx, vy;
5231 
5232  int nResiduals = m_nObservations / 2;
5233 
5234 // std::cout << "total observations: " << m_nObservations << std::endl;
5235 // std::cout << "rejected observations: " << m_nRejectedObservations << std::endl;
5236 // std::cout << "good observations: " << m_nObservations-m_nRejectedObservations << std::endl;
5237 
5238  std::vector<double> resvectors;
5239 
5240  resvectors.resize(nResiduals);
5241 
5242  // load magnitude (squared) of residual vector
5243  int nObservation = 0;
5244  int nObjectPoints = m_pCnet->GetNumPoints();
5245  for (int i = 0; i < nObjectPoints; i++) {
5246 
5247  const ControlPoint *point = m_pCnet->GetPoint(i);
5248  if ( point->IsIgnored() )
5249  continue;
5250 
5251  if ( point->IsRejected() )
5252  continue;
5253 
5254  int nMeasures = point->GetNumMeasures();
5255  for (int j = 0; j < nMeasures; j++) {
5256 
5257  const ControlMeasure *measure = point->GetMeasure(j);
5258  if ( measure->IsIgnored() )
5259  continue;
5260 
5261  if ( measure->IsRejected() )
5262  continue;
5263 
5264  vx = measure->GetSampleResidual();
5265  vy = measure->GetLineResidual();
5266 
5267  resvectors[nObservation] = sqrt(vx*vx + vy*vy);
5268 
5269  nObservation++;
5270  }
5271  }
5272 
5273 // std::cout << "x residuals\n" << x_residuals << std::endl;
5274 // std::cout << "y_residuals\n" << y_residuals << std::endl;
5275 
5276  // sort vectors
5277  std::sort(resvectors.begin(), resvectors.end());
5278 
5279 // std::cout << "residuals range: \n" << resvectors[0] << resvectors[nResiduals-1] << std::endl;
5280 
5281 // std::cout << "x residuals sorted\n" << x_residuals << std::endl;
5282 // std::cout << "y_residuals sorted\n" << y_residuals << std::endl;
5283 
5284  double median;
5285  double mediandev;
5286  double mad;
5287 
5288  int nmidpoint = nResiduals / 2;
5289 
5290  if ( nResiduals % 2 == 0 )
5291  median = (resvectors[nmidpoint-1] + resvectors[nmidpoint]) / 2;
5292  else
5293  median = resvectors[nmidpoint];
5294 
5295 // std::cout << "median: " << median << std::endl;
5296 
5297  // compute M.A.D.
5298  for (int i = 0; i < nResiduals; i++)
5299  resvectors[i] = fabs(resvectors[i] - median);
5300 
5301  std::sort(resvectors.begin(), resvectors.end());
5302 
5303 // std::cout << "residuals range: \n" << resvectors[0] << resvectors[nResiduals-1] << std::endl;
5304 
5305  if ( nResiduals % 2 == 0 )
5306  mediandev = (resvectors[nmidpoint-1] + resvectors[nmidpoint]) / 2;
5307  else
5308  mediandev = resvectors[nmidpoint];
5309 
5310  std::cout << "median deviation: " << mediandev << std::endl;
5311 
5312  mad = 1.4826 * mediandev;
5313 
5314  std::cout << "mad: " << mad << std::endl;
5315 
5316 // double dLow = median - m_dRejectionMultiplier * mad;
5317 // double dHigh = median + m_dRejectionMultiplier * mad;
5318 
5319 // std::cout << "reject range: \n" << dLow << " " << dHigh << std::endl;
5320 // std::cout << "Rejection multipler: \n" << m_dRejectionMultiplier << std::endl;
5321 
5322  m_dRejectionLimit = median + m_dRejectionMultiplier * mad;
5323 
5324  std::cout << "Rejection Limit: " << m_dRejectionLimit << std::endl;
5325 
5326  return true;
5327  }
5328 
5329 
5334  bool BundleAdjust::FlagOutliers() {
5335  double vx, vy;
5336  int nRejected;
5337  int ntotalrejected = 0;
5338 
5339  int nIndexMaxResidual;
5340  double dMaxResidual;
5341  double dSumSquares;
5342  double dUsedRejectionLimit = m_dRejectionLimit;
5343 
5344 // if ( m_dRejectionLimit < 0.05 )
5345 // dUsedRejectionLimit = 0.14;
5346  // dUsedRejectionLimit = 0.05;
5347 
5348  int nComingBack = 0;
5349 
5350  int nObjectPoints = m_pCnet->GetNumPoints();
5351  for (int i = 0; i < nObjectPoints; i++) {
5352  ControlPoint *point = m_pCnet->GetPoint(i);
5353  if ( point->IsIgnored() )
5354  continue;
5355 
5357 
5358  nRejected = 0;
5359  nIndexMaxResidual = -1;
5360  dMaxResidual = -1.0;
5361 
5362  int nMeasures = point->GetNumMeasures();
5363  for (int j = 0; j < nMeasures; j++) {
5364 
5365  ControlMeasure *measure = point->GetMeasure(j);
5366  if ( measure->IsIgnored() )
5367  continue;
5368 
5369  vx = measure->GetSampleResidual();
5370  vy = measure->GetLineResidual();
5371 
5372  dSumSquares = sqrt(vx*vx + vy*vy);
5373 
5374  // measure is good
5375  if ( dSumSquares <= dUsedRejectionLimit ) {
5376 
5377  // was it previously rejected?
5378  if( measure->IsRejected() ) {
5379  printf("Coming back in: %s\r",point->GetId().toAscii().data());
5380  nComingBack++;
5381  m_pCnet->DecrementNumberOfRejectedMeasuresInImage(measure->GetCubeSerialNumber());
5382  }
5383 
5384  measure->SetRejected(false);
5385  continue;
5386  }
5387 
5388  // if it's still rejected, skip it
5389  if ( measure->IsRejected() ) {
5390  nRejected++;
5391  ntotalrejected++;
5392  continue;
5393  }
5394 
5395  if ( dSumSquares > dMaxResidual ) {
5396  dMaxResidual = dSumSquares;
5397  nIndexMaxResidual = j;
5398  }
5399  }
5400 
5401  // no observations above the current rejection limit for this 3D point
5402  if ( dMaxResidual == -1.0 || dMaxResidual <= dUsedRejectionLimit ) {
5403  point->SetNumberOfRejectedMeasures(nRejected);
5404  continue;
5405  }
5406 
5407  // this is another kluge - if we only have two observations
5408  // we won't reject (for now)
5409  if ((nMeasures - (nRejected + 1)) < 2) {
5410  point->SetNumberOfRejectedMeasures(nRejected);
5411  continue;
5412  }
5413 
5414  // otherwise, we have at least one observation
5415  // for this point whose residual is above the
5416  // current rejection limit - we'll flag the
5417  // worst of these as rejected
5418  ControlMeasure *rejected = point->GetMeasure(nIndexMaxResidual);
5419  rejected->SetRejected(true);
5420  nRejected++;
5421  point->SetNumberOfRejectedMeasures(nRejected);
5422  m_pCnet->IncrementNumberOfRejectedMeasuresInImage(rejected->GetCubeSerialNumber());
5423  ntotalrejected++;
5424 
5425  // do we still have sufficient remaining observations for this 3D point?
5426  if( ( nMeasures-nRejected ) < 2 ) {
5427  point->SetRejected(true);
5428  printf("Rejecting Entire Point: %s\r",point->GetId().toAscii().data());
5429  }
5430  else
5431  point->SetRejected(false);
5432 
5433 // int ndummy = point->GetNumberOfRejectedMeasures();
5434 // printf("Rejected for point %s = %d\n", point->GetId().toAscii().data(), ndummy);
5435 // printf("%s: %20.10lf %20.10lf*\n",point->GetId().toAscii().data(), rejected->GetSampleResidual(), rejected->GetLineResidual());
5436  }
5437 
5438  m_nRejectedObservations = 2*ntotalrejected;
5439 
5440  printf("\n\t Rejected Observations:%10d (Rejection Limit:%12.5lf\n",
5441  m_nRejectedObservations, dUsedRejectionLimit);
5442 
5443  std::cout << "Measures that came back: " << nComingBack << std::endl;
5444 
5445  return true;
5446 }
5447 
5448 
5452  bool BundleAdjust::errorPropagation() {
5453  if ( m_decompositionMethod == CHOLMOD )
5454  return errorPropagation_CHOLMOD();
5455  else
5456  return errorPropagation_SPECIALK();
5457 
5458  return false;
5459  }
5460 
5461 
5465  bool BundleAdjust::errorPropagation_SPECIALK() {
5466 
5467  // create inverse of normal equations matrix
5468  if ( !CholeskyUT_NOSQR_Inverse() )
5469  return false;
5470 
5471  matrix<double> T(3, 3);
5472  matrix<double> QS(3, m_nRank);
5473  double dSigmaLat, dSigmaLong, dSigmaRadius;
5474  double t;
5475 
5476  double dSigma02 = m_dSigma0 * m_dSigma0;
5477 
5478  int nPointIndex = 0;
5479  int nObjectPoints = m_pCnet->GetNumPoints();
5480  for (int i = 0; i < nObjectPoints; i++) {
5481  ControlPoint *point = m_pCnet->GetPoint(i);
5482  if ( point->IsIgnored() )
5483  continue;
5484 
5485  if ( point->IsRejected() )
5486  continue;
5487 
5488  printf("\rProcessing point %d of %d",i+1,nObjectPoints);
5489 
5490  T.clear();
5491  QS.clear();
5492 
5493  // get corresponding Q matrix
5494  compressed_matrix<double>& Q = m_Qs_SPECIALK[nPointIndex];
5495 
5496  // form QS
5497  QS = prod(Q, m_Normals);
5498 
5499  // form T
5500  T = prod(QS, trans(Q));
5501 
5502  // Ask Ken what is happening here...Setting just the sigmas is not very accurate
5503  // Shouldn't we be updating and setting the matrix??? TODO
5504  SurfacePoint SurfacePoint = point->GetAdjustedSurfacePoint();
5505 
5506  dSigmaLat = SurfacePoint.GetLatSigma().radians();
5507  dSigmaLong = SurfacePoint.GetLonSigma().radians();
5508  dSigmaRadius = SurfacePoint.GetLocalRadiusSigma().meters();
5509 
5510 // std::cout << dSigmaLat << " " << dSigmaLong << " " << dSigmaRadius << std::endl;
5511 
5512 // dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
5513 // dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
5514 // dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
5515 
5516  t = dSigmaLat*dSigmaLat + T(0, 0);
5517  Distance tLatSig(sqrt(dSigma02 * t) * m_dRTM, Distance::Meters);
5518 
5519  t = dSigmaLong*dSigmaLong + T(1, 1);
5520  t = sqrt(dSigma02 * t) * m_dRTM;
5521  Distance tLonSig(
5522  t * cos(point->GetAdjustedSurfacePoint().GetLatitude().radians()),
5523  Distance::Meters);
5524 
5525  t = dSigmaRadius*dSigmaRadius + T(2, 2);
5526  t = sqrt(dSigma02 * t) * 1000.0;
5527 
5528  SurfacePoint.SetSphericalSigmasDistance(tLatSig, tLonSig,
5529  Distance(t, Distance::Meters));
5530 
5531  point->SetAdjustedSurfacePoint(SurfacePoint);
5532 
5533  nPointIndex++;
5534  }
5535 
5536  return true;
5537  }
5538 
5539 
5540 /*
5541  //
5542  // error propagation for CHOLMOD solution.
5543  //
5544  bool BundleAdjust::errorPropagation_CHOLMOD() {
5545 
5546  // free unneeded memory
5547  cholmod_free_triplet(&m_pTriplet, &m_cm);
5548  cholmod_free_sparse(&m_N, &m_cm);
5549 // m_SparseNormals.wipe();
5550 
5551  // create inverse of normal equations matrix
5552  if ( !cholmod_Inverse() )
5553 // if ( !cholmod_Inverse_binarywrite() )
5554  return false;
5555 
5556  matrix<double> T(3, 3);
5557  matrix<double> QS(3, m_nRank);
5558  double dSigmaLat, dSigmaLong, dSigmaRadius;
5559  double t;
5560 
5561  // TODO_CHOLMOD: would rather not make copies like this
5562  // must be a better way????
5563  compressed_matrix<double> Q(3,m_nRank);
5564 
5565  double dSigma02 = m_dSigma0 * m_dSigma0;
5566 
5567  int nPointIndex = 0;
5568  int nObjectPoints = m_pCnet->GetNumPoints();
5569  for (int i = 0; i < nObjectPoints; i++) {
5570 
5571  ControlPoint *point = m_pCnet->GetPoint(i);
5572  if ( point->IsIgnored() )
5573  continue;
5574 
5575  if ( point->IsRejected() )
5576  continue;
5577 
5578  printf("\rProcessing point %d of %d Time: %s",i+1, nObjectPoints, Isis::iTime::CurrentLocalTime().toAscii().data());
5579 
5580  T.clear();
5581  QS.clear();
5582 
5583  // get corresponding Q matrix
5584  SparseBlockRowMatrix& Qblock = m_Qs_CHOLMOD[nPointIndex];
5585 
5586  qDebug() << Qblock;
5587 
5588  // copy into compressed boost matrix
5589  // TODO_CHOLMOD: don't want to do this
5590  Qblock.copyToBoost(Q);
5591 
5592 // Qblock.print();
5593  std::cout << "Copy of Q" << Q << std::endl;
5594 
5595  // form QS
5596  QS = prod(Q, m_Normals);
5597 
5598 // ANZmultAdd(Q, m_Normals, QS);
5599 
5600  // form T
5601  T = prod(QS, trans(Q));
5602 
5603 // AmulttransBNZ(QS, Q, T);
5604 
5605  std::cout << "T" << std::endl << T << std::endl;
5606 
5607  // Ask Ken what is happening here...Setting just the sigmas is not very
5608  // accurate
5609  // Shouldn't we be updating and setting the matrix??? TODO
5610  SurfacePoint SurfacePoint = point->GetAdjustedSurfacePoint();
5611 
5612  dSigmaLat = SurfacePoint.GetLatSigma().radians();
5613  dSigmaLong = SurfacePoint.GetLonSigma().radians();
5614  dSigmaRadius = SurfacePoint.GetLocalRadiusSigma().meters();
5615 
5616 // std::cout << dSigmaLat << " " << dSigmaLong << " " << dSigmaRadius << std::endl;
5617 
5618 // dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
5619 // dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
5620 // dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
5621 
5622  t = dSigmaLat*dSigmaLat + T(0, 0);
5623  Distance tLatSig(sqrt(dSigma02 * t) * m_dRTM, Distance::Meters);
5624 
5625  t = dSigmaLong*dSigmaLong + T(1, 1);
5626  t = sqrt(dSigma02 * t) * m_dRTM;
5627  Distance tLonSig(
5628  t * cos(point->GetAdjustedSurfacePoint().GetLatitude().radians()),
5629  Distance::Meters);
5630 
5631  t = dSigmaRadius*dSigmaRadius + T(2, 2);
5632  t = sqrt(dSigma02 * t) * 1000.0;
5633 
5634  SurfacePoint.SetSphericalSigmasDistance(tLatSig, tLonSig,
5635  Distance(t, Distance::Meters));
5636 
5637  point->SetAdjustedSurfacePoint(SurfacePoint);
5638 
5639  nPointIndex++;
5640  }
5641 
5642  return true;
5643  }
5644 */
5645 
5646 
5650  bool BundleAdjust::errorPropagation_CHOLMOD() {
5651 
5652  // free unneeded memory
5653  cholmod_free_triplet(&m_pTriplet, &m_cm);
5654  cholmod_free_sparse(&m_N, &m_cm);
5655 
5656  matrix<double> T(3, 3);
5657  double dSigmaLat, dSigmaLong, dSigmaRadius;
5658  double t;
5659 
5660  double dSigma02 = m_dSigma0 * m_dSigma0;
5661 
5662  int nObjectPoints = m_pCnet->GetNumPoints();
5663 
5664  std::string strTime = Isis::iTime::CurrentLocalTime().toAscii().data();
5665  printf(" Time: %s\n\n", strTime.c_str());
5666 
5667  // create and initialize array of 3x3 matrices for all object points
5668  std::vector< symmetric_matrix<double> > point_covs(nObjectPoints,symmetric_matrix<double>(3));
5669  for (int d = 0; d < nObjectPoints; d++)
5670  point_covs[d].clear();
5671 
5672  // allocate memory for adjusted image parameter sigmas
5673  m_Image_AdjustedSigmas.resize(m_SparseNormals.size());
5674 
5675  cholmod_dense *x; // solution vector
5676  cholmod_dense *b; // right-hand side (column vectors of identity)
5677 
5678  b = cholmod_zeros ( m_nRank, 1, CHOLMOD_REAL, &m_cm );
5679  double* pb = (double*)b->x;
5680 
5681  double* px = NULL;
5682 
5683  SparseBlockColumnMatrix sbcMatrix;
5684 
5685  int i, j, k;
5686  int nCurrentColumn = 0;
5687  int ncolsCurrentBlockColumn = 0;
5688 
5689  int nBlockColumns = m_SparseNormals.size();
5690  for (i = 0; i < nBlockColumns; i++) {
5691 
5692  // columns in this column block
5693  SparseBlockColumnMatrix* normalsColumn = m_SparseNormals.at(i);
5694  if (i == 0) {
5695  ncolsCurrentBlockColumn = normalsColumn->numberOfColumns();
5696  int nRows = m_SparseNormals.at(i)->numberOfRows();
5697  sbcMatrix.insertMatrixBlock(i, nRows, ncolsCurrentBlockColumn);
5698  sbcMatrix.zeroBlocks();
5699  }
5700  else {
5701  if (normalsColumn->numberOfColumns() == ncolsCurrentBlockColumn) {
5702  int nRows = m_SparseNormals.at(i)->numberOfRows();
5703  sbcMatrix.insertMatrixBlock(i, nRows, ncolsCurrentBlockColumn);
5704  sbcMatrix.zeroBlocks();
5705  }
5706  else {
5707  ncolsCurrentBlockColumn = normalsColumn->numberOfColumns();
5708 
5709  // reset sbcMatrix
5710  sbcMatrix.wipe();
5711 
5712  // insert blocks
5713  for (j = 0; j < (i+1); j++) {
5714  SparseBlockColumnMatrix* normalsRow = m_SparseNormals.at(j);
5715  int nRows = normalsRow->numberOfRows();
5716 
5717  sbcMatrix.insertMatrixBlock(j, nRows, ncolsCurrentBlockColumn);
5718  }
5719  }
5720  }
5721 
5722  int localCol = 0;
5723 
5724  // solve for inverse for nCols
5725  for (j = 0; j < ncolsCurrentBlockColumn; j++) {
5726  if ( nCurrentColumn > 0 )
5727  pb[nCurrentColumn-1] = 0.0;
5728  pb[nCurrentColumn] = 1.0;
5729 
5730  x = cholmod_solve ( CHOLMOD_A, m_L, b, &m_cm );
5731  px = (double*)x->x;
5732  int rp = 0;
5733 
5734  // store solution in corresponding column of inverse
5735  for ( k = 0; k < sbcMatrix.size(); k++ ) {
5736  matrix<double>* matrix = sbcMatrix.value(k);
5737 
5738  int sz1 = matrix->size1();
5739 
5740  for (int ii = 0; ii < sz1; ii++) {
5741  (*matrix)(ii,localCol) = px[ii + rp];
5742  }
5743  rp += matrix->size1();
5744  }
5745 
5746  nCurrentColumn++;
5747  localCol++;
5748 
5749  cholmod_free_dense(&x,&m_cm);
5750  }
5751 
5752  // save adjusted image sigmas
5753  m_Image_AdjustedSigmas[i].resize(ncolsCurrentBlockColumn);
5754  matrix<double>* imageCovMatrix = sbcMatrix.value(i);
5755  for( int z = 0; z < ncolsCurrentBlockColumn; z++) {
5756  m_Image_AdjustedSigmas[i][z] = (*imageCovMatrix)(z,z);
5757  }
5758 
5759  // now loop over all object points to sum contributions into 3x3 point covariance matrix
5760  int nPointIndex = 0;
5761  for (j = 0; j < nObjectPoints; j++) {
5762 
5763  ControlPoint *point = m_pCnet->GetPoint(j);
5764  if ( point->IsIgnored() )
5765  continue;
5766 
5767  if ( point->IsRejected() )
5768  continue;
5769 
5770  // only update point every 100 points
5771  if (j%100 == 0) {
5772  printf("\rError Propagation: Inverse Block %8d of %8d; Point %8d of %8d", i+1,
5773  nBlockColumns, j+1, nObjectPoints);
5774  }
5775 
5776  // get corresponding Q matrix
5777  SparseBlockRowMatrix& Q = m_Qs_CHOLMOD[nPointIndex];
5778 
5779  T.clear();
5780 
5781  // get corresponding point covariance matrix
5782  symmetric_matrix<double>& cv = point_covs[nPointIndex];
5783 
5784  // get qT - index i is the key into Q for qT
5785  matrix<double>* qT = Q.value(i);
5786  if (!qT) {
5787  nPointIndex++;
5788  continue;
5789  }
5790 
5791  // iterate over Q
5792  // q is current map value
5793  QMapIterator<int, matrix<double>*> it(Q);
5794  while ( it.hasNext() ) {
5795  it.next();
5796 
5797  int nKey = it.key();
5798 
5799  if (it.key() > i)
5800  break;
5801 
5802  matrix<double>* q = it.value();
5803 
5804  if ( !q ) // should never be NULL
5805  continue;
5806 
5807  matrix<double>* nI = sbcMatrix.value(it.key());
5808 
5809  if ( !nI ) // should never be NULL
5810  continue;
5811 
5812  T = prod(*nI, trans(*qT));
5813  T = prod(*q,T);
5814 
5815  if (nKey != i)
5816  T += trans(T);
5817 
5818  cv += T;
5819  }
5820 
5821  nPointIndex++;
5822  }
5823  }
5824 
5825  // can free sparse normals now
5826  m_SparseNormals.wipe();
5827 
5828  printf("\n\n");
5829  strTime = Isis::iTime::CurrentLocalTime().toAscii().data();
5830  printf("\rFilling point covariance matrices: Time %s", strTime.c_str());
5831  printf("\n\n");
5832 
5833  // now loop over points again and set final covariance stuff
5834  int nPointIndex = 0;
5835  for (j = 0; j < nObjectPoints; j++) {
5836 
5837  ControlPoint *point = m_pCnet->GetPoint(j);
5838  if ( point->IsIgnored() )
5839  continue;
5840 
5841  if ( point->IsRejected() )
5842  continue;
5843 
5844  if (j%100 == 0) {
5845  printf("\rError Propagation: Filling point covariance matrices %8d of %8d",j+1,
5846  nObjectPoints);
5847  }
5848 
5849  // get corresponding point covariance matrix
5850  symmetric_matrix<double>& cv = point_covs[nPointIndex];
5851 
5852  // Ask Ken what is happening here...Setting just the sigmas is not very accurate
5853  // Shouldn't we be updating and setting the matrix??? TODO
5854  SurfacePoint SurfacePoint = point->GetAdjustedSurfacePoint();
5855 
5856  dSigmaLat = SurfacePoint.GetLatSigma().radians();
5857  dSigmaLong = SurfacePoint.GetLonSigma().radians();
5858  dSigmaRadius = SurfacePoint.GetLocalRadiusSigma().meters();
5859 
5860  t = dSigmaLat*dSigmaLat + cv(0, 0);
5861  Distance tLatSig(sqrt(dSigma02 * t) * m_dRTM, Distance::Meters);
5862 
5863  t = dSigmaLong*dSigmaLong + cv(1, 1);
5864  t = sqrt(dSigma02 * t) * m_dRTM;
5865  Distance tLonSig(
5866  t * cos(point->GetAdjustedSurfacePoint().GetLatitude().radians()),
5867  Distance::Meters);
5868 
5869  t = dSigmaRadius*dSigmaRadius + cv(2, 2);
5870  t = sqrt(dSigma02 * t) * 1000.0;
5871 
5872  SurfacePoint.SetSphericalSigmasDistance(tLatSig, tLonSig,
5873  Distance(t, Distance::Meters));
5874 
5875  point->SetAdjustedSurfacePoint(SurfacePoint);
5876 
5877  nPointIndex++;
5878  }
5879 
5880  return true;
5881  }
5882 
5883 
5892  void BundleAdjust::Update(BasisFunction &basis) {
5893  // Update selected spice for each image
5894  int nImages = Images();
5895  for (int i = 0; i < nImages; i++) {
5896  if (m_nHeldImages > 0)
5897  if ((m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i)))) continue;
5898 
5899  Camera *pCamera = m_pCnet->Camera(i);
5900  int index = i;
5901  index = ImageIndex(index);
5902  if (m_spacecraftPositionSolveType != Nothing) {
5903  SpicePosition *pInstPos = pCamera->instrumentPosition();
5904  std::vector<double> coefX(m_nNumberCamPosCoefSolved),
5905  coefY(m_nNumberCamPosCoefSolved),
5906  coefZ(m_nNumberCamPosCoefSolved);
5907  pInstPos->GetPolynomial(coefX, coefY, coefZ);
5908 
5909 // printf("X0:%20.10lf X1:%20.10lf X2:%20.10lf\n",abcX[0],abcX[1],abcX[2]);
5910 
5911  // Update the X coordinate coefficient(s)
5912  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
5913  coefX[icoef] += basis.Coefficient(index);
5914  index++;
5915  }
5916 
5917  // Update the Y coordinate coefficient(s)
5918  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
5919  coefY[icoef] += basis.Coefficient(index);
5920  index++;
5921  }
5922 
5923  // Update the Z coordinate cgoefficient(s)
5924  for (int icoef = 0; icoef < m_nNumberCamPosCoefSolved; icoef++) {
5925  coefZ[icoef] += basis.Coefficient(index);
5926  index++;
5927  }
5928 
5929  pInstPos->SetPolynomial(coefX, coefY, coefZ, m_nPositionType);
5930  }
5931 
5932  if (m_cmatrixSolveType != None) {
5933  SpiceRotation *pInstRot = pCamera->instrumentRotation();
5934  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved),
5935  coefDEC(m_nNumberCamAngleCoefSolved),
5936  coefTWI(m_nNumberCamAngleCoefSolved);
5937  pInstRot->GetPolynomial(coefRA, coefDEC, coefTWI);
5938 
5939  // Update right ascension coefficient(s)
5940  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
5941  coefRA[icoef] += basis.Coefficient(index);
5942  index++;
5943  }
5944 
5945  // Update declination coefficient(s)
5946  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
5947  coefDEC[icoef] += basis.Coefficient(index);
5948  index++;
5949  }
5950 
5951  if (m_bSolveTwist) {
5952  // Update twist coefficient(s)
5953  for (int icoef = 0; icoef < m_nNumberCamAngleCoefSolved; icoef++) {
5954  coefTWI[icoef] += basis.Coefficient(index);
5955  index++;
5956  }
5957  }
5958 
5959  pInstRot->SetPolynomial(coefRA, coefDEC, coefTWI, m_nPointingType);
5960  }
5961  }
5962 
5963  // Update lat/lon for each control point
5964  int nObjectPoints = m_pCnet->GetNumPoints();
5965  for (int i = 0; i < nObjectPoints; i++) {
5966  ControlPoint *point = m_pCnet->GetPoint(i);
5967  if (point->IsIgnored())
5968  continue;
5969  if (m_strSolutionMethod != "SPECIALK" &&
5970  m_strSolutionMethod != "SPARSE" &&
5971  m_strSolutionMethod != "OLDSPARSE" &&
5972  point->GetType() == ControlPoint::Fixed)
5973  continue;
5974 
5975  double dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
5976  double dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
5977  double dRad = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
5978  int index = PointIndex(i);
5979  dLat += RAD2DEG * (basis.Coefficient(index));
5980  index++;
5981  dLon += RAD2DEG * (basis.Coefficient(index));
5982  index++;
5983 
5984  // Make sure updated values are still in valid range.
5985  // TODO What is the valid lon range?
5986  if (dLat < -90.0) {
5987  dLat = -180.0 - dLat;
5988  dLon = dLon + 180.0;
5989  }
5990  if (dLat > 90.0) {
5991  dLat = 180.0 - dLat;
5992  dLon = dLon + 180.0;
5993  }
5994  while (dLon > 360.0) dLon = dLon - 360.0;
5995  while (dLon < 0.0) dLon = dLon + 360.0;
5996 
5997  // test to match results of old test case that didn't solve for radius
5998  if ( m_bSolveRadii || m_strSolutionMethod == "OLDSPARSE") {
5999  dRad += 1000.*basis.Coefficient(index);
6000  index++;
6001  }
6002 
6003  // testing
6004  // Compute fixed point in body-fixed coordinates
6005  double pB[3];
6006  latrec_c(dRad * 0.001,
6007  (dLon * DEG2RAD),
6008  (dLat * DEG2RAD),
6009  pB);
6010 // printf("%s %lf %lf %lf\n",point->Id().toAscii().data(),pB[0],pB[1],pB[2]);
6011 
6012  /* else { // Recompute radius to match updated lat/lon... Should this be removed?
6013  ControlMeasure &m = ((*m_pCnet)[i])[0];
6014  Camera *cam = m.Camera();
6015  cam->SetUniversalGround(lat, lon);
6016  rad = cam->LocalRadius(); //meters
6017  }*/
6018 
6019  SurfacePoint SurfacePoint = point->GetAdjustedSurfacePoint();
6020  SurfacePoint.SetSphericalCoordinates(Latitude(dLat, Angle::Degrees),
6021  Longitude(dLon, Angle::Degrees),
6022  Distance(dRad, Distance::Meters));
6023  point->SetAdjustedSurfacePoint(SurfacePoint);
6024  }
6025  }
6026 
6027 
6032  int BundleAdjust::PointIndex(int i) const {
6033  int nIndex;
6034 
6035  if (!m_bObservationMode)
6036  nIndex = Images() * m_nNumImagePartials;
6037  else
6038  nIndex = Observations() * m_nNumImagePartials;
6039 
6040  nIndex += m_nPointIndexMap[i] * m_nNumPointPartials;
6041 
6042  return nIndex;
6043  }
6044 
6045 
6050  int BundleAdjust::ImageIndex (int i) const {
6051  if ( !m_bObservationMode )
6052  return m_nImageIndexMap[i] * m_nNumImagePartials;
6053  else
6054  return m_pObsNumList->observationNumberMapIndex(i) * m_nNumImagePartials;
6055  }
6056 
6057 
6062  QString BundleAdjust::FileName(int i) {
6063 // QString serialNumber = (*m_pSnList)[i];
6064 // return m_pSnList->fileName(serialNumber);
6065  return m_pSnList->fileName(i);
6066  }
6067 
6068 
6073  bool BundleAdjust::IsHeld(int i) {
6074  if ( m_nHeldImages > 0 )
6075  if ((m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i))))
6076  return true;
6077  return false;
6078  }
6079 
6080 
6085  Table BundleAdjust::Cmatrix(int i) {
6086  return m_pCnet->Camera(i)->instrumentRotation()->Cache("InstrumentPointing");
6087  }
6088 
6091  Table BundleAdjust::SpVector(int i) {
6092  return m_pCnet->Camera(i)->instrumentPosition()->Cache("InstrumentPosition");
6093  }
6094 
6095 
6100  int BundleAdjust::Observations() const {
6101  if (!m_bObservationMode)
6102  return m_pSnList->size();
6103 // return m_pSnList->size() - m_nHeldImages;
6104  else
6105  return m_pObsNumList->observationSize();
6106  }
6107 
6108 
6109 //std::vector<double> BundleAdjust::PointPartial(Isis::ControlPoint &point, PartialDerivative wrt)
6110 //{
6111 // double lat = point.GetAdjustedSurfacePoint().GetLatitude(); // Radians
6112 // double lon = point.GetAdjustedSurfacePoint().GetLongitude();
6113 // double sinLon = sin(lon);
6114 // double cosLon = cos(lon);
6115 // double sinLat = sin(lat);
6116 // double cosLat = cos(lat);
6117 // double radius = point.GetAdjustedSurfacePoint().GetLocalRadius() * 0.001; /km
6118 //
6119 // std::vector<double> v(3);
6120 //
6121 // if (wrt == WRT_Latitude)
6122 // {
6123 // v[0] = -radius * sinLat * cosLon;
6124 // v[1] = -radius * sinLon * sinLat;
6125 // v[2] = radius * cosLat;
6126 // }
6127 // else if (wrt == WRT_Longitude)
6128 // {
6129 // v[0] = -radius * cosLat * sinLon;
6130 // v[1] = radius * cosLat * cosLon;
6131 // v[2] = 0.0;
6132 // }
6133 // else
6134 // {
6135 // v[0] = cosLon * cosLat;
6136 // v[1] = sinLon * cosLat;
6137 // v[2] = sinLat;
6138 // }
6139 //
6140 // return v;
6141 //}
6142 //
6143 
6144 
6158  void BundleAdjust::IterationSummary(double avErr, double sigmaXY, double sigmaHat,
6159  double sigmaX, double sigmaY) {
6160  //Add this iteration to the summary pvl
6161  QString itlog = "Iteration" + toString(m_nIteration);
6162  PvlGroup gp(itlog);
6163 
6164  gp += PvlKeyword("MaximumError", toString(m_dError), "pixels");
6165  gp += PvlKeyword("AverageError", toString(avErr), "pixels");
6166  gp += PvlKeyword("SigmaXY", toString(sigmaXY), "mm");
6167 // gp += PvlKeyword("SigmaHat", sigmaHat, "mm");
6168  gp += PvlKeyword("Sigma0", toString(m_dSigma0), "mm");
6169  gp += PvlKeyword("SigmaX", toString(sigmaX), "mm");
6170  gp += PvlKeyword("SigmaY", toString(sigmaY), "mm");
6171 
6172  if (m_maxLikelihoodFlag[m_maxLikelihoodIndex]) { //if maximum likelihood estimation is being used
6173  gp += PvlKeyword("Maximum_Likelihood_Tier: ", toString(m_maxLikelihoodIndex));
6174  gp += PvlKeyword("Median_of_R^2_residuals: ", toString(m_maxLikelihoodMedianR2Residuals));
6175  }
6176 
6177  std::ostringstream ostr;
6178  ostr<<gp<<endl;
6179  m_iterationSummary += QString::fromStdString(ostr.str());
6180  if (m_bPrintSummary) Application::Log(gp);
6181  }
6182 
6183 
6188  void BundleAdjust::SpecialKIterationSummary() {
6189  QString itlog;
6190  if ( m_bConverged )
6191  itlog = "Iteration" + toString(m_nIteration) + ": Final";
6192  else
6193  itlog = "Iteration" + toString(m_nIteration);
6194  PvlGroup gp(itlog);
6195 
6196  gp += PvlKeyword("Sigma0", toString(m_dSigma0));
6197  gp += PvlKeyword("Observations", toString(m_nObservations));
6198  gp += PvlKeyword("Constrained_Point_Parameters", toString(m_nConstrainedPointParameters));
6199  gp += PvlKeyword("Constrained_Image_Parameters", toString(m_nConstrainedImageParameters));
6200  gp += PvlKeyword("Unknown_Parameters", toString(m_nUnknownParameters));
6201  gp += PvlKeyword("Degrees_of_Freedom", toString(m_nDegreesOfFreedom));
6202  gp += PvlKeyword("Rejected_Measures", toString(m_nRejectedObservations/2));
6203 
6204  if (m_maxLikelihoodFlag[m_maxLikelihoodIndex]) { //if maximum likelihood estimation is being used
6205  gp += PvlKeyword("Maximum_Likelihood_Tier: ", toString(m_maxLikelihoodIndex));
6206  gp += PvlKeyword("Median_of_R^2_residuals: ", toString(m_maxLikelihoodMedianR2Residuals));
6207  }
6208 
6209  if ( m_bConverged ) {
6210  gp += PvlKeyword("Converged", "TRUE");
6211  gp += PvlKeyword("TotalElapsedTime", toString(m_dElapsedTime));
6212 
6213  if ( m_bErrorPropagation )
6214  gp += PvlKeyword("ErrorPropagationElapsedTime", toString(m_dElapsedTimeErrorProp));
6215  }
6216 
6217  std::ostringstream ostr;
6218  ostr<<gp<<endl;
6219  m_iterationSummary += QString::fromStdString(ostr.str());
6220  if (m_bPrintSummary) Application::Log(gp);
6221  }
6222 
6223 
6230  bool BundleAdjust::SetParameterWeights() {
6231 
6232  SetSpaceCraftWeights();
6233  ComputeImageParameterWeights();
6234 
6235  m_dParameterWeights.resize(m_nBasisColumns);
6236  std::fill_n(m_dParameterWeights.begin(), m_nBasisColumns, 0.0);
6237  m_nConstrainedImageParameters = 0;
6238  m_nConstrainedPointParameters = 0;
6239 
6240  int nconstraintsperimage = std::count_if( m_dImageParameterWeights.begin(),
6241  m_dImageParameterWeights.end(),
6242  std::bind2nd(std::greater<double>(),0.0));
6243 
6244  int nWtIndex = 0;
6245  int nCurrentIndex = -1;
6246  int nImages = m_pSnList->size();
6247  for( int i = 0; i < nImages; i++ ) {
6248 
6249  nWtIndex = ImageIndex(i);
6250  if ( nWtIndex == nCurrentIndex )
6251  continue;
6252 
6253  nCurrentIndex = nWtIndex;
6254 
6255  if ( m_pHeldSnList != NULL &&
6256  (m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i))) ) {
6257  std::fill_n(m_dParameterWeights.begin()+nWtIndex, m_nNumImagePartials, 1.0e+50);
6258  m_nConstrainedImageParameters += m_nNumImagePartials;
6259  }
6260  else {
6261  std::copy(m_dImageParameterWeights.begin(),
6262  m_dImageParameterWeights.end(),
6263  m_dParameterWeights.begin()+nWtIndex);
6264  m_nConstrainedImageParameters += nconstraintsperimage;
6265  }
6266  }
6267 
6268  // loop over 3D object points
6269  nWtIndex = m_nImageParameters;
6270  int nObjectPoints = m_pCnet->GetNumPoints();
6271 
6272  m_Point_AprioriSigmas.resize(nObjectPoints);
6273 
6274  // initialize sigmas to zero
6275  for (int i = 0; i < nObjectPoints; i++) {
6276  m_Point_AprioriSigmas[i].clear();
6277  }
6278 
6279  int nPointIndex = 0;
6280  for (int i = 0; i < nObjectPoints; i++) {
6281  ControlPoint *point = m_pCnet->GetPoint(i);
6282  if (point->IsIgnored())
6283  continue;
6284 
6285  bounded_vector<double, 3>& apriorisigmas = m_Point_AprioriSigmas[nPointIndex];
6286 
6287  SurfacePoint aprioriSurfacePoint = point->GetAprioriSurfacePoint();
6288 // // How do I solve the compile error regarding the const?
6289 // // point->SetAprioriSurfacePoint(aprioriSurfacePoint);
6290 
6291  if (point->GetType() == ControlPoint::Fixed) {
6292  m_dParameterWeights[nWtIndex] = 1.0e+50;
6293  m_dParameterWeights[nWtIndex+1] = 1.0e+50;
6294  m_dParameterWeights[nWtIndex+2] = 1.0e+50;
6295  m_nConstrainedPointParameters += 3;
6296  }
6297  else {
6298  if( point->IsLatitudeConstrained() ) {
6299  apriorisigmas[0] = point->GetAprioriSurfacePoint().GetLatSigmaDistance().meters();
6300  m_dParameterWeights[nWtIndex] = point->GetAprioriSurfacePoint().GetLatWeight();
6301  m_nConstrainedPointParameters++;
6302  }
6303  else if( m_dGlobalLatitudeAprioriSigma > 0.0 ) {
6304  apriorisigmas[0] = m_dGlobalLatitudeAprioriSigma;
6305  m_dParameterWeights[nWtIndex] = 1. / (m_dGlobalLatitudeAprioriSigma*m_dMTR);
6306  m_dParameterWeights[nWtIndex] *= m_dParameterWeights[nWtIndex];
6307  m_nConstrainedPointParameters++;
6308  }
6309 
6310  if( point->IsLongitudeConstrained() ) {
6311  apriorisigmas[1] = point->GetAprioriSurfacePoint().GetLonSigmaDistance().meters();
6312  m_dParameterWeights[nWtIndex+1] = point->GetAprioriSurfacePoint().GetLonWeight();
6313  m_nConstrainedPointParameters++;
6314  }
6315  else if( m_dGlobalLongitudeAprioriSigma > 0.0 ) {
6316  apriorisigmas[1] = m_dGlobalLongitudeAprioriSigma;
6317  m_dParameterWeights[nWtIndex+1] = 1. / (m_dGlobalLongitudeAprioriSigma*m_dMTR);
6318  m_dParameterWeights[nWtIndex+1] *= m_dParameterWeights[nWtIndex+1];
6319  m_nConstrainedPointParameters++;
6320  }
6321 
6322  if ( !m_bSolveRadii ) {
6323  m_dParameterWeights[nWtIndex+2] = 1.0e+50;
6324  m_nConstrainedPointParameters++;
6325  }
6326  else if( point->IsRadiusConstrained() ) {
6327  apriorisigmas[2] = point->GetAprioriSurfacePoint().GetLocalRadiusSigma().meters();
6328  m_dParameterWeights[nWtIndex+2] = point->GetAprioriSurfacePoint().GetLocalRadiusWeight();
6329  m_nConstrainedPointParameters++;
6330  }
6331  else if( m_dGlobalRadiusAprioriSigma > 0.0 ) {
6332  apriorisigmas[2] = m_dGlobalRadiusAprioriSigma;
6333  m_dParameterWeights[nWtIndex+2] = 1000. / m_dGlobalRadiusAprioriSigma;
6334  m_dParameterWeights[nWtIndex+2] *= m_dParameterWeights[nWtIndex+2];
6335  m_nConstrainedPointParameters++;
6336  }
6337  }
6338 
6339  nWtIndex += 3;
6340  nPointIndex++;
6341  }
6342 
6343  m_pLsq->SetParameterWeights(m_dParameterWeights);
6344 
6345  // Next call added by DAC 02-04-2011...Is this correct? Ask Ken
6346  m_pLsq->SetNumberOfConstrainedParameters(
6347  m_nConstrainedPointParameters+m_nConstrainedImageParameters);
6348 
6349  return true;
6350  }
6351 
6352 
6357  void BundleAdjust::SetPostBundleSigmas() {
6358  double dSigmaLat;
6359  double dSigmaLong;
6360  double dSigmaRadius;
6361 
6362  // get reference to the covariance matrix from the least-squares object
6363  gmm::row_matrix<gmm::rsvector<double> > lsqCovMatrix = m_pLsq->GetCovarianceMatrix();
6364 
6365  int nIndex = m_nImageParameters;
6366 
6367  int nPoints = m_pCnet->GetNumPoints();
6368  for (int i = 0; i < nPoints; i++) {
6369  ControlPoint *point = m_pCnet->GetPoint(i);
6370  if (point->IsIgnored())
6371  continue;
6372 
6373  dSigmaLat = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6374  dSigmaLat *= m_dRTM;
6375  nIndex++;
6376 
6377  dSigmaLong = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6378  dSigmaLong *= m_dRTM * cos(point->GetAdjustedSurfacePoint().GetLatitude().radians()); // Lat in radians
6379  nIndex++;
6380 
6381  dSigmaRadius = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6382 
6383  nIndex++;
6384 
6385  SurfacePoint SurfacePoint = point->GetAdjustedSurfacePoint();
6386 
6387  SurfacePoint.SetSphericalSigmasDistance(
6388  Distance(dSigmaLat, Distance::Meters),
6389  Distance(dSigmaLong, Distance::Meters),
6390  Distance(dSigmaRadius, Distance::Kilometers));
6391 
6392  point->SetAdjustedSurfacePoint(SurfacePoint);
6393  }
6394  }
6395 
6396 
6400  bool BundleAdjust::Output() {
6401  if (m_bOutputStandard) {
6402  if (m_bConverged && m_bErrorPropagation)
6403  OutputWithErrorPropagation();
6404  else
6405  OutputNoErrorPropagation();
6406  }
6407 
6408  if (m_bOutputCSV) {
6409  OutputPointsCSV();
6410  OutputImagesCSV();
6411  }
6412 
6413  if (m_bOutputResiduals)
6414  OutputResiduals();
6415 
6416  return true;
6417  }
6418 
6419 
6424  bool BundleAdjust::OutputHeader(std::ofstream& fp_out) {
6425  if (!fp_out)
6426  return false;
6427 
6428  char buf[1056];
6429  int nImages = Images();
6430  int nValidPoints = m_pCnet->GetNumValidPoints();
6431  int nInnerConstraints = 0;
6432  int nDistanceConstraints = 0;
6433  int nDegreesOfFreedom = m_nObservations + m_nConstrainedPointParameters + m_nConstrainedImageParameters - m_nUnknownParameters;
6434  int nConvergenceCriteria = 1;
6435 
6436  if (!m_bDeltack)
6437  sprintf(buf, "JIGSAW: BUNDLE ADJUSTMENT\n=========================\n");
6438  else
6439  sprintf(buf, "JIGSAW (DELTACK or QTIE): BUNDLE ADJUSTMENT\n=========================\n");
6440 
6441  fp_out << buf;
6442  sprintf(buf, "\n Run Time: %s", Isis::iTime::CurrentLocalTime().toAscii().data());
6443  fp_out << buf;
6444  sprintf(buf,"\n Network Filename: %s", m_strCnetFileName.toAscii().data());
6445  fp_out << buf;
6446  sprintf(buf,"\n Network Id: %s", m_pCnet->GetNetworkId().toAscii().data());
6447  fp_out << buf;
6448  sprintf(buf,"\n Network Description: %s", m_pCnet->Description().toAscii().data());
6449  fp_out << buf;
6450  sprintf(buf,"\n Target: %s", m_pCnet->GetTarget().toAscii().data());
6451  fp_out << buf;
6452  sprintf(buf,"\n\n Linear Units: kilometers");
6453  fp_out << buf;
6454  sprintf(buf,"\n Angular Units: decimal degrees");
6455  fp_out << buf;
6456  sprintf(buf, "\n\nINPUT: SOLVE OPTIONS\n====================\n");
6457  fp_out << buf;
6458  m_bObservationMode ? sprintf(buf, "\n OBSERVATIONS: ON"):
6459  sprintf(buf, "\n OBSERVATIONS: OFF");
6460  fp_out << buf;
6461  m_bSolveRadii ? sprintf(buf, "\n RADIUS: ON"):
6462  sprintf(buf, "\n RADIUS: OFF");
6463  fp_out << buf;
6464  m_bUpdateCubes ? sprintf(buf, "\n UPDATE: YES"):
6465  sprintf(buf, "\n UPDATE: NO");
6466  fp_out << buf;
6467  sprintf(buf,"\n SOLUTION TYPE: %s", m_strSolutionMethod.toAscii().data());
6468  fp_out << buf;
6469  m_bErrorPropagation ? sprintf(buf, "\n ERROR PROPAGATION: ON"):
6470  sprintf(buf, "\n ERROR PROPAGATION: OFF");
6471  fp_out << buf;
6472  m_bOutlierRejection ? sprintf(buf, "\n OUTLIER REJECTION: ON"):
6473  sprintf(buf, "\n OUTLIER REJECTION: OFF");
6474  fp_out << buf;
6475  sprintf(buf,"\n REJECTION MULTIPLIER: %lf",m_dRejectionMultiplier);
6476  fp_out << buf;
6477  sprintf(buf, "\n\nMAXIMUM LIKELIHOOD ESTIMATION\n============================\n");
6478  fp_out << buf;
6479  for (int tier=0;tier<3;tier++) {
6480  if (m_maxLikelihoodFlag[tier]) {
6481  sprintf(buf, "\n Tier %d Enabled: TRUE",tier);
6482  fp_out << buf;
6483  sprintf(buf,"\n Maximum Likelihood Model: %s",
6484  MaximumLikelihoodWFunctions::modelToString(m_wFunc[tier]->model()).toAscii().data());
6485  fp_out << buf;
6486  sprintf(buf, "\n Quantile used for tweaking constant: %lf", m_maxLikelihoodQuan[tier]);
6487  fp_out << buf;
6488  sprintf(buf, "\n Quantile weighted R^2 Residual value: %lf", m_wFunc[tier]->tweakingConstant());
6489  fp_out << buf;
6490  sprintf(buf, "\n Approx. weighted Residual cutoff: %s",
6491  m_wFunc[tier]->weightedResidualCutoff().toAscii().data());
6492  fp_out << buf;
6493  if (tier != 2) fp_out << "\n";
6494  }
6495  else {
6496  sprintf(buf, "\n Tier %d Enabled: FALSE",tier);
6497  fp_out << buf;
6498  }
6499  }
6500  sprintf(buf, "\n\nINPUT: CONVERGENCE CRITERIA\n===========================\n");
6501  fp_out << buf;
6502  sprintf(buf,"\n SIGMA0: %e",m_dConvergenceThreshold);
6503  fp_out << buf;
6504  sprintf(buf,"\n MAXIMUM ITERATIONS: %d",m_nMaxIterations);
6505  fp_out << buf;
6506  sprintf(buf, "\n\nINPUT: CAMERA POINTING OPTIONS\n==============================\n");
6507  fp_out << buf;
6508  switch (m_cmatrixSolveType) {
6509  case BundleAdjust::AnglesOnly:
6510  sprintf(buf,"\n CAMSOLVE: ANGLES");
6511  break;
6512  case BundleAdjust::AnglesVelocity:
6513  sprintf(buf,"\n CAMSOLVE: ANGLES, VELOCITIES");
6514  break;
6515  case BundleAdjust::AnglesVelocityAcceleration:
6516  sprintf(buf,"\n CAMSOLVE: ANGLES, VELOCITIES, ACCELERATIONS");
6517  break;
6518  case BundleAdjust::CKAll:
6519  sprintf(buf,"\n CAMSOLVE: ALL POLYNOMIAL COEFFICIENTS (%d)",m_nsolveCKDegree);
6520  break;
6521  case BundleAdjust::None:
6522  sprintf(buf,"\n CAMSOLVE: NONE");
6523  break;
6524  default:
6525  break;
6526  }
6527  fp_out << buf;
6528  m_bSolveTwist ? sprintf(buf, "\n TWIST: ON"):
6529  sprintf(buf, "\n TWIST: OFF");
6530  fp_out << buf;
6531 
6532  m_bSolvePolyOverPointing ? sprintf(buf, "\n POLYNOMIAL OVER EXISTING POINTING: ON"):
6533  sprintf(buf, "\nPOLYNOMIAL OVER EXISTING POINTING : OFF");
6534  fp_out << buf;
6535 
6536  sprintf(buf, "\n\nINPUT: SPACECRAFT OPTIONS\n=========================\n");
6537  fp_out << buf;
6538  switch (m_spacecraftPositionSolveType) {
6539  case Nothing:
6540  sprintf(buf,"\n SPSOLVE: NONE");
6541  break;
6542  case PositionOnly:
6543  sprintf(buf,"\n SPSOLVE: POSITION");
6544  break;
6545  case PositionVelocity:
6546  sprintf(buf,"\n SPSOLVE: POSITION, VELOCITIES");
6547  break;
6548  case PositionVelocityAcceleration:
6549  sprintf(buf,"\n SPSOLVE: POSITION, VELOCITIES, ACCELERATIONS");
6550  break;
6551  case BundleAdjust::SPKAll:
6552  sprintf(buf,"\n CAMSOLVE: ALL POLYNOMIAL COEFFICIENTS (%d)",m_nsolveSPKDegree);
6553  break;
6554  default:
6555  break;
6556  }
6557  fp_out << buf;
6558 
6559  m_bSolvePolyOverHermite ? sprintf(buf, "\n POLYNOMIAL OVER HERMITE SPLINE: ON"):
6560  sprintf(buf, "\nPOLYNOMIAL OVER HERMITE SPLINE : OFF");
6561  fp_out << buf;
6562 
6563  sprintf(buf, "\n\nINPUT: GLOBAL IMAGE PARAMETER UNCERTAINTIES\n===========================================\n");
6564  fp_out << buf;
6565  (m_dGlobalLatitudeAprioriSigma == -1) ? sprintf(buf,"\n POINT LATITUDE SIGMA: N/A"):
6566  sprintf(buf,"\n POINT LATITUDE SIGMA: %lf (meters)",m_dGlobalLatitudeAprioriSigma);
6567  fp_out << buf;
6568  (m_dGlobalLongitudeAprioriSigma == -1) ? sprintf(buf,"\n POINT LONGITUDE SIGMA: N/A"):
6569  sprintf(buf,"\n POINT LONGITUDE SIGMA: %lf (meters)",m_dGlobalLongitudeAprioriSigma);
6570  fp_out << buf;
6571  (m_dGlobalRadiusAprioriSigma == -1) ? sprintf(buf,"\n POINT RADIUS SIGMA: N/A"):
6572  sprintf(buf,"\n POINT RADIUS SIGMA: %lf (meters)",m_dGlobalRadiusAprioriSigma);
6573  fp_out << buf;
6574 
6575  if (m_nNumberCamPosCoefSolved < 1 || m_dGlobalSpacecraftPositionAprioriSigma[0] == -1)
6576  sprintf(buf,"\n SPACECRAFT POSITION SIGMA: N/A");
6577  else
6578  sprintf(buf,"\n SPACECRAFT POSITION SIGMA: %lf (meters)",m_dGlobalSpacecraftPositionAprioriSigma[0]);
6579  fp_out << buf;
6580 
6581  if (m_nNumberCamPosCoefSolved < 2 || m_dGlobalSpacecraftPositionAprioriSigma[1] == -1)
6582  sprintf(buf,"\n SPACECRAFT VELOCITY SIGMA: N/A");
6583  else
6584  sprintf(buf,"\n SPACECRAFT VELOCITY SIGMA: %lf (m/s)",m_dGlobalSpacecraftPositionAprioriSigma[1]);
6585  fp_out << buf;
6586 
6587  if (m_nNumberCamPosCoefSolved < 3 || m_dGlobalSpacecraftPositionAprioriSigma[2] == -1)
6588  sprintf(buf,"\n SPACECRAFT ACCELERATION SIGMA: N/A");
6589  else
6590  sprintf(buf,"\n SPACECRAFT ACCELERATION SIGMA: %lf (m/s/s)",m_dGlobalSpacecraftPositionAprioriSigma[2]);
6591  fp_out << buf;
6592 
6593  if (m_nNumberCamAngleCoefSolved < 1 || m_dGlobalCameraAnglesAprioriSigma[0] == -1)
6594  sprintf(buf,"\n CAMERA ANGLES SIGMA: N/A");
6595  else
6596  sprintf(buf,"\n CAMERA ANGLES SIGMA: %lf (dd)",m_dGlobalCameraAnglesAprioriSigma[0]);
6597  fp_out << buf;
6598 
6599  if (m_nNumberCamAngleCoefSolved < 2 || m_dGlobalCameraAnglesAprioriSigma[1] == -1)
6600  sprintf(buf,"\n CAMERA ANGULAR VELOCITY SIGMA: N/A");
6601  else
6602  sprintf(buf,"\n CAMERA ANGULAR VELOCITY SIGMA: %lf (dd/s)",m_dGlobalCameraAnglesAprioriSigma[1]);
6603  fp_out << buf;
6604 
6605  if (m_nNumberCamAngleCoefSolved < 3 || m_dGlobalCameraAnglesAprioriSigma[2] == -1)
6606  sprintf(buf,"\n CAMERA ANGULAR ACCELERATION SIGMA: N/A");
6607  else
6608  sprintf(buf,"\n CAMERA ANGULAR ACCELERATION SIGMA: %lf (dd/s/s)",m_dGlobalCameraAnglesAprioriSigma[2]);
6609  fp_out << buf;
6610 
6611  sprintf(buf, "\n\nJIGSAW: RESULTS\n===============\n");
6612  fp_out << buf;
6613  sprintf(buf,"\n Images: %6d",nImages);
6614  fp_out << buf;
6615  sprintf(buf,"\n Points: %6d",nValidPoints);
6616  fp_out << buf;
6617  sprintf(buf,"\n Total Measures: %6d",(m_nObservations+m_nRejectedObservations)/2);
6618  fp_out << buf;
6619  sprintf(buf,"\n Total Observations: %6d",m_nObservations+m_nRejectedObservations);
6620  fp_out << buf;
6621  sprintf(buf,"\n Good Observations: %6d",m_nObservations);
6622  fp_out << buf;
6623  sprintf(buf,"\n Rejected Observations: %6d",m_nRejectedObservations);
6624  fp_out << buf;
6625 
6626  if (m_nConstrainedPointParameters > 0) {
6627  sprintf(buf, "\n Constrained Point Parameters: %6d",m_nConstrainedPointParameters);
6628  fp_out << buf;
6629  }
6630  if (m_nConstrainedImageParameters > 0) {
6631  sprintf(buf, "\n Constrained Image Parameters: %6d",m_nConstrainedImageParameters);
6632  fp_out << buf;
6633  }
6634  sprintf(buf,"\n Unknowns: %6d",m_nUnknownParameters);
6635  fp_out << buf;
6636  if (nInnerConstraints > 0) {
6637  sprintf(buf, "\n Inner Constraints: %6d",nInnerConstraints);
6638  fp_out << buf;
6639  }
6640  if (nDistanceConstraints > 0) {
6641  sprintf(buf, "\n Distance Constraints: %d",nDistanceConstraints);
6642  fp_out << buf;
6643  }
6644 
6645  sprintf(buf,"\n Degrees of Freedom: %6d",nDegreesOfFreedom);
6646  fp_out << buf;
6647  sprintf(buf,"\n Convergence Criteria: %6.3g",m_dConvergenceThreshold);
6648  fp_out << buf;
6649 
6650  if (nConvergenceCriteria == 1) {
6651  sprintf(buf, "(Sigma0)");
6652  fp_out << buf;
6653  }
6654 
6655  sprintf(buf, "\n Iterations: %6d",m_nIteration);
6656  fp_out << buf;
6657 
6658  if (m_nIteration >= m_nMaxIterations) {
6659  sprintf(buf, "(Maximum reached)");
6660  fp_out << buf;
6661  }
6662 
6663  sprintf(buf, "\n Sigma0: %30.20lf\n",m_dSigma0);
6664  fp_out << buf;
6665  sprintf(buf, " Error Propagation Elapsed Time: %6.4lf (seconds)\n",m_dElapsedTimeErrorProp);
6666  fp_out << buf;
6667  sprintf(buf, " Total Elapsed Time: %6.4lf (seconds)\n",m_dElapsedTime);
6668  fp_out << buf;
6669  if (m_nObservations+m_nRejectedObservations > 100) { //if there was enough data to calculate percentiles and box plot data
6670  sprintf(buf, "\n Residual Percentiles:\n");
6671  fp_out << buf;
6672  try {
6673  for (int bin=1;bin<34;bin++) {
6674  //double quan = m_cumProRes->value(double(bin)/100);
6675  sprintf(buf, " Percentile %3d: %+8.3lf Percentile %3d: %+8.3lf Percentile %3d: %+8.3lf\n",bin ,m_cumProRes->value(double(bin )/100.0),
6676  bin+33,m_cumProRes->value(double(bin+33)/100.0),
6677  bin+66,m_cumProRes->value(double(bin+66)/100.0));
6678  fp_out << buf;
6679  }
6680  }
6681  catch (IException &e) {
6682  QString msg = "Faiiled to output residual percentiles for bundleout";
6683  throw IException(e, IException::Io, msg, _FILEINFO_);
6684  }
6685  try {
6686  sprintf(buf, "\n Residual Box Plot:");
6687  fp_out << buf;
6688  sprintf(buf, "\n minimum: %+8.3lf",m_cumProRes->min());
6689  fp_out << buf;
6690  sprintf(buf, "\n Quartile 1: %+8.3lf",m_cumProRes->value(0.25));
6691  fp_out << buf;
6692  sprintf(buf, "\n Median: %+8.3lf",m_cumProRes->value(0.50));
6693  fp_out << buf;
6694  sprintf(buf, "\n Quartile 3: %+8.3lf",m_cumProRes->value(0.75));
6695  fp_out << buf;
6696  sprintf(buf, "\n maximum: %+8.3lf\n",m_cumProRes->max());
6697  fp_out << buf;
6698  }
6699  catch (IException &e) {
6700  QString msg = "Faiiled to output residual box plot for bundleout";
6701  throw IException(e, IException::Io, msg, _FILEINFO_);
6702  }
6703  }
6704 
6705  sprintf(buf,"\nIMAGE MEASURES SUMMARY\n==========================\n\n");
6706  fp_out << buf;
6707 
6708  int nMeasures;
6709  int nRejectedMeasures;
6710  int nUsed;
6711 
6712  for (int i = 0; i < nImages; i++) {
6713  // ImageIndex(i) retrieves index into the normal equations matrix
6714  // for Image(i)
6715  double rmsSampleResiduals = m_rmsImageSampleResiduals[i].Rms();
6716  double rmsLineResiduals = m_rmsImageLineResiduals[i].Rms();
6717  double rmsLandSResiduals = m_rmsImageResiduals[i].Rms();
6718 
6719  nMeasures = m_pCnet->GetNumberOfValidMeasuresInImage(m_pSnList->serialNumber(i));
6720  nRejectedMeasures =
6721  m_pCnet->GetNumberOfJigsawRejectedMeasuresInImage(m_pSnList->serialNumber(i));
6722 
6723  nUsed = nMeasures - nRejectedMeasures;
6724 
6725  if (nUsed == nMeasures)
6726  sprintf(buf,"%s %5d of %5d %6.3lf %6.3lf %6.3lf\n",
6727  m_pSnList->fileName(i).toAscii().data(),
6728  (nMeasures-nRejectedMeasures), nMeasures,
6729  rmsSampleResiduals,rmsLineResiduals,rmsLandSResiduals);
6730  else
6731  sprintf(buf,"%s %5d of %5d* %6.3lf %6.3lf %6.3lf\n",
6732  m_pSnList->fileName(i).toAscii().data(),
6733  (nMeasures-nRejectedMeasures), nMeasures,
6734  rmsSampleResiduals,rmsLineResiduals,rmsLandSResiduals);
6735  fp_out << buf;
6736  }
6737 
6738  return true;
6739  }
6740 
6741 
6745  bool BundleAdjust::OutputWithErrorPropagation() {
6746 
6747  QString ofname("bundleout.txt");
6748  if( m_strOutputFilePrefix.length() != 0 )
6749  ofname = m_strOutputFilePrefix + "_" + ofname;
6750 
6751  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
6752  if (!fp_out)
6753  return false;
6754 
6755  char buf[1056];
6756  std::vector<double> coefX(m_nNumberCamPosCoefSolved);
6757  std::vector<double> coefY(m_nNumberCamPosCoefSolved);
6758  std::vector<double> coefZ(m_nNumberCamPosCoefSolved);
6759  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved);
6760  std::vector<double> coefDEC(m_nNumberCamAngleCoefSolved);
6761  std::vector<double> coefTWI(m_nNumberCamAngleCoefSolved);
6762  std::vector<double> angles;
6763  Camera *pCamera = NULL;
6764  SpicePosition *pSpicePosition = NULL;
6765  SpiceRotation *pSpiceRotation = NULL;
6766 
6767  int nImages = Images();
6768  double dSigma=0;
6769  int nIndex = 0;
6770  bool bSolveSparse = false;
6771 
6772  gmm::row_matrix<gmm::rsvector<double> > lsqCovMatrix;
6773 
6774  if (m_strSolutionMethod == "OLDSPARSE") {
6775  lsqCovMatrix = m_pLsq->GetCovarianceMatrix(); // get reference to the covariance matrix from the least-squares object
6776  bSolveSparse = true;
6777  }
6778 
6779  // data structure to contain adjusted image parameter sigmas for CHOLMOD error propagation only
6780  vector<double> vImageAdjustedSigmas;
6781 
6782  OutputHeader(fp_out);
6783 
6784  sprintf(buf, "\nIMAGE EXTERIOR ORIENTATION\n==========================\n");
6785  fp_out << buf;
6786 
6787  for (int i = 0; i < nImages; i++) {
6788 
6789  //if ( m_nHeldImages > 0 && m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i)) )
6790  // bHeld = true;
6791 
6792  pCamera = m_pCnet->Camera(i);
6793  if (!pCamera)
6794  continue;
6795 
6796  // ImageIndex(i) retrieves index into the normal equations matrix for Image(i)
6797  nIndex = ImageIndex(i);
6798 
6799  if (m_decompositionMethod == CHOLMOD)
6800  vImageAdjustedSigmas = m_Image_AdjustedSigmas.at(i);
6801 
6802  pSpicePosition = pCamera->instrumentPosition();
6803  if (!pSpicePosition)
6804  continue;
6805 
6806  pSpiceRotation = pCamera->instrumentRotation();
6807  if (!pSpiceRotation)
6808  continue;
6809 
6810  // for frame cameras we directly retrieve the Exterior Orientation (i.e. position
6811  // and orientation angles). For others (linescan, radar) we retrieve the polynomial
6812  // coefficients from which the Exterior Orientation parameters are derived.
6813  if (m_spacecraftPositionSolveType > 0)
6814  pSpicePosition->GetPolynomial(coefX, coefY, coefZ);
6815  else { // not solving for position
6816  std::vector <double> coordinate(3);
6817  coordinate = pSpicePosition->GetCenterCoordinate();
6818  coefX.push_back(coordinate[0]);
6819  coefY.push_back(coordinate[1]);
6820  coefZ.push_back(coordinate[2]);
6821  }
6822 
6823  if (m_cmatrixSolveType > 0)
6824  pSpiceRotation->GetPolynomial(coefRA,coefDEC,coefTWI);
6825  // else { // frame camera
6826  else { // This is for m_cmatrixSolveType = None and no polynomial fit has occurred
6827  angles = pSpiceRotation->GetCenterAngles();
6828  coefRA.push_back(angles.at(0));
6829  coefDEC.push_back(angles.at(1));
6830  coefTWI.push_back(angles.at(2));
6831  }
6832 
6833  sprintf(buf, "\nImage Full File Name: %s\n", m_pSnList->fileName(i).toAscii().data());
6834  fp_out << buf;
6835  sprintf(buf, "\nImage Serial Number: %s\n", m_pSnList->serialNumber(i).toAscii().data());
6836  fp_out << buf;
6837  sprintf(buf, "\n Image Initial Total Final Initial Final\n"
6838  "Parameter Value Correction Value Accuracy Accuracy\n");
6839  fp_out << buf;
6840 
6841  int nSigmaIndex = 0;
6842 
6843  if (m_nNumberCamPosCoefSolved > 0) {
6844  char strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
6845  std::ostringstream ostr;
6846  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
6847  if (i == 0)
6848  ostr << " " << strcoeff;
6849  else if (i == 1)
6850  ostr << " " << strcoeff << "t";
6851  else
6852  ostr << strcoeff << "t" << i;
6853  if (bSolveSparse)
6854  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6855  else if (m_decompositionMethod == CHOLMOD)
6856  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6857  else if (m_decompositionMethod == SPECIALK)
6858  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
6859  if (i == 0) {
6860  sprintf(buf, " X (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6861  ostr.str().c_str(),coefX[i] - m_Image_Corrections(nIndex),
6862  m_Image_Corrections(nIndex), coefX[i],
6863  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6864  }
6865  else {
6866  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6867  ostr.str().c_str(),coefX[i] - m_Image_Corrections(nIndex),
6868  m_Image_Corrections(nIndex), coefX[i],
6869  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6870  }
6871  fp_out << buf;
6872  ostr.str("");
6873  strcoeff--;
6874  nIndex++;
6875  nSigmaIndex++;
6876  }
6877  strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
6878  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
6879  if (i == 0)
6880  ostr << " " << strcoeff;
6881  else if (i == 1)
6882  ostr << " " << strcoeff << "t";
6883  else
6884  ostr << strcoeff << "t" << i;
6885  if (bSolveSparse)
6886  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6887  else if (m_decompositionMethod == CHOLMOD)
6888  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6889  else if (m_decompositionMethod == SPECIALK)
6890  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
6891  if (i == 0) {
6892  sprintf(buf, " Y (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6893  ostr.str().c_str(),coefY[i] - m_Image_Corrections(nIndex),
6894  m_Image_Corrections(nIndex), coefY[i],
6895  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6896  }
6897  else {
6898  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6899  ostr.str().c_str(),coefY[i] - m_Image_Corrections(nIndex),
6900  m_Image_Corrections(nIndex), coefY[i],
6901  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6902  }
6903  fp_out << buf;
6904  ostr.str("");
6905  strcoeff--;
6906  nIndex++;
6907  nSigmaIndex++;
6908  }
6909  strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
6910  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
6911  if ( i == 0 )
6912  ostr << " " << strcoeff;
6913  else if (i == 1)
6914  ostr << " " << strcoeff << "t";
6915  else
6916  ostr << strcoeff << "t" << i;
6917  if (bSolveSparse)
6918  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6919  else if (m_decompositionMethod == CHOLMOD)
6920  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6921  else if (m_decompositionMethod == SPECIALK)
6922  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
6923  if (i == 0) {
6924  sprintf(buf, " Z (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6925  ostr.str().c_str(),coefZ[i] - m_Image_Corrections(nIndex),
6926  m_Image_Corrections(nIndex), coefZ[i],
6927  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6928  }
6929  else {
6930  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6931  ostr.str().c_str(),coefZ[i] - m_Image_Corrections(nIndex),
6932  m_Image_Corrections(nIndex), coefZ[i],
6933  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6934  }
6935  fp_out << buf;
6936  ostr.str("");
6937  strcoeff--;
6938  nIndex++;
6939  nSigmaIndex++;
6940  }
6941  }
6942 
6943  else {
6944  sprintf(buf, " X%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefX[0], 0.0, coefX[0], 0.0, "N/A");
6945  fp_out << buf;
6946  sprintf(buf, " Y%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefY[0], 0.0, coefY[0], 0.0, "N/A");
6947  fp_out << buf;
6948  sprintf(buf, " Z%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefZ[0], 0.0, coefZ[0], 0.0, "N/A");
6949  fp_out << buf;
6950  }
6951 
6952  if (m_nNumberCamAngleCoefSolved > 0) {
6953  char strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
6954  std::ostringstream ostr;
6955  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
6956  if (i == 0)
6957  ostr << " " << strcoeff;
6958  else if (i == 1)
6959  ostr << " " << strcoeff << "t";
6960  else
6961  ostr << strcoeff << "t" << i;
6962  if (bSolveSparse)
6963  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6964  else if (m_decompositionMethod == CHOLMOD)
6965  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6966  else if (m_decompositionMethod == SPECIALK)
6967  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
6968  if (i == 0) {
6969  sprintf(buf, " RA (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6970  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
6971  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
6972  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
6973  }
6974  else {
6975  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6976  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
6977  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
6978  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
6979  }
6980  fp_out << buf;
6981  ostr.str("");
6982  strcoeff--;
6983  nIndex++;
6984  nSigmaIndex++;
6985  }
6986  strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
6987  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
6988  if (i == 0)
6989  ostr << " " << strcoeff;
6990  else if (i == 1)
6991  ostr << " " << strcoeff << "t";
6992  else
6993  ostr << strcoeff << "t" << i;
6994  if (bSolveSparse)
6995  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6996  else if (m_decompositionMethod == CHOLMOD)
6997  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6998  else if (m_decompositionMethod == SPECIALK)
6999  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7000  if (i == 0) {
7001  sprintf(buf, "DEC (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7002  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7003  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7004  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7005  }
7006  else {
7007  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7008  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7009  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7010  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7011  }
7012  fp_out << buf;
7013  ostr.str("");
7014  strcoeff--;
7015  nIndex++;
7016  nSigmaIndex++;
7017  }
7018 
7019  if (!m_bSolveTwist) {
7020  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7021  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7022  fp_out << buf;
7023  }
7024  else {
7025  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
7026  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
7027  if (i == 0)
7028  ostr << " " << strcoeff;
7029  else if (i == 1)
7030  ostr << " " << strcoeff << "t";
7031  else
7032  ostr << strcoeff << "t" << i;
7033  if (bSolveSparse)
7034  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7035  else if (m_decompositionMethod == CHOLMOD)
7036  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
7037  else if (m_decompositionMethod == SPECIALK)
7038  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7039  if (i == 0) {
7040  sprintf(buf, "TWI (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7041  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7042  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7043  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7044  }
7045  else {
7046  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7047  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7048  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7049  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7050  }
7051  fp_out << buf;
7052  ostr.str("");
7053  strcoeff--;
7054  nIndex++;
7055  nSigmaIndex++;
7056  }
7057  }
7058  }
7059 
7060  else {
7061  sprintf(buf, " RA%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7062  coefRA[0]*RAD2DEG, 0.0, coefRA[0]*RAD2DEG, 0.0, "N/A");
7063  fp_out << buf;
7064  sprintf(buf, " DEC%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7065  coefDEC[0]*RAD2DEG, 0.0, coefDEC[0]*RAD2DEG, 0.0, "N/A");
7066  fp_out << buf;
7067  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7068  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7069  fp_out << buf;
7070  }
7071  }
7072 
7073  // output point data
7074  sprintf(buf, "\n\n\nPOINTS UNCERTAINTY SUMMARY\n==========================\n\n");
7075  fp_out << buf;
7076  sprintf(buf, " RMS Sigma Latitude(m)%20.8lf\n", m_drms_sigmaLat);
7077  fp_out << buf;
7078  sprintf(buf, " MIN Sigma Latitude(m)%20.8lf at %s\n",
7079  m_dminSigmaLatitude,m_idMinSigmaLatitude.toAscii().data());
7080  fp_out << buf;
7081  sprintf(buf, " MAX Sigma Latitude(m)%20.8lf at %s\n\n",
7082  m_dmaxSigmaLatitude,m_idMaxSigmaLatitude.toAscii().data());
7083  fp_out << buf;
7084  sprintf(buf, "RMS Sigma Longitude(m)%20.8lf\n", m_drms_sigmaLon);
7085  fp_out << buf;
7086  sprintf(buf, "MIN Sigma Longitude(m)%20.8lf at %s\n",
7087  m_dminSigmaLongitude,m_idMinSigmaLongitude.toAscii().data());
7088  fp_out << buf;
7089  sprintf(buf, "MAX Sigma Longitude(m)%20.8lf at %s\n\n",
7090  m_dmaxSigmaLongitude,m_idMaxSigmaLongitude.toAscii().data());
7091  fp_out << buf;
7092  if (m_bSolveRadii) {
7093  sprintf(buf, " RMS Sigma Radius(m)%20.8lf\n", m_drms_sigmaRad);
7094  fp_out << buf;
7095  sprintf(buf, " MIN Sigma Radius(m)%20.8lf at %s\n",
7096  m_dminSigmaRadius,m_idMinSigmaRadius.toAscii().data());
7097  fp_out << buf;
7098  sprintf(buf, " MAX Sigma Radius(m)%20.8lf at %s\n",
7099  m_dmaxSigmaRadius,m_idMaxSigmaRadius.toAscii().data());
7100  fp_out << buf;
7101  }
7102  else {
7103  sprintf(buf, " RMS Sigma Radius(m) N/A\n");
7104  fp_out << buf;
7105  sprintf(buf, " MIN Sigma Radius(m) N/A\n");
7106  fp_out << buf;
7107  sprintf(buf, " MAX Sigma Radius(m) N/A\n");
7108  fp_out << buf;
7109  }
7110 
7111  // output point data
7112  sprintf(buf, "\n\nPOINTS SUMMARY\n==============\n%103sSigma Sigma Sigma\n"
7113  " Label Status Rays RMS Latitude Longitude Radius"
7114  " Latitude Longitude Radius\n", "");
7115  fp_out << buf;
7116 
7117  int nRays = 0;
7118  double dLat, dLon, dRadius;
7119  double dSigmaLat, dSigmaLong, dSigmaRadius;
7120  double cor_lat_dd, cor_lon_dd, cor_rad_m;
7121  double cor_lat_m, cor_lon_m;
7122  double dLatInit, dLonInit, dRadiusInit;
7123  int nGoodRays;
7124  double dResidualRms;
7125  QString strStatus;
7126  int nPointIndex = 0;
7127 
7128  int nPoints = m_pCnet->GetNumPoints();
7129  for (int i = 0; i < nPoints; i++) {
7130 
7131  const ControlPoint *point = m_pCnet->GetPoint(i);
7132  if (point->IsIgnored())
7133  continue;
7134 
7135  nRays = point->GetNumMeasures();
7136  dResidualRms = point->GetResidualRms();
7137  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
7138  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
7139  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
7140  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
7141  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
7142  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
7143  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
7144 
7145  if (point->GetType() == ControlPoint::Fixed)
7146  strStatus = "FIXED";
7147  else if (point->GetType() == ControlPoint::Constrained)
7148  strStatus = "CONSTRAINED";
7149  else if (point->GetType() == ControlPoint::Free)
7150  strStatus = "FREE";
7151  else
7152  strStatus = "UNKNOWN";
7153 
7154  sprintf(buf, "%16s%15s%5d of %d%6.2lf%16.8lf%16.8lf%16.8lf%16.8lf%16.8lf%16.8lf\n",
7155  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays,
7156  dResidualRms, dLat, dLon, dRadius * 0.001, dSigmaLat, dSigmaLong, dSigmaRadius);
7157  fp_out << buf;
7158  nPointIndex++;
7159  }
7160 
7161  // output point data
7162  sprintf(buf, "\n\nPOINTS DETAIL\n=============\n\n");
7163  fp_out << buf;
7164 
7165  nPointIndex = 0;
7166  for (int i = 0; i < nPoints; i++) {
7167 
7168  const ControlPoint *point = m_pCnet->GetPoint(i);
7169  if ( point->IsIgnored() )
7170  continue;
7171 
7172  nRays = point->GetNumMeasures();
7173  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
7174  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
7175  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
7176  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
7177  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
7178  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
7179  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
7180 
7181  // point corrections and initial sigmas
7182  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
7183  bounded_vector<double, 3>& apriorisigmas = m_Point_AprioriSigmas[nPointIndex];
7184 
7185  cor_lat_dd = corrections[0] * Isis::RAD2DEG;
7186  cor_lon_dd = corrections[1] * Isis::RAD2DEG;
7187  cor_rad_m = corrections[2] * 1000.0;
7188 
7189  cor_lat_m = corrections[0] * m_dRTM;
7190  cor_lon_m = corrections[1] * m_dRTM * cos(dLat*Isis::DEG2RAD);
7191 
7192  dLatInit = dLat - cor_lat_dd;
7193  dLonInit = dLon - cor_lon_dd;
7194  dRadiusInit = dRadius - (corrections[2] * 1000.0);
7195 
7196  if (point->GetType() == ControlPoint::Fixed)
7197  strStatus = "FIXED";
7198  else if (point->GetType() == ControlPoint::Constrained)
7199  strStatus = "CONSTRAINED";
7200  else if (point->GetType() == ControlPoint::Free)
7201  strStatus = "FREE";
7202  else
7203  strStatus = "UNKNOWN";
7204 
7205  sprintf(buf, " Label: %s\nStatus: %s\n Rays: %d of %d\n",
7206  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays);
7207  fp_out << buf;
7208 
7209  sprintf(buf, "\n Point Initial Total Total Final Initial Final\n"
7210  "Coordinate Value Correction Correction Value Accuracy Accuracy\n"
7211  " (dd/dd/km) (dd/dd/km) (Meters) (dd/dd/km) (Meters) (Meters)\n");
7212  fp_out << buf;
7213 
7214  sprintf(buf, " LATITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n",
7215  dLatInit, cor_lat_dd, cor_lat_m, dLat, apriorisigmas[0], dSigmaLat);
7216  fp_out << buf;
7217 
7218  sprintf(buf, " LONGITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n",
7219  dLonInit, cor_lon_dd, cor_lon_m, dLon, apriorisigmas[1], dSigmaLong);
7220  fp_out << buf;
7221 
7222  sprintf(buf, " RADIUS%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n\n",
7223  dRadiusInit * 0.001, corrections[2], cor_rad_m, dRadius * 0.001,
7224  apriorisigmas[2], dSigmaRadius);
7225 
7226  fp_out << buf;
7227  nPointIndex++;
7228  }
7229 
7230  fp_out.close();
7231 
7232  return true;
7233  }
7234 
7235 
7239 /*
7240  bool BundleAdjust::OutputWithErrorPropagation() {
7241 
7242  QString ofname("bundleout.txt");
7243  if( m_strOutputFilePrefix.length() != 0 )
7244  ofname = m_strOutputFilePrefix + "_" + ofname;
7245 
7246  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
7247  if (!fp_out)
7248  return false;
7249 
7250  char buf[1056];
7251  //bool bHeld = false;
7252  std::vector<double> coefX(m_nNumberCamPosCoefSolved);
7253  std::vector<double> coefY(m_nNumberCamPosCoefSolved);
7254  std::vector<double> coefZ(m_nNumberCamPosCoefSolved);
7255  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved);
7256  std::vector<double> coefDEC(m_nNumberCamAngleCoefSolved);
7257  std::vector<double> coefTWI(m_nNumberCamAngleCoefSolved);
7258  std::vector<double> angles;
7259  Camera *pCamera = NULL;
7260  SpicePosition *pSpicePosition = NULL;
7261  SpiceRotation *pSpiceRotation = NULL;
7262 
7263  int nImages = Images();
7264  double dSigma=0;
7265  int nIndex = 0;
7266  bool bSolveSparse = false;
7267 
7268  gmm::row_matrix<gmm::rsvector<double> > lsqCovMatrix;
7269 
7270 // std::cout << m_Image_Corrections << std::endl;
7271 
7272  if( m_strSolutionMethod == "OLDSPARSE" )
7273  {
7274  lsqCovMatrix = m_pLsq->GetCovarianceMatrix(); // get reference to the covariance matrix from the least-squares object
7275  bSolveSparse = true;
7276  }
7277 
7278  OutputHeader(fp_out);
7279 //
7280  sprintf(buf, "\nIMAGE EXTERIOR ORIENTATION\n==========================\n");
7281  fp_out << buf;
7282 
7283  for ( int i = 0; i < nImages; i++ ) {
7284 
7285  //if ( m_nHeldImages > 0 && m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i)) )
7286  // bHeld = true;
7287 
7288  pCamera = m_pCnet->Camera(i);
7289  if ( !pCamera )
7290  continue;
7291 
7292  // ImageIndex(i) retrieves index into the normal equations matrix for Image(i)
7293  nIndex = ImageIndex(i) ;
7294 
7295  pSpicePosition = pCamera->instrumentPosition();
7296  if ( !pSpicePosition )
7297  continue;
7298 
7299  pSpiceRotation = pCamera->instrumentRotation();
7300  if ( !pSpiceRotation )
7301  continue;
7302 
7303  // for frame cameras we directly retrieve the Exterior Orientation (i.e. position
7304  // and orientation angles). For others (linescan, radar) we retrieve the polynomial
7305  // coefficients from which the Exterior Orientation parameters are derived.
7306  if ( m_spacecraftPositionSolveType > 0 )
7307  pSpicePosition->GetPolynomial(coefX, coefY, coefZ);
7308  else { // not solving for position
7309  std::vector <double> coordinate(3);
7310  coordinate = pSpicePosition->GetCenterCoordinate();
7311  coefX.push_back(coordinate[0]);
7312  coefY.push_back(coordinate[1]);
7313  coefZ.push_back(coordinate[2]);
7314  }
7315 
7316  if ( m_cmatrixSolveType > 0 )
7317  pSpiceRotation->GetPolynomial(coefRA,coefDEC,coefTWI);
7318  // else { // frame camera
7319  else { // This is for m_cmatrixSolveType = None and no polynomial fit has occurred
7320  angles = pSpiceRotation->GetCenterAngles();
7321  coefRA.push_back(angles.at(0));
7322  coefDEC.push_back(angles.at(1));
7323  coefTWI.push_back(angles.at(2));
7324  }
7325 
7326  sprintf(buf, "\nImage Full File Name: %s\n", m_pSnList->fileName(i).toAscii().data());
7327  fp_out << buf;
7328  sprintf(buf, "\nImage Serial Number: %s\n", m_pSnList->serialNumber(i).toAscii().data());
7329  fp_out << buf;
7330  sprintf(buf, "\n Image Initial Total Final Initial Final\n"
7331  "Parameter Value Correction Value Accuracy Accuracy\n");
7332  fp_out << buf;
7333 
7334  if( m_nNumberCamPosCoefSolved > 0 ) {
7335  char strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
7336  std::ostringstream ostr;
7337  for( int i = 0; i < m_nNumberCamPosCoefSolved; i++ ) {
7338  if( i ==0 )
7339  ostr << " " << strcoeff;
7340  else if ( i == 1 )
7341  ostr << " " << strcoeff << "t";
7342  else
7343  ostr << strcoeff << "t" << i;
7344  if( bSolveSparse )
7345  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7346  else
7347  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7348  if( i == 0 ) {
7349  sprintf(buf, " X (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7350  ostr.str().c_str(),coefX[i] - m_Image_Corrections(nIndex),
7351  m_Image_Corrections(nIndex), coefX[i],
7352  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7353  }
7354  else {
7355  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7356  ostr.str().c_str(),coefX[i] - m_Image_Corrections(nIndex),
7357  m_Image_Corrections(nIndex), coefX[i],
7358  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7359  }
7360  fp_out << buf;
7361  ostr.str("");
7362  strcoeff--;
7363  nIndex++;
7364  }
7365  strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
7366  for( int i = 0; i < m_nNumberCamPosCoefSolved; i++ ) {
7367  if( i ==0 )
7368  ostr << " " << strcoeff;
7369  else if ( i == 1 )
7370  ostr << " " << strcoeff << "t";
7371  else
7372  ostr << strcoeff << "t" << i;
7373  if( bSolveSparse )
7374  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7375  else
7376  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7377  if( i == 0 ) {
7378  sprintf(buf, " Y (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7379  ostr.str().c_str(),coefY[i] - m_Image_Corrections(nIndex),
7380  m_Image_Corrections(nIndex), coefY[i],
7381  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7382  }
7383  else {
7384  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7385  ostr.str().c_str(),coefY[i] - m_Image_Corrections(nIndex),
7386  m_Image_Corrections(nIndex), coefY[i],
7387  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7388  }
7389  fp_out << buf;
7390  ostr.str("");
7391  strcoeff--;
7392  nIndex++;
7393  }
7394  strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
7395  for( int i = 0; i < m_nNumberCamPosCoefSolved; i++ ) {
7396  if( i ==0 )
7397  ostr << " " << strcoeff;
7398  else if ( i == 1 )
7399  ostr << " " << strcoeff << "t";
7400  else
7401  ostr << strcoeff << "t" << i;
7402  if( bSolveSparse )
7403  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7404  else
7405  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7406  if( i == 0 ) {
7407  sprintf(buf, " Z (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7408  ostr.str().c_str(),coefZ[i] - m_Image_Corrections(nIndex),
7409  m_Image_Corrections(nIndex), coefZ[i],
7410  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7411  }
7412  else {
7413  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7414  ostr.str().c_str(),coefZ[i] - m_Image_Corrections(nIndex),
7415  m_Image_Corrections(nIndex), coefZ[i],
7416  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7417  }
7418  fp_out << buf;
7419  ostr.str("");
7420  strcoeff--;
7421  nIndex++;
7422  }
7423  }
7424 
7425  else {
7426  sprintf(buf, " X%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefX[0], 0.0, coefX[0], 0.0, "N/A");
7427  fp_out << buf;
7428  sprintf(buf, " Y%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefY[0], 0.0, coefY[0], 0.0, "N/A");
7429  fp_out << buf;
7430  sprintf(buf, " Z%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefZ[0], 0.0, coefZ[0], 0.0, "N/A");
7431  fp_out << buf;
7432  }
7433 
7434  if( m_nNumberCamAngleCoefSolved > 0 ) {
7435  char strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
7436  std::ostringstream ostr;
7437  for( int i = 0; i < m_nNumberCamAngleCoefSolved; i++ ) {
7438  if( i ==0 )
7439  ostr << " " << strcoeff;
7440  else if ( i == 1 )
7441  ostr << " " << strcoeff << "t";
7442  else
7443  ostr << strcoeff << "t" << i;
7444  if( bSolveSparse )
7445  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7446  else
7447  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7448  if( i == 0 ) {
7449  sprintf(buf, " RA (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7450  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
7451  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
7452  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7453  }
7454  else {
7455  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7456  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
7457  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
7458  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7459  }
7460  fp_out << buf;
7461  ostr.str("");
7462  strcoeff--;
7463  nIndex++;
7464  }
7465  strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
7466  for( int i = 0; i < m_nNumberCamAngleCoefSolved; i++ ) {
7467  if( i ==0 )
7468  ostr << " " << strcoeff;
7469  else if ( i == 1 )
7470  ostr << " " << strcoeff << "t";
7471  else
7472  ostr << strcoeff << "t" << i;
7473  if( bSolveSparse )
7474  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7475  else
7476  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7477  if( i == 0 ) {
7478  sprintf(buf, "DEC (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7479  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7480  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7481  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7482  }
7483  else {
7484  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7485  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7486  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7487  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7488  }
7489  fp_out << buf;
7490  ostr.str("");
7491  strcoeff--;
7492  nIndex++;
7493  }
7494  if ( !m_bSolveTwist ) {
7495  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7496  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7497  fp_out << buf;
7498  }
7499  else {
7500  strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
7501  for( int i = 0; i < m_nNumberCamAngleCoefSolved; i++ ) {
7502  if( i ==0 )
7503  ostr << " " << strcoeff;
7504  else if ( i == 1 )
7505  ostr << " " << strcoeff << "t";
7506  else
7507  ostr << strcoeff << "t" << i;
7508  if( bSolveSparse )
7509  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7510  else
7511  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7512  if( i == 0 ) {
7513  sprintf(buf, "TWI (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7514  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7515  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7516  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7517  }
7518  else {
7519  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7520  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7521  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7522  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7523  }
7524  fp_out << buf;
7525  ostr.str("");
7526  strcoeff--;
7527  nIndex++;
7528  }
7529  }
7530  }
7531 
7532  else {
7533  sprintf(buf, " RA%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7534  coefRA[0]*RAD2DEG, 0.0, coefRA[0]*RAD2DEG, 0.0, "N/A");
7535  fp_out << buf;
7536  sprintf(buf, " DEC%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7537  coefDEC[0]*RAD2DEG, 0.0, coefDEC[0]*RAD2DEG, 0.0, "N/A");
7538  fp_out << buf;
7539  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7540  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7541  fp_out << buf;
7542  }
7543  }
7544 /
7545  // output point data
7546  sprintf(buf, "\n\n\nPOINTS UNCERTAINTY SUMMARY\n==========================\n\n");
7547  fp_out << buf;
7548  sprintf(buf, " RMS Sigma Latitude(m)%20.8lf\n",
7549  m_drms_sigmaLat);
7550  fp_out << buf;
7551  sprintf(buf, " MIN Sigma Latitude(m)%20.8lf at %s\n",
7552  m_dminSigmaLatitude,m_idMinSigmaLatitude.toAscii().data());
7553  fp_out << buf;
7554  sprintf(buf, " MAX Sigma Latitude(m)%20.8lf at %s\n\n",
7555  m_dmaxSigmaLatitude,m_idMaxSigmaLatitude.toAscii().data());
7556  fp_out << buf;
7557  sprintf(buf, "RMS Sigma Longitude(m)%20.8lf\n",
7558  m_drms_sigmaLon);
7559  fp_out << buf;
7560  sprintf(buf, "MIN Sigma Longitude(m)%20.8lf at %s\n",
7561  m_dminSigmaLongitude,m_idMinSigmaLongitude.toAscii().data());
7562  fp_out << buf;
7563  sprintf(buf, "MAX Sigma Longitude(m)%20.8lf at %s\n\n",
7564  m_dmaxSigmaLongitude,m_idMaxSigmaLongitude.toAscii().data());
7565  fp_out << buf;
7566  if ( m_bSolveRadii ) {
7567  sprintf(buf, " RMS Sigma Radius(m)%20.8lf\n",
7568  m_drms_sigmaRad);
7569  fp_out << buf;
7570  sprintf(buf, " MIN Sigma Radius(m)%20.8lf at %s\n",
7571  m_dminSigmaRadius,m_idMinSigmaRadius.toAscii().data());
7572  fp_out << buf;
7573  sprintf(buf, " MAX Sigma Radius(m)%20.8lf at %s\n",
7574  m_dmaxSigmaRadius,m_idMaxSigmaRadius.toAscii().data());
7575  fp_out << buf;
7576  }
7577  else {
7578  sprintf(buf, " RMS Sigma Radius(m) N/A\n");
7579  fp_out << buf;
7580  sprintf(buf, " MIN Sigma Radius(m) N/A\n");
7581  fp_out << buf;
7582  sprintf(buf, " MAX Sigma Radius(m) N/A\n");
7583  fp_out << buf;
7584  }
7585 
7586  // output point data
7587  sprintf(buf, "\n\nPOINTS SUMMARY\n==============\n%103sSigma Sigma Sigma\n"
7588  " Label Status Rays RMS Latitude Longitude Radius"
7589  " Latitude Longitude Radius\n", "");
7590  fp_out << buf;
7591 
7592  int nRays = 0;
7593  double dLat, dLon, dRadius;
7594  double dSigmaLat, dSigmaLong, dSigmaRadius;
7595  double cor_lat_dd, cor_lon_dd, cor_rad_m;
7596  double cor_lat_m, cor_lon_m;
7597  double dLatInit, dLonInit, dRadiusInit;
7598  int nGoodRays;
7599  double dResidualRms;
7600  QString strStatus;
7601  int nPointIndex = 0;
7602 
7603  int nPoints = m_pCnet->GetNumPoints();
7604  for ( int i = 0; i < nPoints; i++ ) {
7605 
7606  const ControlPoint *point = m_pCnet->GetPoint(i);
7607  if ( point->IsIgnored() )
7608  continue;
7609 
7610  nRays = point->GetNumMeasures();
7611  dResidualRms = point->GetResidualRms();
7612  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
7613  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
7614  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
7615  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
7616  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
7617  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
7618  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
7619 
7620  if (point->GetType() == ControlPoint::Fixed)
7621  strStatus = "FIXED";
7622  else if (point->GetType() == ControlPoint::Constrained)
7623  strStatus = "CONSTRAINED";
7624  else if (point->GetType() == ControlPoint::Free)
7625  strStatus = "FREE";
7626  else
7627  strStatus = "UNKNOWN";
7628 
7629  sprintf(buf, "%16s%15s%5d of %d%6.2lf%16.8lf%16.8lf%16.8lf%16.8lf%16.8lf%16.8lf\n",
7630  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays, dResidualRms, dLat,
7631  dLon, dRadius * 0.001, dSigmaLat, dSigmaLong, dSigmaRadius);
7632  fp_out << buf;
7633  nPointIndex++;
7634  }
7635 
7636  // output point data
7637  sprintf(buf, "\n\nPOINTS DETAIL\n=============\n\n");
7638  fp_out << buf;
7639 
7640  nPointIndex = 0;
7641  for ( int i = 0; i < nPoints; i++ ) {
7642 
7643  const ControlPoint *point = m_pCnet->GetPoint(i);
7644  if ( point->IsIgnored() )
7645  continue;
7646 
7647  nRays = point->GetNumMeasures();
7648  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
7649  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
7650  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
7651  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
7652  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
7653  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
7654  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
7655 
7656  // point corrections and initial sigmas
7657  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
7658  bounded_vector<double, 3>& apriorisigmas = m_Point_AprioriSigmas[nPointIndex];
7659 
7660  cor_lat_dd = corrections[0] * Isis::RAD2DEG;
7661  cor_lon_dd = corrections[1] * Isis::RAD2DEG;
7662  cor_rad_m = corrections[2] * 1000.0;
7663 
7664  cor_lat_m = corrections[0] * m_dRTM;
7665  cor_lon_m = corrections[1] * m_dRTM * cos(dLat*Isis::DEG2RAD);
7666 
7667  dLatInit = dLat - cor_lat_dd;
7668  dLonInit = dLon - cor_lon_dd;
7669  dRadiusInit = dRadius - (corrections[2] * 1000.0);
7670 
7671  if (point->GetType() == ControlPoint::Fixed)
7672  strStatus = "FIXED";
7673  else if (point->GetType() == ControlPoint::Constrained)
7674  strStatus = "CONSTRAINED";
7675  else if (point->GetType() == ControlPoint::Free)
7676  strStatus = "FREE";
7677  else
7678  strStatus = "UNKNOWN";
7679 
7680  sprintf(buf, " Label: %s\nStatus: %s\n Rays: %d of %d\n",
7681  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays);
7682  fp_out << buf;
7683 
7684  sprintf(buf, "\n Point Initial Total Total Final Initial Final\n"
7685  "Coordinate Value Correction Correction Value Accuracy Accuracy\n"
7686  " (dd/dd/km) (dd/dd/km) (Meters) (dd/dd/km) (Meters) (Meters)\n");
7687  fp_out << buf;
7688 
7689  sprintf(buf, " LATITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n",
7690  dLatInit, cor_lat_dd, cor_lat_m, dLat, apriorisigmas[0], dSigmaLat);
7691  fp_out << buf;
7692 
7693  sprintf(buf, " LONGITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n",
7694  dLonInit, cor_lon_dd, cor_lon_m, dLon, apriorisigmas[1], dSigmaLong);
7695  fp_out << buf;
7696 
7697  sprintf(buf, " RADIUS%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n\n",
7698  dRadiusInit * 0.001, corrections[2], cor_rad_m, dRadius * 0.001,
7699  apriorisigmas[2], dSigmaRadius);
7700 
7701  fp_out << buf;
7702  nPointIndex++;
7703  }
7704 
7705  fp_out.close();
7706 
7707  return true;
7708  }
7709 */
7710 
7722  bool BundleAdjust::OutputNoErrorPropagation() {
7723 
7724  QString ofname("bundleout.txt");
7725  if (!m_strOutputFilePrefix.isEmpty())
7726  ofname = m_strOutputFilePrefix + "_" + ofname;
7727 
7728  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
7729  if (!fp_out)
7730  return false;
7731 
7732  char buf[1056];
7733 
7734  //bool bHeld = false;
7735  std::vector<double> coefX(m_nNumberCamPosCoefSolved);
7736  std::vector<double> coefY(m_nNumberCamPosCoefSolved);
7737  std::vector<double> coefZ(m_nNumberCamPosCoefSolved);
7738  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved);
7739  std::vector<double> coefDEC(m_nNumberCamAngleCoefSolved);
7740  std::vector<double> coefTWI(m_nNumberCamAngleCoefSolved);
7741  std::vector<double> angles;
7742  Camera *pCamera = NULL;
7743  SpicePosition *pSpicePosition = NULL;
7744  SpiceRotation *pSpiceRotation = NULL;
7745  int nIndex = 0;
7746  int nImages = Images();
7747 
7748  OutputHeader(fp_out);
7749 
7750  sprintf(buf, "\nIMAGE EXTERIOR ORIENTATION ***J2000***\n======================================\n");
7751  fp_out << buf;
7752 
7753  for (int i = 0; i < nImages; i++) {
7754  //if (m_nHeldImages > 0 && m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i)))
7755  // bHeld = true;
7756 
7757  pCamera = m_pCnet->Camera(i);
7758  if (!pCamera)
7759  continue;
7760 
7761  nIndex = ImageIndex(i);
7762 
7763  pSpicePosition = pCamera->instrumentPosition();
7764  if (!pSpicePosition)
7765  continue;
7766 
7767  pSpiceRotation = pCamera->instrumentRotation();
7768  if (!pSpiceRotation)
7769  continue;
7770 
7771  // for frame cameras we directly retrieve the Exterior Orientation (i.e. position
7772  // and orientation angles). For others (linescan, radar) we retrieve the polynomial
7773  // coefficients from which the Exterior Orientation paramters are derived.
7774  // This is incorrect...Correction below
7775  // For all instruments we retrieve the polynomial coefficients from which the
7776  // Exterior Orientation parameters are derived. For framing cameras, a single
7777  // coefficient for each coordinate is returned.
7778  if (m_spacecraftPositionSolveType > 0)
7779  pSpicePosition->GetPolynomial(coefX,coefY,coefZ);
7780  // else { // frame camera
7781  else { // This is for m_spacecraftPositionSolveType = None and no polynomial fit has occurred
7782  std::vector <double> coordinate(3);
7783  coordinate = pSpicePosition->GetCenterCoordinate();
7784  coefX.push_back(coordinate[0]);
7785  coefY.push_back(coordinate[1]);
7786  coefZ.push_back(coordinate[2]);
7787  }
7788 
7789  if (m_cmatrixSolveType > 0) {
7790 // angles = pSpiceRotation->Angles(3,1,3);
7791  pSpiceRotation->GetPolynomial(coefRA,coefDEC,coefTWI);
7792  }
7793  else { // frame camera
7794  angles = pSpiceRotation->GetCenterAngles();
7795  coefRA.push_back(angles.at(0));
7796  coefDEC.push_back(angles.at(1));
7797  coefTWI.push_back(angles.at(2));
7798  }
7799 
7800  sprintf(buf, "\nImage Full File Name: %s\n", m_pSnList->fileName(i).toAscii().data());
7801  fp_out << buf;
7802  sprintf(buf, "\n Image Serial Number: %s\n", m_pSnList->serialNumber(i).toAscii().data());
7803  fp_out << buf;
7804  sprintf(buf, "\n Image Initial Total Final Initial Final\n"
7805  "Parameter Value Correction Value Accuracy Accuracy\n");
7806  fp_out << buf;
7807 
7808  if (m_nNumberCamPosCoefSolved > 0) {
7809  char strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
7810  std::ostringstream ostr;
7811  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
7812  if (i == 0)
7813  ostr << " " << strcoeff;
7814  else if (i == 1)
7815  ostr << " " << strcoeff << "t";
7816  else
7817  ostr << strcoeff << "t" << i;
7818  if (i == 0) {
7819  sprintf(buf, " X (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7820  ostr.str().c_str(), coefX[i] - m_Image_Corrections(nIndex),
7821  m_Image_Corrections(nIndex), coefX[i],
7822  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7823  }
7824  else {
7825  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7826  ostr.str().c_str(), coefX[i] - m_Image_Corrections(nIndex),
7827  m_Image_Corrections(nIndex), coefX[i],
7828  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7829  }
7830  fp_out << buf;
7831  ostr.str("");
7832  strcoeff--;
7833  nIndex++;
7834  }
7835  strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
7836  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
7837  if (i == 0)
7838  ostr << " " << strcoeff;
7839  else if (i == 1)
7840  ostr << " " << strcoeff << "t";
7841  else
7842  ostr << strcoeff << "t" << i;
7843  if (i == 0 ) {
7844  sprintf(buf, " Y (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7845  ostr.str().c_str(), coefY[i] - m_Image_Corrections(nIndex),
7846  m_Image_Corrections(nIndex), coefY[i],
7847  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7848  }
7849  else {
7850  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7851  ostr.str().c_str(), coefY[i] - m_Image_Corrections(nIndex),
7852  m_Image_Corrections(nIndex), coefY[i],
7853  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7854  }
7855  fp_out << buf;
7856  ostr.str("");
7857  strcoeff--;
7858  nIndex++;
7859  }
7860  strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
7861  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
7862  if (i == 0)
7863  ostr << " " << strcoeff;
7864  else if (i == 1)
7865  ostr << " " << strcoeff << "t";
7866  else
7867  ostr << strcoeff << "t" << i;
7868  if (i == 0) {
7869  sprintf(buf, " Z (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7870  ostr.str().c_str(), coefZ[i] - m_Image_Corrections(nIndex),
7871  m_Image_Corrections(nIndex), coefZ[i],
7872  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7873  }
7874  else {
7875  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7876  ostr.str().c_str(), coefZ[i] - m_Image_Corrections(nIndex),
7877  m_Image_Corrections(nIndex), coefZ[i],
7878  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7879  }
7880  fp_out << buf;
7881  ostr.str("");
7882  strcoeff--;
7883  nIndex++;
7884  }
7885  }
7886  else {
7887  sprintf(buf, " X%17.8lf%21.8lf%20.8lf%18s%18s\n", coefX[0], 0.0, coefX[0], "N/A", "N/A");
7888  fp_out << buf;
7889  sprintf(buf, " Y%17.8lf%21.8lf%20.8lf%18s%18s\n", coefY[0], 0.0, coefY[0], "N/A", "N/A");
7890  fp_out << buf;
7891  sprintf(buf, " Z%17.8lf%21.8lf%20.8lf%18s%18s\n", coefZ[0], 0.0, coefZ[0], "N/A", "N/A");
7892  fp_out << buf;
7893  }
7894 
7895  if (m_nNumberCamAngleCoefSolved > 0) {
7896  char strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
7897  std::ostringstream ostr;
7898  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
7899  if (i == 0)
7900  ostr << " " << strcoeff;
7901  else if (i == 1)
7902  ostr << " " << strcoeff << "t";
7903  else
7904  ostr << strcoeff << "t" << i;
7905  if (i == 0) {
7906  sprintf(buf, " RA (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7907  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
7908  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
7909  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7910  }
7911  else {
7912  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7913  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
7914  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
7915  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7916  }
7917  fp_out << buf;
7918  ostr.str("");
7919  strcoeff--;
7920  nIndex++;
7921  }
7922  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
7923  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
7924  if (i == 0)
7925  ostr << " " << strcoeff;
7926  else if (i == 1)
7927  ostr << " " << strcoeff << "t";
7928  else
7929  ostr << strcoeff << "t" << i;
7930  if (i == 0) {
7931  sprintf(buf, "DEC (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7932  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7933  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7934  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7935  }
7936  else {
7937  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7938  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7939  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7940  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7941  }
7942  fp_out << buf;
7943  ostr.str("");
7944  strcoeff--;
7945  nIndex++;
7946  }
7947  if (!m_bSolveTwist) {
7948  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7949  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7950  fp_out << buf;
7951  }
7952  else {
7953  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
7954  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
7955  if (i == 0)
7956  ostr << " " << strcoeff;
7957  else if (i == 1)
7958  ostr << " " << strcoeff << "t";
7959  else
7960  ostr << strcoeff << "t" << i;
7961  if (i == 0) {
7962  sprintf(buf, "TWI (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7963  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7964  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7965  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7966  }
7967  else {
7968  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7969  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7970  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7971  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7972  }
7973  fp_out << buf;
7974  ostr.str("");
7975  strcoeff--;
7976  nIndex++;
7977  }
7978  }
7979  }
7980  else {
7981  sprintf(buf, " RA%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7982  coefRA[0]*RAD2DEG, 0.0, coefRA[0]*RAD2DEG, 0.0, "N/A");
7983  fp_out << buf;
7984  sprintf(buf, " DEC%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7985  coefDEC[0]*RAD2DEG, 0.0, coefDEC[0]*RAD2DEG, 0.0, "N/A");
7986  fp_out << buf;
7987  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7988  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7989  fp_out << buf;
7990  }
7991  }
7992 
7993  fp_out << "\n\n\n";
7994 
7995  // output point data
7996  sprintf(buf,"\nPOINTS SUMMARY\n==============\n%99sSigma Sigma Sigma\n"
7997  " Label Status Rays RMS Latitude Longitude Radius"
7998  " Latitude Longitude Radius\n","");
7999  fp_out << buf;
8000 
8001  int nRays = 0;
8002  double dResidualRms;
8003  double dLat,dLon,dRadius;
8004  double cor_lat_dd,cor_lon_dd,cor_rad_m;
8005  double cor_lat_m,cor_lon_m;
8006  double dLatInit,dLonInit,dRadiusInit;
8007  int nGoodRays;
8008 
8009  QString strStatus;
8010 
8011  int nPoints = m_pCnet->GetNumPoints();
8012  for (int i = 0; i < nPoints; i++) {
8013 
8014  const ControlPoint* point = m_pCnet->GetPoint(i);
8015  if (point->IsIgnored())
8016  continue;
8017 
8018  nRays = point->GetNumMeasures();
8019  dResidualRms = point->GetResidualRms();
8020  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
8021  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
8022  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
8023  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
8024 
8025  if (point->GetType() == ControlPoint::Fixed)
8026  strStatus = "FIXED";
8027  else if (point->GetType() == ControlPoint::Constrained)
8028  strStatus = "CONSTRAINED";
8029  else if (point->GetType() == ControlPoint::Free)
8030  strStatus = "FREE";
8031  else
8032  strStatus = "UNKNOWN";
8033 
8034  sprintf(buf, "%16s%12s%4d of %d%6.2lf%16.8lf%16.8lf%16.8lf%11s%16s%16s\n",
8035  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays,
8036  dResidualRms, dLat, dLon, dRadius * 0.001,"N/A","N/A","N/A");
8037 
8038  fp_out << buf;
8039  }
8040 
8041  sprintf(buf,"\n\nPOINTS DETAIL\n=============\n\n");
8042  fp_out << buf;
8043 
8044  int nPointIndex = 0;
8045  for (int i = 0; i < nPoints; i++) {
8046 
8047  const ControlPoint* point = m_pCnet->GetPoint(i);
8048  if (point->IsIgnored())
8049  continue;
8050 
8051  nRays = point->GetNumMeasures();
8052  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
8053  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
8054  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
8055  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
8056 
8057  // point corrections and initial sigmas
8058  bounded_vector<double,3>& corrections = m_Point_Corrections[nPointIndex];
8059  bounded_vector<double,3>& apriorisigmas = m_Point_AprioriSigmas[nPointIndex];
8060 
8061  cor_lat_dd = corrections[0]*Isis::RAD2DEG;
8062  cor_lon_dd = corrections[1]*Isis::RAD2DEG;
8063  cor_rad_m = corrections[2]*1000.0;
8064 
8065  cor_lat_m = corrections[0]*m_dRTM;
8066  cor_lon_m = corrections[1]*m_dRTM*cos(dLat*Isis::DEG2RAD);
8067 
8068  dLatInit = dLat-cor_lat_dd;
8069  dLonInit = dLon-cor_lon_dd;
8070  dRadiusInit = dRadius-(corrections[2]*1000.0);
8071 
8072  if (point->GetType() == ControlPoint::Fixed)
8073  strStatus = "FIXED";
8074  else if (point->GetType() == ControlPoint::Constrained)
8075  strStatus = "CONSTRAINED";
8076  else if (point->GetType() == ControlPoint::Free)
8077  strStatus = "FREE";
8078  else
8079  strStatus = "UNKNOWN";
8080 
8081  sprintf(buf," Label: %s\nStatus: %s\n Rays: %d of %d\n",
8082  point->GetId().toAscii().data(),strStatus.toAscii().data(),nGoodRays,nRays);
8083  fp_out << buf;
8084 
8085  sprintf(buf,"\n Point Initial Total Total Final Initial Final\n"
8086  "Coordinate Value Correction Correction Value Accuracy Accuracy\n"
8087  " (dd/dd/km) (dd/dd/km) (Meters) (dd/dd/km) (Meters) (Meters)\n");
8088  fp_out << buf;
8089 
8090  sprintf(buf," LATITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18s\n",
8091  dLatInit, cor_lat_dd, cor_lat_m, dLat, apriorisigmas[0], "N/A");
8092  fp_out << buf;
8093 
8094  sprintf(buf," LONGITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18s\n",
8095  dLonInit, cor_lon_dd, cor_lon_m, dLon, apriorisigmas[1], "N/A");
8096  fp_out << buf;
8097 
8098  sprintf(buf," RADIUS%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18s\n\n",
8099  dRadiusInit*0.001, corrections[2], cor_rad_m, dRadius*0.001, apriorisigmas[2], "N/A");
8100 
8101  fp_out << buf;
8102 
8103  nPointIndex++;
8104  }
8105 
8106  fp_out.close();
8107 
8108  return true;
8109  }
8110 
8111 
8115  bool BundleAdjust::OutputPointsCSV() {
8116  char buf[1056];
8117 
8118  QString ofname("bundleout_points.csv");
8119  if (!m_strOutputFilePrefix.isEmpty())
8120  ofname = m_strOutputFilePrefix + "_" + ofname;
8121 
8122  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
8123  if (!fp_out)
8124  return false;
8125 
8126  int nPoints = m_pCnet->GetNumPoints();
8127 
8128  double dLat, dLon, dRadius;
8129  double dX, dY, dZ;
8130  double dSigmaLat, dSigmaLong, dSigmaRadius;
8131  QString strStatus;
8132  double cor_lat_m;
8133  double cor_lon_m;
8134  double cor_rad_m;
8135  int nMeasures, nRejectedMeasures;
8136  double dResidualRms;
8137 
8138  // print column headers
8139  if (m_bErrorPropagation) {
8140  sprintf(buf, "Point,Point,Accepted,Rejected,Residual,3-d,3-d,3-d,Sigma,"
8141  "Sigma,Sigma,Correction,Correction,Correction,Coordinate,"
8142  "Coordinate,Coordinate\nID,,,,,Latitude,Longitude,Radius,"
8143  "Latitude,Longitude,Radius,Latitude,Longitude,Radius,X,Y,Z\n"
8144  "Label,Status,Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),"
8145  "(m),(m),(m),(km),(km),(km)\n");
8146  }
8147  else {
8148  sprintf(buf, "Point,Point,Accepted,Rejected,Residual,3-d,3-d,3-d,"
8149  "Correction,Correction,Correction,Coordinate,Coordinate,"
8150  "Coordinate\n,,,,,Latitude,Longitude,Radius,Latitude,"
8151  "Longitude,Radius,X,Y,Z\nLabel,Status,Measures,Measures,"
8152  "RMS,(dd),(dd),(km),(m),(m),(m),(km),(km),(km)\n");
8153  }
8154  fp_out << buf;
8155 
8156  int nPointIndex = 0;
8157  for (int i = 0; i < nPoints; i++) {
8158  const ControlPoint *point = m_pCnet->GetPoint(i);
8159 
8160  if (!point)
8161  continue;
8162 
8163  if (point->IsIgnored() || point->IsRejected())
8164  continue;
8165 
8166  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
8167  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
8168  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().kilometers();
8169  dX = point->GetAdjustedSurfacePoint().GetX().kilometers();
8170  dY = point->GetAdjustedSurfacePoint().GetY().kilometers();
8171  dZ = point->GetAdjustedSurfacePoint().GetZ().kilometers();
8172  nMeasures = point->GetNumMeasures();
8173  nRejectedMeasures = point->GetNumberOfRejectedMeasures();
8174  dResidualRms = point->GetResidualRms();
8175 
8176  // point corrections and initial sigmas
8177  bounded_vector<double,3>& corrections = m_Point_Corrections[nPointIndex];
8178  cor_lat_m = corrections[0]*m_dRTM;
8179  cor_lon_m = corrections[1]*m_dRTM*cos(dLat*Isis::DEG2RAD);
8180  cor_rad_m = corrections[2]*1000.0;
8181 
8182  if (point->GetType() == ControlPoint::Fixed)
8183  strStatus = "FIXED";
8184  else if (point->GetType() == ControlPoint::Constrained)
8185  strStatus = "CONSTRAINED";
8186  else if (point->GetType() == ControlPoint::Free)
8187  strStatus = "FREE";
8188  else
8189  strStatus = "UNKNOWN";
8190 
8191  if (m_bErrorPropagation) {
8192  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
8193  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
8194  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
8195 
8196  sprintf(buf, "%s,%s,%d,%d,%6.2lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf\n",
8197  point->GetId().toAscii().data(), strStatus.toAscii().data(), nMeasures, nRejectedMeasures, dResidualRms, dLat, dLon, dRadius,
8198  dSigmaLat, dSigmaLong, dSigmaRadius, cor_lat_m, cor_lon_m, cor_rad_m, dX, dY, dZ);
8199  }
8200  else
8201  sprintf(buf, "%s,%s,%d,%d,%6.2lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf\n",
8202  point->GetId().toAscii().data(), strStatus.toAscii().data(), nMeasures, nRejectedMeasures, dResidualRms, dLat, dLon, dRadius,
8203  cor_lat_m, cor_lon_m, cor_rad_m, dX, dY, dZ);
8204 
8205  fp_out << buf;
8206 
8207  nPointIndex++;
8208  }
8209 
8210  fp_out.close();
8211 
8212  return true;
8213  }
8214 
8215 
8220  bool BundleAdjust::OutputResiduals() {
8221  char buf[1056];
8222 
8223  QString ofname("residuals.csv");
8224  if (!m_strOutputFilePrefix.isEmpty())
8225  ofname = m_strOutputFilePrefix + "_" + ofname;
8226 
8227  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
8228  if (!fp_out)
8229  return false;
8230 
8231  // output column headers
8232  sprintf(buf, ",,,x image,y image,Measured,Measured,sample,line,Residual Vector\n");
8233  fp_out << buf;
8234  sprintf(buf, "Point,Image,Image,coordinate,coordinate,Sample,Line,residual,residual,Magnitude\n");
8235  fp_out << buf;
8236  sprintf(buf, "Label,Filename,Serial Number,(mm),(mm),(pixels),(pixels),(pixels),(pixels),(pixels),Rejected\n");
8237  fp_out << buf;
8238 
8239  int nImageIndex;
8240 
8241  // printf("output residuals!!!\n");
8242 
8243  int nObjectPoints = m_pCnet->GetNumPoints();
8244  for (int i = 0; i < nObjectPoints; i++) {
8245  const ControlPoint *point = m_pCnet->GetPoint(i);
8246  if (point->IsIgnored())
8247  continue;
8248 
8249  int nObservations = point->GetNumMeasures();
8250  for (int j = 0; j < nObservations; j++) {
8251  const ControlMeasure *measure = point->GetMeasure(j);
8252  if (measure->IsIgnored())
8253  continue;
8254 
8255  Camera *pCamera = measure->Camera();
8256  if (!pCamera)
8257  continue;
8258 
8259  // Determine the image index
8260  nImageIndex = m_pSnList->serialNumberIndex(measure->GetCubeSerialNumber());
8261 
8262  if (measure->IsRejected())
8263  sprintf(buf, "%s,%s,%s,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,*\n",
8264  point->GetId().toAscii().data(), m_pSnList->fileName(nImageIndex).toAscii().data(), m_pSnList->serialNumber(nImageIndex).toAscii().data(),
8265  measure->GetFocalPlaneMeasuredX(), measure->GetFocalPlaneMeasuredY(), measure->GetSample(),
8266  measure->GetLine(), measure->GetSampleResidual(), measure->GetLineResidual(),
8267  measure->GetResidualMagnitude());
8268  else
8269  sprintf(buf, "%s,%s,%s,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf\n",
8270  point->GetId().toAscii().data(), m_pSnList->fileName(nImageIndex).toAscii().data(), m_pSnList->serialNumber(nImageIndex).toAscii().data(),
8271  measure->GetFocalPlaneMeasuredX(), measure->GetFocalPlaneMeasuredY(), measure->GetSample(),
8272  measure->GetLine(), measure->GetSampleResidual(), measure->GetLineResidual(), measure->GetResidualMagnitude());
8273  fp_out << buf;
8274  }
8275  }
8276 
8277  fp_out.close();
8278 
8279  return true;
8280  }
8281 
8285  bool BundleAdjust::OutputImagesCSV() {
8286  char buf[1056];
8287 
8288  QString ofname("bundleout_images.csv");
8289  if (!m_strOutputFilePrefix.isEmpty())
8290  ofname = m_strOutputFilePrefix + "_" + ofname;
8291 
8292  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
8293  if (!fp_out)
8294  return false;
8295 
8296  // setup column headers
8297  std::vector<QString> output_columns;
8298 
8299  output_columns.push_back("Image,");
8300 
8301  output_columns.push_back("rms,");
8302  output_columns.push_back("rms,");
8303  output_columns.push_back("rms,");
8304 
8305  char strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
8306  std::ostringstream ostr;
8307  int ncoeff = 1;
8308  if (m_nNumberCamPosCoefSolved > 0)
8309  ncoeff = m_nNumberCamPosCoefSolved;
8310 
8311  for (int i = 0; i < ncoeff; i++) {
8312  if (i == 0)
8313  ostr << strcoeff;
8314  else if (i == 1)
8315  ostr << strcoeff << "t";
8316  else
8317  ostr << strcoeff << "t" << i;
8318  for (int j = 0; j < 5; j++) {
8319  if (ncoeff == 1)
8320  output_columns.push_back("X,");
8321  else {
8322  QString str = "X(";
8323  str += ostr.str().c_str();
8324  str += "),";
8325  output_columns.push_back(str);
8326  }
8327  }
8328  ostr.str("");
8329  strcoeff--;
8330  }
8331  strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
8332  for (int i = 0; i < ncoeff; i++) {
8333  if (i == 0)
8334  ostr << strcoeff;
8335  else if (i == 1)
8336  ostr << strcoeff << "t";
8337  else
8338  ostr << strcoeff << "t" << i;
8339  for (int j = 0; j < 5; j++) {
8340  if (ncoeff == 1)
8341  output_columns.push_back("Y,");
8342  else {
8343  QString str = "Y(";
8344  str += ostr.str().c_str();
8345  str += "),";
8346  output_columns.push_back(str);
8347  }
8348  }
8349  ostr.str("");
8350  strcoeff--;
8351  }
8352  strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
8353  for (int i = 0; i < ncoeff; i++) {
8354  if (i == 0)
8355  ostr << strcoeff;
8356  else if (i == 1)
8357  ostr << strcoeff << "t";
8358  else
8359  ostr << strcoeff << "t" << i;
8360  for (int j = 0; j < 5; j++) {
8361  if (ncoeff == 1) {
8362  output_columns.push_back("Z,");
8363  }
8364  else {
8365  QString str = "Z(";
8366  str += ostr.str().c_str();
8367  str += "),";
8368  output_columns.push_back(str);
8369  }
8370  }
8371  ostr.str("");
8372  strcoeff--;
8373  if (!m_bSolveTwist)
8374  break;
8375  }
8376 
8377  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
8378  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8379  if(i == 0)
8380  ostr << strcoeff;
8381  else if (i == 1)
8382  ostr << strcoeff << "t";
8383  else
8384  ostr << strcoeff << "t" << i;
8385  for (int j = 0; j < 5; j++) {
8386  if (m_nNumberCamAngleCoefSolved == 1)
8387  output_columns.push_back("RA,");
8388  else {
8389  QString str = "RA(";
8390  str += ostr.str().c_str();
8391  str += "),";
8392  output_columns.push_back(str);
8393  }
8394  }
8395  ostr.str("");
8396  strcoeff--;
8397  }
8398  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
8399  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8400  if (i == 0)
8401  ostr << strcoeff;
8402  else if (i == 1)
8403  ostr << strcoeff << "t";
8404  else
8405  ostr << strcoeff << "t" << i;
8406  for (int j = 0; j < 5; j++) {
8407  if (m_nNumberCamAngleCoefSolved == 1)
8408  output_columns.push_back("DEC,");
8409  else {
8410  QString str = "DEC(";
8411  str += ostr.str().c_str();
8412  str += "),";
8413  output_columns.push_back(str);
8414  }
8415  }
8416  ostr.str("");
8417  strcoeff--;
8418  }
8419  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
8420  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8421  if (i == 0)
8422  ostr << strcoeff;
8423  else if (i == 1)
8424  ostr << strcoeff << "t";
8425  else
8426  ostr << strcoeff << "t" << i;
8427  for (int j = 0; j < 5; j++) {
8428  if (m_nNumberCamAngleCoefSolved == 1 || !m_bSolveTwist) {
8429  output_columns.push_back("TWIST,");
8430  }
8431  else {
8432  QString str = "TWIST(";
8433  str += ostr.str().c_str();
8434  str += "),";
8435  output_columns.push_back(str);
8436  }
8437  }
8438  ostr.str("");
8439  strcoeff--;
8440  if (!m_bSolveTwist)
8441  break;
8442  }
8443 
8444  // print first column header to buffer and output to file
8445  int ncolumns = output_columns.size();
8446  for (int i = 0; i < ncolumns; i++) {
8447  QString str = output_columns.at(i);
8448  sprintf(buf, "%s", (const char*)str.toAscii().data());
8449  fp_out << buf;
8450  }
8451  sprintf(buf, "\n");
8452  fp_out << buf;
8453 
8454  output_columns.clear();
8455  output_columns.push_back("Filename,");
8456 
8457  output_columns.push_back("sample res,");
8458  output_columns.push_back("line res,");
8459  output_columns.push_back("total res,");
8460 
8461  int nparams = 3;
8462  if (m_nNumberCamPosCoefSolved)
8463  nparams = 3 * m_nNumberCamPosCoefSolved;
8464 
8465  int numCameraAnglesSolved = 2;
8466  if (m_bSolveTwist) numCameraAnglesSolved++;
8467  nparams += numCameraAnglesSolved*m_nNumberCamAngleCoefSolved;
8468  if (!m_bSolveTwist) nparams += 1; // Report on twist only
8469  for (int i = 0; i < nparams; i++) {
8470  output_columns.push_back("Initial,");
8471  output_columns.push_back("Correction,");
8472  output_columns.push_back("Final,");
8473  output_columns.push_back("Apriori Sigma,");
8474  output_columns.push_back("Adj Sigma,");
8475  }
8476 
8477  // print second column header to buffer and output to file
8478  ncolumns = output_columns.size();
8479  for (int i = 0; i < ncolumns; i++) {
8480  QString str = output_columns.at(i);
8481  sprintf(buf, "%s", (const char*)str.toAscii().data());
8482  fp_out << buf;
8483  }
8484  sprintf(buf, "\n");
8485  fp_out << buf;
8486 
8487  Camera *pCamera = NULL;
8488  SpicePosition *pSpicePosition = NULL;
8489  SpiceRotation *pSpiceRotation = NULL;
8490 
8491  int nImages = Images();
8492  double dSigma = 0.;
8493  int nIndex = 0;
8494  bool bSolveSparse = false;
8495  //bool bHeld = false;
8496  std::vector<double> coefX(m_nNumberCamPosCoefSolved);
8497  std::vector<double> coefY(m_nNumberCamPosCoefSolved);
8498  std::vector<double> coefZ(m_nNumberCamPosCoefSolved);
8499  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved);
8500  std::vector<double> coefDEC(m_nNumberCamAngleCoefSolved);
8501  std::vector<double> coefTWI(m_nNumberCamAngleCoefSolved);
8502  std::vector<double> angles;
8503 
8504  output_columns.clear();
8505 
8506  gmm::row_matrix<gmm::rsvector<double> > lsqCovMatrix;
8507  if (m_strSolutionMethod == "OLDSPARSE" && m_bErrorPropagation) {
8508  // Get reference to the covariance matrix from the least-squares object
8509  lsqCovMatrix = m_pLsq->GetCovarianceMatrix();
8510  bSolveSparse = true;
8511  }
8512 
8513  // data structure to contain adjusted image parameter sigmas for CHOLMOD error propagation only
8514  vector<double> vImageAdjustedSigmas;
8515 
8516  std::vector<double> BFP(3);
8517 
8518  for (int i = 0; i < nImages; i++) {
8519 
8520  //if (m_nHeldImages > 0 &&
8521  // m_pHeldSnList->hasSerialNumber(m_pSnList->serialNumber(i)) )
8522  // bHeld = true;
8523 
8524  pCamera = m_pCnet->Camera(i);
8525  if (!pCamera)
8526  continue;
8527 
8528  // ImageIndex(i) retrieves index into the normal equations matrix for
8529  // Image(i)
8530  nIndex = ImageIndex(i) ;
8531 
8532  if (m_bErrorPropagation && m_bConverged && (m_decompositionMethod == CHOLMOD))
8533  vImageAdjustedSigmas = m_Image_AdjustedSigmas.at(i);
8534 
8535  pSpicePosition = pCamera->instrumentPosition();
8536  if (!pSpicePosition)
8537  continue;
8538 
8539  pSpiceRotation = pCamera->instrumentRotation();
8540  if (!pSpiceRotation)
8541  continue;
8542 
8543  // for frame cameras we directly retrieve the J2000 Exterior Orientation
8544  // (i.e. position and orientation angles). For others (linescan, radar)
8545  // we retrieve the polynomial coefficients from which the Exterior
8546  // Orientation parameters are derived.
8547  if (m_spacecraftPositionSolveType > 0)
8548  pSpicePosition->GetPolynomial(coefX, coefY, coefZ);
8549  else { // not solving for position so report state at center of image
8550  std::vector <double> coordinate(3);
8551  coordinate = pSpicePosition->GetCenterCoordinate();
8552 
8553  coefX.push_back(coordinate[0]);
8554  coefY.push_back(coordinate[1]);
8555  coefZ.push_back(coordinate[2]);
8556  }
8557 
8558  if (m_cmatrixSolveType > 0)
8559  pSpiceRotation->GetPolynomial(coefRA,coefDEC,coefTWI);
8560 // else { // frame camera
8561  else if (pCamera->GetCameraType() != 3) {
8562 // This is for m_cmatrixSolveType = None (except Radar which has no pointing)
8563 // and no polynomial fit has occurred
8564  angles = pSpiceRotation->GetCenterAngles();
8565  coefRA.push_back(angles.at(0));
8566  coefDEC.push_back(angles.at(1));
8567  coefTWI.push_back(angles.at(2));
8568  }
8569 
8570  // clear column vector
8571  output_columns.clear();
8572 
8573  // add filename
8574  output_columns.push_back(m_pSnList->fileName(i).toAscii().data());
8575 
8576  // add rms of sample, line, total image coordinate residuals
8577  output_columns.push_back(
8578  toString(m_rmsImageSampleResiduals[i].Rms()));
8579  output_columns.push_back(
8580  toString(m_rmsImageLineResiduals[i].Rms()));
8581  output_columns.push_back(
8582  toString(m_rmsImageResiduals[i].Rms()));
8583 
8584  int nSigmaIndex = 0;
8585  if (m_nNumberCamPosCoefSolved > 0) {
8586  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
8587 
8588  if (m_bErrorPropagation && m_bConverged) {
8589  if (bSolveSparse)
8590  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8591  else if (m_decompositionMethod == CHOLMOD)
8592  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8593  else if (m_decompositionMethod == SPECIALK)
8594  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8595  }
8596 
8597  output_columns.push_back(
8598  toString(coefX[0] - m_Image_Corrections(nIndex)));
8599  output_columns.push_back(
8600  toString(m_Image_Corrections(nIndex)));
8601  output_columns.push_back(
8602  toString(coefX[i]));
8603  output_columns.push_back(
8604  toString(m_dGlobalSpacecraftPositionAprioriSigma[i]));
8605 
8606  if (m_bErrorPropagation && m_bConverged)
8607  output_columns.push_back(
8608  toString(dSigma));
8609  else
8610  output_columns.push_back("N/A");
8611  nIndex++;
8612  nSigmaIndex++;
8613  }
8614  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
8615 
8616  if (m_bErrorPropagation && m_bConverged) {
8617  if (bSolveSparse)
8618  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8619  else if (m_decompositionMethod == CHOLMOD)
8620  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8621  else if (m_decompositionMethod == SPECIALK)
8622  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8623  }
8624 
8625  output_columns.push_back(
8626  toString(coefY[0] - m_Image_Corrections(nIndex)));
8627  output_columns.push_back(
8628  toString(m_Image_Corrections(nIndex)));
8629  output_columns.push_back(
8630  toString(coefY[i]));
8631  output_columns.push_back(
8632  toString(m_dGlobalSpacecraftPositionAprioriSigma[i]));
8633 
8634  if (m_bErrorPropagation && m_bConverged)
8635  output_columns.push_back(
8636  toString(dSigma));
8637  else
8638  output_columns.push_back("N/A");
8639  nIndex++;
8640  nSigmaIndex++;
8641  }
8642  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
8643 
8644  if (m_bErrorPropagation && m_bConverged) {
8645  if (bSolveSparse)
8646  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8647  else if (m_decompositionMethod == CHOLMOD)
8648  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8649  else if (m_decompositionMethod == SPECIALK)
8650  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8651  }
8652 
8653  output_columns.push_back(
8654  toString(coefZ[0] - m_Image_Corrections(nIndex)));
8655  output_columns.push_back(
8656  toString(m_Image_Corrections(nIndex)));
8657  output_columns.push_back(
8658  toString(coefZ[i]));
8659  output_columns.push_back(
8660  toString(m_dGlobalSpacecraftPositionAprioriSigma[i]));
8661 
8662  if (m_bErrorPropagation && m_bConverged)
8663  output_columns.push_back(toString
8664  (dSigma));
8665  else
8666  output_columns.push_back("N/A");
8667  nIndex++;
8668  nSigmaIndex++;
8669  }
8670  }
8671  else {
8672  output_columns.push_back(toString(coefX[0]));
8673  output_columns.push_back(toString(0));
8674  output_columns.push_back(toString(coefX[0]));
8675  output_columns.push_back(toString(0));
8676  output_columns.push_back("N/A");
8677  output_columns.push_back(toString(coefY[0]));
8678  output_columns.push_back(toString(0));
8679  output_columns.push_back(toString(coefY[0]));
8680  output_columns.push_back(toString(0));
8681  output_columns.push_back("N/A");
8682  output_columns.push_back(toString(coefZ[0]));
8683  output_columns.push_back(toString(0));
8684  output_columns.push_back(toString(coefZ[0]));
8685  output_columns.push_back(toString(0));
8686  output_columns.push_back("N/A");
8687  }
8688 
8689  if (m_nNumberCamAngleCoefSolved > 0) {
8690  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8691 
8692  if (m_bErrorPropagation && m_bConverged) {
8693  if (bSolveSparse)
8694  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8695  else if (m_decompositionMethod == CHOLMOD)
8696  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8697  else if (m_decompositionMethod == SPECIALK)
8698  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8699  }
8700 
8701  output_columns.push_back(toString
8702  ((coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG));
8703  output_columns.push_back(toString
8704  (m_Image_Corrections(nIndex) * RAD2DEG));
8705  output_columns.push_back(toString
8706  (coefRA[i] * RAD2DEG));
8707  output_columns.push_back(toString(
8708  m_dGlobalCameraAnglesAprioriSigma[i]));
8709 
8710  if (m_bErrorPropagation && m_bConverged)
8711  output_columns.push_back(toString
8712  (dSigma * RAD2DEG));
8713  else
8714  output_columns.push_back("N/A");
8715  nIndex++;
8716  nSigmaIndex++;
8717  }
8718  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8719 
8720  if (m_bErrorPropagation && m_bConverged) {
8721  if (bSolveSparse)
8722  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8723  else if (m_decompositionMethod == CHOLMOD)
8724  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8725  else if (m_decompositionMethod == SPECIALK)
8726  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8727  }
8728 
8729  output_columns.push_back(toString
8730  ((coefDEC[i] - m_Image_Corrections(nIndex)) * RAD2DEG));
8731  output_columns.push_back(toString
8732  (m_Image_Corrections(nIndex) * RAD2DEG));
8733  output_columns.push_back(toString
8734  (coefDEC[i] * RAD2DEG));
8735  output_columns.push_back(toString
8736  (m_dGlobalCameraAnglesAprioriSigma[i]));
8737 
8738  if (m_bErrorPropagation && m_bConverged)
8739  output_columns.push_back(toString
8740  (dSigma * RAD2DEG));
8741  else
8742  output_columns.push_back("N/A");
8743  nIndex++;
8744  nSigmaIndex++;
8745  }
8746  if (!m_bSolveTwist) {
8747  output_columns.push_back(toString
8748  (coefTWI[0]*RAD2DEG));
8749  output_columns.push_back(toString(0.0));
8750  output_columns.push_back(toString
8751  (coefTWI[0]*RAD2DEG));
8752  output_columns.push_back(toString(0.0));
8753  output_columns.push_back("N/A");
8754  }
8755  else {
8756  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8757 
8758  if (m_bErrorPropagation && m_bConverged) {
8759  if (bSolveSparse)
8760  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8761  else if (m_decompositionMethod == CHOLMOD)
8762  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8763  else if (m_decompositionMethod == SPECIALK)
8764  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8765  }
8766 
8767  output_columns.push_back(toString
8768  ((coefTWI[i] - m_Image_Corrections(nIndex)) * RAD2DEG));
8769  output_columns.push_back(toString
8770  (m_Image_Corrections(nIndex) * RAD2DEG));
8771  output_columns.push_back(toString
8772  (coefTWI[i] * RAD2DEG));
8773  output_columns.push_back(toString
8774  (m_dGlobalCameraAnglesAprioriSigma[i]));
8775 
8776  if (m_bErrorPropagation && m_bConverged)
8777  output_columns.push_back(toString
8778  (dSigma * RAD2DEG));
8779  else
8780  output_columns.push_back("N/A");
8781  nIndex++;
8782  nSigmaIndex++;
8783  }
8784  }
8785  }
8786 
8787  else if (pCamera->GetCameraType() != 3) {
8788  output_columns.push_back(toString
8789  (coefRA[0]*RAD2DEG));
8790  output_columns.push_back(toString(0.0));
8791  output_columns.push_back(toString
8792  (coefRA[0]*RAD2DEG));
8793  output_columns.push_back(toString(0.0));
8794  output_columns.push_back("N/A");
8795  output_columns.push_back(toString
8796  (coefDEC[0]*RAD2DEG));
8797  output_columns.push_back(toString(0.0));
8798  output_columns.push_back(toString
8799  (coefDEC[0]*RAD2DEG));
8800  output_columns.push_back(toString(0.0));
8801  output_columns.push_back("N/A");
8802  output_columns.push_back(toString
8803  (coefTWI[0]*RAD2DEG));
8804  output_columns.push_back(toString(0.0));
8805  output_columns.push_back(toString
8806  (coefTWI[0]*RAD2DEG));
8807  output_columns.push_back(toString(0.0));
8808  output_columns.push_back("N/A");
8809  }
8810 
8811  // print column vector to buffer and output to file
8812  int ncolumns = output_columns.size();
8813  for (int i = 0; i < ncolumns; i++) {
8814  QString str = output_columns.at(i);
8815 
8816  if (i < ncolumns-1)
8817  sprintf(buf, "%s,", (const char*)str.toAscii().data());
8818  else
8819  sprintf(buf, "%s", (const char*)str.toAscii().data());
8820  fp_out << buf;
8821  }
8822  sprintf(buf, "\n");
8823  fp_out << buf;
8824  }
8825 
8826  fp_out.close();
8827 
8828  return true;
8829  }
8830 
8831 
8836  void BundleAdjust::SetSolutionMethod(QString str) {
8837  m_strSolutionMethod = str;
8838  FillPointIndexMap();
8839  }
8840 
8841 
8845  void BundleAdjust::maximumLikelihoodSetup( QList<QString> models, QList<double> quantiles ) {
8846  m_wFunc[0]=m_wFunc[1]=m_wFunc[2]=NULL; //initialize to NULL
8847  m_maxLikelihoodFlag[0]=m_maxLikelihoodFlag[1]=m_maxLikelihoodFlag[2]=false; //NULL flag by defualt
8848  if (models.size() == 0) { //MaximumLikeliHood Estimation not being used, so leave everything NULL
8849  m_cumPro=NULL;
8850  }
8851  else {
8852  m_cumPro = new StatCumProbDistDynCalc;
8853  m_cumPro->setQuantiles(101); //set up the cum probibility solver to have a node at every percent of the distribution
8854  for (int i=0;i<models.size() && i<3;i++) {
8855  m_maxLikelihoodFlag[i] = true;
8856  m_wFunc[i] = new MaximumLikelihoodWFunctions;
8857  if (models[i].compare("HUBER") == 0)
8858  m_wFunc[i]->setModel(MaximumLikelihoodWFunctions::Huber);
8859  else if (models[i].compare("HUBER_MODIFIED") == 0)
8860  m_wFunc[i]->setModel(MaximumLikelihoodWFunctions::HuberModified);
8861  else if (models[i].compare("WELSCH") == 0)
8862  m_wFunc[i]->setModel(MaximumLikelihoodWFunctions::Welsch);
8863  else if (models[i].compare("CHEN") == 0)
8864  m_wFunc[i]->setModel(MaximumLikelihoodWFunctions::Chen);
8865  else {
8866  QString msg = "Unsuported Maximum Likelihood estimation model: " + models[i] + "\n";
8867  m_maxLikelihoodFlag[i] = false;
8868  throw IException(IException::Io, msg, _FILEINFO_);
8869  }
8870  }
8871  }
8872  for (int i=0;i<quantiles.size() && i<3;i++)
8873  m_maxLikelihoodQuan[i] = quantiles[i];
8874 
8875  //maximum likelihood estimation tiered solutions requiring multiple convergeances are support,
8876  // this index keeps track of which tier the solution is in
8877  m_maxLikelihoodIndex=0;
8878  }
8879 }