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->initialize(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->initialize(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->initialize(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->initialize(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->initialize(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->initialize(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: ");
6484  fp_out << buf;
6485  m_wFunc[tier]->maximumLikelihoodModel(buf);
6486  fp_out << buf;
6487  sprintf(buf, "\n Quantile used for tweaking constant: %lf",m_maxLikelihoodQuan[tier]);
6488  fp_out << buf;
6489  sprintf(buf, "\n Quantile weighted R^2 Residual value: %lf",m_wFunc[tier]->tweakingConstant());
6490  fp_out << buf;
6491  sprintf(buf, "\n Approx. weighted Residual cutoff: ");
6492  fp_out << buf;
6493  m_wFunc[tier]->weightedResidualCutoff(buf);
6494  fp_out << buf;
6495  if (tier != 2) fp_out << "\n";
6496  }
6497  else {
6498  sprintf(buf, "\n Tier %d Enabled: FALSE",tier);
6499  fp_out << buf;
6500  }
6501  }
6502  sprintf(buf, "\n\nINPUT: CONVERGENCE CRITERIA\n===========================\n");
6503  fp_out << buf;
6504  sprintf(buf,"\n SIGMA0: %e",m_dConvergenceThreshold);
6505  fp_out << buf;
6506  sprintf(buf,"\n MAXIMUM ITERATIONS: %d",m_nMaxIterations);
6507  fp_out << buf;
6508  sprintf(buf, "\n\nINPUT: CAMERA POINTING OPTIONS\n==============================\n");
6509  fp_out << buf;
6510  switch (m_cmatrixSolveType) {
6511  case BundleAdjust::AnglesOnly:
6512  sprintf(buf,"\n CAMSOLVE: ANGLES");
6513  break;
6514  case BundleAdjust::AnglesVelocity:
6515  sprintf(buf,"\n CAMSOLVE: ANGLES, VELOCITIES");
6516  break;
6517  case BundleAdjust::AnglesVelocityAcceleration:
6518  sprintf(buf,"\n CAMSOLVE: ANGLES, VELOCITIES, ACCELERATIONS");
6519  break;
6520  case BundleAdjust::CKAll:
6521  sprintf(buf,"\n CAMSOLVE: ALL POLYNOMIAL COEFFICIENTS (%d)",m_nsolveCKDegree);
6522  break;
6523  case BundleAdjust::None:
6524  sprintf(buf,"\n CAMSOLVE: NONE");
6525  break;
6526  default:
6527  break;
6528  }
6529  fp_out << buf;
6530  m_bSolveTwist ? sprintf(buf, "\n TWIST: ON"):
6531  sprintf(buf, "\n TWIST: OFF");
6532  fp_out << buf;
6533 
6534  m_bSolvePolyOverPointing ? sprintf(buf, "\n POLYNOMIAL OVER EXISTING POINTING: ON"):
6535  sprintf(buf, "\nPOLYNOMIAL OVER EXISTING POINTING : OFF");
6536  fp_out << buf;
6537 
6538  sprintf(buf, "\n\nINPUT: SPACECRAFT OPTIONS\n=========================\n");
6539  fp_out << buf;
6540  switch (m_spacecraftPositionSolveType) {
6541  case Nothing:
6542  sprintf(buf,"\n SPSOLVE: NONE");
6543  break;
6544  case PositionOnly:
6545  sprintf(buf,"\n SPSOLVE: POSITION");
6546  break;
6547  case PositionVelocity:
6548  sprintf(buf,"\n SPSOLVE: POSITION, VELOCITIES");
6549  break;
6550  case PositionVelocityAcceleration:
6551  sprintf(buf,"\n SPSOLVE: POSITION, VELOCITIES, ACCELERATIONS");
6552  break;
6553  case BundleAdjust::SPKAll:
6554  sprintf(buf,"\n CAMSOLVE: ALL POLYNOMIAL COEFFICIENTS (%d)",m_nsolveSPKDegree);
6555  break;
6556  default:
6557  break;
6558  }
6559  fp_out << buf;
6560 
6561  m_bSolvePolyOverHermite ? sprintf(buf, "\n POLYNOMIAL OVER HERMITE SPLINE: ON"):
6562  sprintf(buf, "\nPOLYNOMIAL OVER HERMITE SPLINE : OFF");
6563  fp_out << buf;
6564 
6565  sprintf(buf, "\n\nINPUT: GLOBAL IMAGE PARAMETER UNCERTAINTIES\n===========================================\n");
6566  fp_out << buf;
6567  (m_dGlobalLatitudeAprioriSigma == -1) ? sprintf(buf,"\n POINT LATITUDE SIGMA: N/A"):
6568  sprintf(buf,"\n POINT LATITUDE SIGMA: %lf (meters)",m_dGlobalLatitudeAprioriSigma);
6569  fp_out << buf;
6570  (m_dGlobalLongitudeAprioriSigma == -1) ? sprintf(buf,"\n POINT LONGITUDE SIGMA: N/A"):
6571  sprintf(buf,"\n POINT LONGITUDE SIGMA: %lf (meters)",m_dGlobalLongitudeAprioriSigma);
6572  fp_out << buf;
6573  (m_dGlobalRadiusAprioriSigma == -1) ? sprintf(buf,"\n POINT RADIUS SIGMA: N/A"):
6574  sprintf(buf,"\n POINT RADIUS SIGMA: %lf (meters)",m_dGlobalRadiusAprioriSigma);
6575  fp_out << buf;
6576 
6577  if (m_nNumberCamPosCoefSolved < 1 || m_dGlobalSpacecraftPositionAprioriSigma[0] == -1)
6578  sprintf(buf,"\n SPACECRAFT POSITION SIGMA: N/A");
6579  else
6580  sprintf(buf,"\n SPACECRAFT POSITION SIGMA: %lf (meters)",m_dGlobalSpacecraftPositionAprioriSigma[0]);
6581  fp_out << buf;
6582 
6583  if (m_nNumberCamPosCoefSolved < 2 || m_dGlobalSpacecraftPositionAprioriSigma[1] == -1)
6584  sprintf(buf,"\n SPACECRAFT VELOCITY SIGMA: N/A");
6585  else
6586  sprintf(buf,"\n SPACECRAFT VELOCITY SIGMA: %lf (m/s)",m_dGlobalSpacecraftPositionAprioriSigma[1]);
6587  fp_out << buf;
6588 
6589  if (m_nNumberCamPosCoefSolved < 3 || m_dGlobalSpacecraftPositionAprioriSigma[2] == -1)
6590  sprintf(buf,"\n SPACECRAFT ACCELERATION SIGMA: N/A");
6591  else
6592  sprintf(buf,"\n SPACECRAFT ACCELERATION SIGMA: %lf (m/s/s)",m_dGlobalSpacecraftPositionAprioriSigma[2]);
6593  fp_out << buf;
6594 
6595  if (m_nNumberCamAngleCoefSolved < 1 || m_dGlobalCameraAnglesAprioriSigma[0] == -1)
6596  sprintf(buf,"\n CAMERA ANGLES SIGMA: N/A");
6597  else
6598  sprintf(buf,"\n CAMERA ANGLES SIGMA: %lf (dd)",m_dGlobalCameraAnglesAprioriSigma[0]);
6599  fp_out << buf;
6600 
6601  if (m_nNumberCamAngleCoefSolved < 2 || m_dGlobalCameraAnglesAprioriSigma[1] == -1)
6602  sprintf(buf,"\n CAMERA ANGULAR VELOCITY SIGMA: N/A");
6603  else
6604  sprintf(buf,"\n CAMERA ANGULAR VELOCITY SIGMA: %lf (dd/s)",m_dGlobalCameraAnglesAprioriSigma[1]);
6605  fp_out << buf;
6606 
6607  if (m_nNumberCamAngleCoefSolved < 3 || m_dGlobalCameraAnglesAprioriSigma[2] == -1)
6608  sprintf(buf,"\n CAMERA ANGULAR ACCELERATION SIGMA: N/A");
6609  else
6610  sprintf(buf,"\n CAMERA ANGULAR ACCELERATION SIGMA: %lf (dd/s/s)",m_dGlobalCameraAnglesAprioriSigma[2]);
6611  fp_out << buf;
6612 
6613  sprintf(buf, "\n\nJIGSAW: RESULTS\n===============\n");
6614  fp_out << buf;
6615  sprintf(buf,"\n Images: %6d",nImages);
6616  fp_out << buf;
6617  sprintf(buf,"\n Points: %6d",nValidPoints);
6618  fp_out << buf;
6619  sprintf(buf,"\n Total Measures: %6d",(m_nObservations+m_nRejectedObservations)/2);
6620  fp_out << buf;
6621  sprintf(buf,"\n Total Observations: %6d",m_nObservations+m_nRejectedObservations);
6622  fp_out << buf;
6623  sprintf(buf,"\n Good Observations: %6d",m_nObservations);
6624  fp_out << buf;
6625  sprintf(buf,"\n Rejected Observations: %6d",m_nRejectedObservations);
6626  fp_out << buf;
6627 
6628  if (m_nConstrainedPointParameters > 0) {
6629  sprintf(buf, "\n Constrained Point Parameters: %6d",m_nConstrainedPointParameters);
6630  fp_out << buf;
6631  }
6632  if (m_nConstrainedImageParameters > 0) {
6633  sprintf(buf, "\n Constrained Image Parameters: %6d",m_nConstrainedImageParameters);
6634  fp_out << buf;
6635  }
6636  sprintf(buf,"\n Unknowns: %6d",m_nUnknownParameters);
6637  fp_out << buf;
6638  if (nInnerConstraints > 0) {
6639  sprintf(buf, "\n Inner Constraints: %6d",nInnerConstraints);
6640  fp_out << buf;
6641  }
6642  if (nDistanceConstraints > 0) {
6643  sprintf(buf, "\n Distance Constraints: %d",nDistanceConstraints);
6644  fp_out << buf;
6645  }
6646 
6647  sprintf(buf,"\n Degrees of Freedom: %6d",nDegreesOfFreedom);
6648  fp_out << buf;
6649  sprintf(buf,"\n Convergence Criteria: %6.3g",m_dConvergenceThreshold);
6650  fp_out << buf;
6651 
6652  if (nConvergenceCriteria == 1) {
6653  sprintf(buf, "(Sigma0)");
6654  fp_out << buf;
6655  }
6656 
6657  sprintf(buf, "\n Iterations: %6d",m_nIteration);
6658  fp_out << buf;
6659 
6660  if (m_nIteration >= m_nMaxIterations) {
6661  sprintf(buf, "(Maximum reached)");
6662  fp_out << buf;
6663  }
6664 
6665  sprintf(buf, "\n Sigma0: %30.20lf\n",m_dSigma0);
6666  fp_out << buf;
6667  sprintf(buf, " Error Propagation Elapsed Time: %6.4lf (seconds)\n",m_dElapsedTimeErrorProp);
6668  fp_out << buf;
6669  sprintf(buf, " Total Elapsed Time: %6.4lf (seconds)\n",m_dElapsedTime);
6670  fp_out << buf;
6671  if (m_nObservations+m_nRejectedObservations > 100) { //if there was enough data to calculate percentiles and box plot data
6672  sprintf(buf, "\n Residual Percentiles:\n");
6673  fp_out << buf;
6674  try {
6675  for (int bin=1;bin<34;bin++) {
6676  //double quan = m_cumProRes->value(double(bin)/100);
6677  sprintf(buf, " Percentile %3d: %+8.3lf Percentile %3d: %+8.3lf Percentile %3d: %+8.3lf\n",bin ,m_cumProRes->value(double(bin )/100.0),
6678  bin+33,m_cumProRes->value(double(bin+33)/100.0),
6679  bin+66,m_cumProRes->value(double(bin+66)/100.0));
6680  fp_out << buf;
6681  }
6682  }
6683  catch (IException &e) {
6684  QString msg = "Faiiled to output residual percentiles for bundleout";
6685  throw IException(e, IException::Io, msg, _FILEINFO_);
6686  }
6687  try {
6688  sprintf(buf, "\n Residual Box Plot:");
6689  fp_out << buf;
6690  sprintf(buf, "\n minimum: %+8.3lf",m_cumProRes->min());
6691  fp_out << buf;
6692  sprintf(buf, "\n Quartile 1: %+8.3lf",m_cumProRes->value(0.25));
6693  fp_out << buf;
6694  sprintf(buf, "\n Median: %+8.3lf",m_cumProRes->value(0.50));
6695  fp_out << buf;
6696  sprintf(buf, "\n Quartile 3: %+8.3lf",m_cumProRes->value(0.75));
6697  fp_out << buf;
6698  sprintf(buf, "\n maximum: %+8.3lf\n",m_cumProRes->max());
6699  fp_out << buf;
6700  }
6701  catch (IException &e) {
6702  QString msg = "Faiiled to output residual box plot for bundleout";
6703  throw IException(e, IException::Io, msg, _FILEINFO_);
6704  }
6705  }
6706 
6707  sprintf(buf,"\nIMAGE MEASURES SUMMARY\n==========================\n\n");
6708  fp_out << buf;
6709 
6710  int nMeasures;
6711  int nRejectedMeasures;
6712  int nUsed;
6713 
6714  for (int i = 0; i < nImages; i++) {
6715  // ImageIndex(i) retrieves index into the normal equations matrix
6716  // for Image(i)
6717  double rmsSampleResiduals = m_rmsImageSampleResiduals[i].Rms();
6718  double rmsLineResiduals = m_rmsImageLineResiduals[i].Rms();
6719  double rmsLandSResiduals = m_rmsImageResiduals[i].Rms();
6720 
6721  nMeasures = m_pCnet->GetNumberOfValidMeasuresInImage(m_pSnList->SerialNumber(i));
6722  nRejectedMeasures =
6723  m_pCnet->GetNumberOfJigsawRejectedMeasuresInImage(m_pSnList->SerialNumber(i));
6724 
6725  nUsed = nMeasures - nRejectedMeasures;
6726 
6727  if (nUsed == nMeasures)
6728  sprintf(buf,"%s %5d of %5d %6.3lf %6.3lf %6.3lf\n",
6729  m_pSnList->FileName(i).toAscii().data(),
6730  (nMeasures-nRejectedMeasures), nMeasures,
6731  rmsSampleResiduals,rmsLineResiduals,rmsLandSResiduals);
6732  else
6733  sprintf(buf,"%s %5d of %5d* %6.3lf %6.3lf %6.3lf\n",
6734  m_pSnList->FileName(i).toAscii().data(),
6735  (nMeasures-nRejectedMeasures), nMeasures,
6736  rmsSampleResiduals,rmsLineResiduals,rmsLandSResiduals);
6737  fp_out << buf;
6738  }
6739 
6740  return true;
6741  }
6742 
6743 
6747  bool BundleAdjust::OutputWithErrorPropagation() {
6748 
6749  QString ofname("bundleout.txt");
6750  if( m_strOutputFilePrefix.length() != 0 )
6751  ofname = m_strOutputFilePrefix + "_" + ofname;
6752 
6753  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
6754  if (!fp_out)
6755  return false;
6756 
6757  char buf[1056];
6758  std::vector<double> coefX(m_nNumberCamPosCoefSolved);
6759  std::vector<double> coefY(m_nNumberCamPosCoefSolved);
6760  std::vector<double> coefZ(m_nNumberCamPosCoefSolved);
6761  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved);
6762  std::vector<double> coefDEC(m_nNumberCamAngleCoefSolved);
6763  std::vector<double> coefTWI(m_nNumberCamAngleCoefSolved);
6764  std::vector<double> angles;
6765  Camera *pCamera = NULL;
6766  SpicePosition *pSpicePosition = NULL;
6767  SpiceRotation *pSpiceRotation = NULL;
6768 
6769  int nImages = Images();
6770  double dSigma=0;
6771  int nIndex = 0;
6772  bool bSolveSparse = false;
6773 
6774  gmm::row_matrix<gmm::rsvector<double> > lsqCovMatrix;
6775 
6776  if (m_strSolutionMethod == "OLDSPARSE") {
6777  lsqCovMatrix = m_pLsq->GetCovarianceMatrix(); // get reference to the covariance matrix from the least-squares object
6778  bSolveSparse = true;
6779  }
6780 
6781  // data structure to contain adjusted image parameter sigmas for CHOLMOD error propagation only
6782  vector<double> vImageAdjustedSigmas;
6783 
6784  OutputHeader(fp_out);
6785 
6786  sprintf(buf, "\nIMAGE EXTERIOR ORIENTATION\n==========================\n");
6787  fp_out << buf;
6788 
6789  for (int i = 0; i < nImages; i++) {
6790 
6791  //if ( m_nHeldImages > 0 && m_pHeldSnList->HasSerialNumber(m_pSnList->SerialNumber(i)) )
6792  // bHeld = true;
6793 
6794  pCamera = m_pCnet->Camera(i);
6795  if (!pCamera)
6796  continue;
6797 
6798  // ImageIndex(i) retrieves index into the normal equations matrix for Image(i)
6799  nIndex = ImageIndex(i);
6800 
6801  if (m_decompositionMethod == CHOLMOD)
6802  vImageAdjustedSigmas = m_Image_AdjustedSigmas.at(i);
6803 
6804  pSpicePosition = pCamera->instrumentPosition();
6805  if (!pSpicePosition)
6806  continue;
6807 
6808  pSpiceRotation = pCamera->instrumentRotation();
6809  if (!pSpiceRotation)
6810  continue;
6811 
6812  // for frame cameras we directly retrieve the Exterior Orientation (i.e. position
6813  // and orientation angles). For others (linescan, radar) we retrieve the polynomial
6814  // coefficients from which the Exterior Orientation parameters are derived.
6815  if (m_spacecraftPositionSolveType > 0)
6816  pSpicePosition->GetPolynomial(coefX, coefY, coefZ);
6817  else { // not solving for position
6818  std::vector <double> coordinate(3);
6819  coordinate = pSpicePosition->GetCenterCoordinate();
6820  coefX.push_back(coordinate[0]);
6821  coefY.push_back(coordinate[1]);
6822  coefZ.push_back(coordinate[2]);
6823  }
6824 
6825  if (m_cmatrixSolveType > 0)
6826  pSpiceRotation->GetPolynomial(coefRA,coefDEC,coefTWI);
6827  // else { // frame camera
6828  else { // This is for m_cmatrixSolveType = None and no polynomial fit has occurred
6829  angles = pSpiceRotation->GetCenterAngles();
6830  coefRA.push_back(angles.at(0));
6831  coefDEC.push_back(angles.at(1));
6832  coefTWI.push_back(angles.at(2));
6833  }
6834 
6835  sprintf(buf, "\nImage Full File Name: %s\n", m_pSnList->FileName(i).toAscii().data());
6836  fp_out << buf;
6837  sprintf(buf, "\nImage Serial Number: %s\n", m_pSnList->SerialNumber(i).toAscii().data());
6838  fp_out << buf;
6839  sprintf(buf, "\n Image Initial Total Final Initial Final\n"
6840  "Parameter Value Correction Value Accuracy Accuracy\n");
6841  fp_out << buf;
6842 
6843  int nSigmaIndex = 0;
6844 
6845  if (m_nNumberCamPosCoefSolved > 0) {
6846  char strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
6847  std::ostringstream ostr;
6848  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
6849  if (i == 0)
6850  ostr << " " << strcoeff;
6851  else if (i == 1)
6852  ostr << " " << strcoeff << "t";
6853  else
6854  ostr << strcoeff << "t" << i;
6855  if (bSolveSparse)
6856  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6857  else if (m_decompositionMethod == CHOLMOD)
6858  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6859  else if (m_decompositionMethod == SPECIALK)
6860  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
6861  if (i == 0) {
6862  sprintf(buf, " X (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6863  ostr.str().c_str(),coefX[i] - m_Image_Corrections(nIndex),
6864  m_Image_Corrections(nIndex), coefX[i],
6865  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6866  }
6867  else {
6868  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6869  ostr.str().c_str(),coefX[i] - m_Image_Corrections(nIndex),
6870  m_Image_Corrections(nIndex), coefX[i],
6871  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6872  }
6873  fp_out << buf;
6874  ostr.str("");
6875  strcoeff--;
6876  nIndex++;
6877  nSigmaIndex++;
6878  }
6879  strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
6880  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
6881  if (i == 0)
6882  ostr << " " << strcoeff;
6883  else if (i == 1)
6884  ostr << " " << strcoeff << "t";
6885  else
6886  ostr << strcoeff << "t" << i;
6887  if (bSolveSparse)
6888  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6889  else if (m_decompositionMethod == CHOLMOD)
6890  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6891  else if (m_decompositionMethod == SPECIALK)
6892  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
6893  if (i == 0) {
6894  sprintf(buf, " Y (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6895  ostr.str().c_str(),coefY[i] - m_Image_Corrections(nIndex),
6896  m_Image_Corrections(nIndex), coefY[i],
6897  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6898  }
6899  else {
6900  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6901  ostr.str().c_str(),coefY[i] - m_Image_Corrections(nIndex),
6902  m_Image_Corrections(nIndex), coefY[i],
6903  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6904  }
6905  fp_out << buf;
6906  ostr.str("");
6907  strcoeff--;
6908  nIndex++;
6909  nSigmaIndex++;
6910  }
6911  strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
6912  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
6913  if ( i == 0 )
6914  ostr << " " << strcoeff;
6915  else if (i == 1)
6916  ostr << " " << strcoeff << "t";
6917  else
6918  ostr << strcoeff << "t" << i;
6919  if (bSolveSparse)
6920  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6921  else if (m_decompositionMethod == CHOLMOD)
6922  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6923  else if (m_decompositionMethod == SPECIALK)
6924  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
6925  if (i == 0) {
6926  sprintf(buf, " Z (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6927  ostr.str().c_str(),coefZ[i] - m_Image_Corrections(nIndex),
6928  m_Image_Corrections(nIndex), coefZ[i],
6929  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6930  }
6931  else {
6932  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6933  ostr.str().c_str(),coefZ[i] - m_Image_Corrections(nIndex),
6934  m_Image_Corrections(nIndex), coefZ[i],
6935  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
6936  }
6937  fp_out << buf;
6938  ostr.str("");
6939  strcoeff--;
6940  nIndex++;
6941  nSigmaIndex++;
6942  }
6943  }
6944 
6945  else {
6946  sprintf(buf, " X%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefX[0], 0.0, coefX[0], 0.0, "N/A");
6947  fp_out << buf;
6948  sprintf(buf, " Y%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefY[0], 0.0, coefY[0], 0.0, "N/A");
6949  fp_out << buf;
6950  sprintf(buf, " Z%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefZ[0], 0.0, coefZ[0], 0.0, "N/A");
6951  fp_out << buf;
6952  }
6953 
6954  if (m_nNumberCamAngleCoefSolved > 0) {
6955  char strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
6956  std::ostringstream ostr;
6957  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
6958  if (i == 0)
6959  ostr << " " << strcoeff;
6960  else if (i == 1)
6961  ostr << " " << strcoeff << "t";
6962  else
6963  ostr << strcoeff << "t" << i;
6964  if (bSolveSparse)
6965  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6966  else if (m_decompositionMethod == CHOLMOD)
6967  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
6968  else if (m_decompositionMethod == SPECIALK)
6969  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
6970  if (i == 0) {
6971  sprintf(buf, " RA (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6972  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
6973  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
6974  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
6975  }
6976  else {
6977  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
6978  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
6979  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
6980  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
6981  }
6982  fp_out << buf;
6983  ostr.str("");
6984  strcoeff--;
6985  nIndex++;
6986  nSigmaIndex++;
6987  }
6988  strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
6989  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
6990  if (i == 0)
6991  ostr << " " << strcoeff;
6992  else if (i == 1)
6993  ostr << " " << strcoeff << "t";
6994  else
6995  ostr << strcoeff << "t" << i;
6996  if (bSolveSparse)
6997  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
6998  else if (m_decompositionMethod == CHOLMOD)
6999  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
7000  else if (m_decompositionMethod == SPECIALK)
7001  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7002  if (i == 0) {
7003  sprintf(buf, "DEC (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7004  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7005  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7006  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7007  }
7008  else {
7009  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7010  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7011  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7012  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7013  }
7014  fp_out << buf;
7015  ostr.str("");
7016  strcoeff--;
7017  nIndex++;
7018  nSigmaIndex++;
7019  }
7020 
7021  if (!m_bSolveTwist) {
7022  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7023  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7024  fp_out << buf;
7025  }
7026  else {
7027  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
7028  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
7029  if (i == 0)
7030  ostr << " " << strcoeff;
7031  else if (i == 1)
7032  ostr << " " << strcoeff << "t";
7033  else
7034  ostr << strcoeff << "t" << i;
7035  if (bSolveSparse)
7036  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7037  else if (m_decompositionMethod == CHOLMOD)
7038  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
7039  else if (m_decompositionMethod == SPECIALK)
7040  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7041  if (i == 0) {
7042  sprintf(buf, "TWI (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7043  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7044  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7045  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7046  }
7047  else {
7048  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7049  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7050  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7051  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7052  }
7053  fp_out << buf;
7054  ostr.str("");
7055  strcoeff--;
7056  nIndex++;
7057  nSigmaIndex++;
7058  }
7059  }
7060  }
7061 
7062  else {
7063  sprintf(buf, " RA%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7064  coefRA[0]*RAD2DEG, 0.0, coefRA[0]*RAD2DEG, 0.0, "N/A");
7065  fp_out << buf;
7066  sprintf(buf, " DEC%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7067  coefDEC[0]*RAD2DEG, 0.0, coefDEC[0]*RAD2DEG, 0.0, "N/A");
7068  fp_out << buf;
7069  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7070  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7071  fp_out << buf;
7072  }
7073  }
7074 
7075  // output point data
7076  sprintf(buf, "\n\n\nPOINTS UNCERTAINTY SUMMARY\n==========================\n\n");
7077  fp_out << buf;
7078  sprintf(buf, " RMS Sigma Latitude(m)%20.8lf\n", m_drms_sigmaLat);
7079  fp_out << buf;
7080  sprintf(buf, " MIN Sigma Latitude(m)%20.8lf at %s\n",
7081  m_dminSigmaLatitude,m_idMinSigmaLatitude.toAscii().data());
7082  fp_out << buf;
7083  sprintf(buf, " MAX Sigma Latitude(m)%20.8lf at %s\n\n",
7084  m_dmaxSigmaLatitude,m_idMaxSigmaLatitude.toAscii().data());
7085  fp_out << buf;
7086  sprintf(buf, "RMS Sigma Longitude(m)%20.8lf\n", m_drms_sigmaLon);
7087  fp_out << buf;
7088  sprintf(buf, "MIN Sigma Longitude(m)%20.8lf at %s\n",
7089  m_dminSigmaLongitude,m_idMinSigmaLongitude.toAscii().data());
7090  fp_out << buf;
7091  sprintf(buf, "MAX Sigma Longitude(m)%20.8lf at %s\n\n",
7092  m_dmaxSigmaLongitude,m_idMaxSigmaLongitude.toAscii().data());
7093  fp_out << buf;
7094  if (m_bSolveRadii) {
7095  sprintf(buf, " RMS Sigma Radius(m)%20.8lf\n", m_drms_sigmaRad);
7096  fp_out << buf;
7097  sprintf(buf, " MIN Sigma Radius(m)%20.8lf at %s\n",
7098  m_dminSigmaRadius,m_idMinSigmaRadius.toAscii().data());
7099  fp_out << buf;
7100  sprintf(buf, " MAX Sigma Radius(m)%20.8lf at %s\n",
7101  m_dmaxSigmaRadius,m_idMaxSigmaRadius.toAscii().data());
7102  fp_out << buf;
7103  }
7104  else {
7105  sprintf(buf, " RMS Sigma Radius(m) N/A\n");
7106  fp_out << buf;
7107  sprintf(buf, " MIN Sigma Radius(m) N/A\n");
7108  fp_out << buf;
7109  sprintf(buf, " MAX Sigma Radius(m) N/A\n");
7110  fp_out << buf;
7111  }
7112 
7113  // output point data
7114  sprintf(buf, "\n\nPOINTS SUMMARY\n==============\n%103sSigma Sigma Sigma\n"
7115  " Label Status Rays RMS Latitude Longitude Radius"
7116  " Latitude Longitude Radius\n", "");
7117  fp_out << buf;
7118 
7119  int nRays = 0;
7120  double dLat, dLon, dRadius;
7121  double dSigmaLat, dSigmaLong, dSigmaRadius;
7122  double cor_lat_dd, cor_lon_dd, cor_rad_m;
7123  double cor_lat_m, cor_lon_m;
7124  double dLatInit, dLonInit, dRadiusInit;
7125  int nGoodRays;
7126  double dResidualRms;
7127  QString strStatus;
7128  int nPointIndex = 0;
7129 
7130  int nPoints = m_pCnet->GetNumPoints();
7131  for (int i = 0; i < nPoints; i++) {
7132 
7133  const ControlPoint *point = m_pCnet->GetPoint(i);
7134  if (point->IsIgnored())
7135  continue;
7136 
7137  nRays = point->GetNumMeasures();
7138  dResidualRms = point->GetResidualRms();
7139  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
7140  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
7141  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
7142  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
7143  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
7144  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
7145  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
7146 
7147  if (point->GetType() == ControlPoint::Fixed)
7148  strStatus = "FIXED";
7149  else if (point->GetType() == ControlPoint::Constrained)
7150  strStatus = "CONSTRAINED";
7151  else if (point->GetType() == ControlPoint::Free)
7152  strStatus = "FREE";
7153  else
7154  strStatus = "UNKNOWN";
7155 
7156  sprintf(buf, "%16s%15s%5d of %d%6.2lf%16.8lf%16.8lf%16.8lf%16.8lf%16.8lf%16.8lf\n",
7157  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays,
7158  dResidualRms, dLat, dLon, dRadius * 0.001, dSigmaLat, dSigmaLong, dSigmaRadius);
7159  fp_out << buf;
7160  nPointIndex++;
7161  }
7162 
7163  // output point data
7164  sprintf(buf, "\n\nPOINTS DETAIL\n=============\n\n");
7165  fp_out << buf;
7166 
7167  nPointIndex = 0;
7168  for (int i = 0; i < nPoints; i++) {
7169 
7170  const ControlPoint *point = m_pCnet->GetPoint(i);
7171  if ( point->IsIgnored() )
7172  continue;
7173 
7174  nRays = point->GetNumMeasures();
7175  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
7176  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
7177  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
7178  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
7179  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
7180  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
7181  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
7182 
7183  // point corrections and initial sigmas
7184  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
7185  bounded_vector<double, 3>& apriorisigmas = m_Point_AprioriSigmas[nPointIndex];
7186 
7187  cor_lat_dd = corrections[0] * Isis::RAD2DEG;
7188  cor_lon_dd = corrections[1] * Isis::RAD2DEG;
7189  cor_rad_m = corrections[2] * 1000.0;
7190 
7191  cor_lat_m = corrections[0] * m_dRTM;
7192  cor_lon_m = corrections[1] * m_dRTM * cos(dLat*Isis::DEG2RAD);
7193 
7194  dLatInit = dLat - cor_lat_dd;
7195  dLonInit = dLon - cor_lon_dd;
7196  dRadiusInit = dRadius - (corrections[2] * 1000.0);
7197 
7198  if (point->GetType() == ControlPoint::Fixed)
7199  strStatus = "FIXED";
7200  else if (point->GetType() == ControlPoint::Constrained)
7201  strStatus = "CONSTRAINED";
7202  else if (point->GetType() == ControlPoint::Free)
7203  strStatus = "FREE";
7204  else
7205  strStatus = "UNKNOWN";
7206 
7207  sprintf(buf, " Label: %s\nStatus: %s\n Rays: %d of %d\n",
7208  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays);
7209  fp_out << buf;
7210 
7211  sprintf(buf, "\n Point Initial Total Total Final Initial Final\n"
7212  "Coordinate Value Correction Correction Value Accuracy Accuracy\n"
7213  " (dd/dd/km) (dd/dd/km) (Meters) (dd/dd/km) (Meters) (Meters)\n");
7214  fp_out << buf;
7215 
7216  sprintf(buf, " LATITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n",
7217  dLatInit, cor_lat_dd, cor_lat_m, dLat, apriorisigmas[0], dSigmaLat);
7218  fp_out << buf;
7219 
7220  sprintf(buf, " LONGITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n",
7221  dLonInit, cor_lon_dd, cor_lon_m, dLon, apriorisigmas[1], dSigmaLong);
7222  fp_out << buf;
7223 
7224  sprintf(buf, " RADIUS%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n\n",
7225  dRadiusInit * 0.001, corrections[2], cor_rad_m, dRadius * 0.001,
7226  apriorisigmas[2], dSigmaRadius);
7227 
7228  fp_out << buf;
7229  nPointIndex++;
7230  }
7231 
7232  fp_out.close();
7233 
7234  return true;
7235  }
7236 
7237 
7241 /*
7242  bool BundleAdjust::OutputWithErrorPropagation() {
7243 
7244  QString ofname("bundleout.txt");
7245  if( m_strOutputFilePrefix.length() != 0 )
7246  ofname = m_strOutputFilePrefix + "_" + ofname;
7247 
7248  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
7249  if (!fp_out)
7250  return false;
7251 
7252  char buf[1056];
7253  //bool bHeld = false;
7254  std::vector<double> coefX(m_nNumberCamPosCoefSolved);
7255  std::vector<double> coefY(m_nNumberCamPosCoefSolved);
7256  std::vector<double> coefZ(m_nNumberCamPosCoefSolved);
7257  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved);
7258  std::vector<double> coefDEC(m_nNumberCamAngleCoefSolved);
7259  std::vector<double> coefTWI(m_nNumberCamAngleCoefSolved);
7260  std::vector<double> angles;
7261  Camera *pCamera = NULL;
7262  SpicePosition *pSpicePosition = NULL;
7263  SpiceRotation *pSpiceRotation = NULL;
7264 
7265  int nImages = Images();
7266  double dSigma=0;
7267  int nIndex = 0;
7268  bool bSolveSparse = false;
7269 
7270  gmm::row_matrix<gmm::rsvector<double> > lsqCovMatrix;
7271 
7272 // std::cout << m_Image_Corrections << std::endl;
7273 
7274  if( m_strSolutionMethod == "OLDSPARSE" )
7275  {
7276  lsqCovMatrix = m_pLsq->GetCovarianceMatrix(); // get reference to the covariance matrix from the least-squares object
7277  bSolveSparse = true;
7278  }
7279 
7280  OutputHeader(fp_out);
7281 //
7282  sprintf(buf, "\nIMAGE EXTERIOR ORIENTATION\n==========================\n");
7283  fp_out << buf;
7284 
7285  for ( int i = 0; i < nImages; i++ ) {
7286 
7287  //if ( m_nHeldImages > 0 && m_pHeldSnList->HasSerialNumber(m_pSnList->SerialNumber(i)) )
7288  // bHeld = true;
7289 
7290  pCamera = m_pCnet->Camera(i);
7291  if ( !pCamera )
7292  continue;
7293 
7294  // ImageIndex(i) retrieves index into the normal equations matrix for Image(i)
7295  nIndex = ImageIndex(i) ;
7296 
7297  pSpicePosition = pCamera->instrumentPosition();
7298  if ( !pSpicePosition )
7299  continue;
7300 
7301  pSpiceRotation = pCamera->instrumentRotation();
7302  if ( !pSpiceRotation )
7303  continue;
7304 
7305  // for frame cameras we directly retrieve the Exterior Orientation (i.e. position
7306  // and orientation angles). For others (linescan, radar) we retrieve the polynomial
7307  // coefficients from which the Exterior Orientation parameters are derived.
7308  if ( m_spacecraftPositionSolveType > 0 )
7309  pSpicePosition->GetPolynomial(coefX, coefY, coefZ);
7310  else { // not solving for position
7311  std::vector <double> coordinate(3);
7312  coordinate = pSpicePosition->GetCenterCoordinate();
7313  coefX.push_back(coordinate[0]);
7314  coefY.push_back(coordinate[1]);
7315  coefZ.push_back(coordinate[2]);
7316  }
7317 
7318  if ( m_cmatrixSolveType > 0 )
7319  pSpiceRotation->GetPolynomial(coefRA,coefDEC,coefTWI);
7320  // else { // frame camera
7321  else { // This is for m_cmatrixSolveType = None and no polynomial fit has occurred
7322  angles = pSpiceRotation->GetCenterAngles();
7323  coefRA.push_back(angles.at(0));
7324  coefDEC.push_back(angles.at(1));
7325  coefTWI.push_back(angles.at(2));
7326  }
7327 
7328  sprintf(buf, "\nImage Full File Name: %s\n", m_pSnList->FileName(i).toAscii().data());
7329  fp_out << buf;
7330  sprintf(buf, "\nImage Serial Number: %s\n", m_pSnList->SerialNumber(i).toAscii().data());
7331  fp_out << buf;
7332  sprintf(buf, "\n Image Initial Total Final Initial Final\n"
7333  "Parameter Value Correction Value Accuracy Accuracy\n");
7334  fp_out << buf;
7335 
7336  if( m_nNumberCamPosCoefSolved > 0 ) {
7337  char strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
7338  std::ostringstream ostr;
7339  for( int i = 0; i < m_nNumberCamPosCoefSolved; i++ ) {
7340  if( i ==0 )
7341  ostr << " " << strcoeff;
7342  else if ( i == 1 )
7343  ostr << " " << strcoeff << "t";
7344  else
7345  ostr << strcoeff << "t" << i;
7346  if( bSolveSparse )
7347  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7348  else
7349  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7350  if( i == 0 ) {
7351  sprintf(buf, " X (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7352  ostr.str().c_str(),coefX[i] - m_Image_Corrections(nIndex),
7353  m_Image_Corrections(nIndex), coefX[i],
7354  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7355  }
7356  else {
7357  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7358  ostr.str().c_str(),coefX[i] - m_Image_Corrections(nIndex),
7359  m_Image_Corrections(nIndex), coefX[i],
7360  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7361  }
7362  fp_out << buf;
7363  ostr.str("");
7364  strcoeff--;
7365  nIndex++;
7366  }
7367  strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
7368  for( int i = 0; i < m_nNumberCamPosCoefSolved; i++ ) {
7369  if( i ==0 )
7370  ostr << " " << strcoeff;
7371  else if ( i == 1 )
7372  ostr << " " << strcoeff << "t";
7373  else
7374  ostr << strcoeff << "t" << i;
7375  if( bSolveSparse )
7376  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7377  else
7378  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7379  if( i == 0 ) {
7380  sprintf(buf, " Y (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7381  ostr.str().c_str(),coefY[i] - m_Image_Corrections(nIndex),
7382  m_Image_Corrections(nIndex), coefY[i],
7383  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7384  }
7385  else {
7386  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7387  ostr.str().c_str(),coefY[i] - m_Image_Corrections(nIndex),
7388  m_Image_Corrections(nIndex), coefY[i],
7389  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7390  }
7391  fp_out << buf;
7392  ostr.str("");
7393  strcoeff--;
7394  nIndex++;
7395  }
7396  strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
7397  for( int i = 0; i < m_nNumberCamPosCoefSolved; i++ ) {
7398  if( i ==0 )
7399  ostr << " " << strcoeff;
7400  else if ( i == 1 )
7401  ostr << " " << strcoeff << "t";
7402  else
7403  ostr << strcoeff << "t" << i;
7404  if( bSolveSparse )
7405  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7406  else
7407  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7408  if( i == 0 ) {
7409  sprintf(buf, " Z (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7410  ostr.str().c_str(),coefZ[i] - m_Image_Corrections(nIndex),
7411  m_Image_Corrections(nIndex), coefZ[i],
7412  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7413  }
7414  else {
7415  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7416  ostr.str().c_str(),coefZ[i] - m_Image_Corrections(nIndex),
7417  m_Image_Corrections(nIndex), coefZ[i],
7418  m_dGlobalSpacecraftPositionAprioriSigma[i], dSigma);
7419  }
7420  fp_out << buf;
7421  ostr.str("");
7422  strcoeff--;
7423  nIndex++;
7424  }
7425  }
7426 
7427  else {
7428  sprintf(buf, " X%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefX[0], 0.0, coefX[0], 0.0, "N/A");
7429  fp_out << buf;
7430  sprintf(buf, " Y%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefY[0], 0.0, coefY[0], 0.0, "N/A");
7431  fp_out << buf;
7432  sprintf(buf, " Z%17.8lf%21.8lf%20.8lf%18.8lf%18s\n", coefZ[0], 0.0, coefZ[0], 0.0, "N/A");
7433  fp_out << buf;
7434  }
7435 
7436  if( m_nNumberCamAngleCoefSolved > 0 ) {
7437  char strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
7438  std::ostringstream ostr;
7439  for( int i = 0; i < m_nNumberCamAngleCoefSolved; i++ ) {
7440  if( i ==0 )
7441  ostr << " " << strcoeff;
7442  else if ( i == 1 )
7443  ostr << " " << strcoeff << "t";
7444  else
7445  ostr << strcoeff << "t" << i;
7446  if( bSolveSparse )
7447  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7448  else
7449  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7450  if( i == 0 ) {
7451  sprintf(buf, " RA (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7452  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
7453  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
7454  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7455  }
7456  else {
7457  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7458  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
7459  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
7460  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7461  }
7462  fp_out << buf;
7463  ostr.str("");
7464  strcoeff--;
7465  nIndex++;
7466  }
7467  strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
7468  for( int i = 0; i < m_nNumberCamAngleCoefSolved; i++ ) {
7469  if( i ==0 )
7470  ostr << " " << strcoeff;
7471  else if ( i == 1 )
7472  ostr << " " << strcoeff << "t";
7473  else
7474  ostr << strcoeff << "t" << i;
7475  if( bSolveSparse )
7476  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7477  else
7478  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7479  if( i == 0 ) {
7480  sprintf(buf, "DEC (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7481  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7482  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7483  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7484  }
7485  else {
7486  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7487  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7488  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7489  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7490  }
7491  fp_out << buf;
7492  ostr.str("");
7493  strcoeff--;
7494  nIndex++;
7495  }
7496  if ( !m_bSolveTwist ) {
7497  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7498  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7499  fp_out << buf;
7500  }
7501  else {
7502  strcoeff = 'a' + m_nNumberCamAngleCoefSolved -1;
7503  for( int i = 0; i < m_nNumberCamAngleCoefSolved; i++ ) {
7504  if( i ==0 )
7505  ostr << " " << strcoeff;
7506  else if ( i == 1 )
7507  ostr << " " << strcoeff << "t";
7508  else
7509  ostr << strcoeff << "t" << i;
7510  if( bSolveSparse )
7511  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
7512  else
7513  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
7514  if( i == 0 ) {
7515  sprintf(buf, "TWI (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7516  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7517  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7518  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7519  }
7520  else {
7521  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18.8lf\n",
7522  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7523  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7524  m_dGlobalCameraAnglesAprioriSigma[i], dSigma * RAD2DEG);
7525  }
7526  fp_out << buf;
7527  ostr.str("");
7528  strcoeff--;
7529  nIndex++;
7530  }
7531  }
7532  }
7533 
7534  else {
7535  sprintf(buf, " RA%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7536  coefRA[0]*RAD2DEG, 0.0, coefRA[0]*RAD2DEG, 0.0, "N/A");
7537  fp_out << buf;
7538  sprintf(buf, " DEC%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7539  coefDEC[0]*RAD2DEG, 0.0, coefDEC[0]*RAD2DEG, 0.0, "N/A");
7540  fp_out << buf;
7541  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7542  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7543  fp_out << buf;
7544  }
7545  }
7546 /
7547  // output point data
7548  sprintf(buf, "\n\n\nPOINTS UNCERTAINTY SUMMARY\n==========================\n\n");
7549  fp_out << buf;
7550  sprintf(buf, " RMS Sigma Latitude(m)%20.8lf\n",
7551  m_drms_sigmaLat);
7552  fp_out << buf;
7553  sprintf(buf, " MIN Sigma Latitude(m)%20.8lf at %s\n",
7554  m_dminSigmaLatitude,m_idMinSigmaLatitude.toAscii().data());
7555  fp_out << buf;
7556  sprintf(buf, " MAX Sigma Latitude(m)%20.8lf at %s\n\n",
7557  m_dmaxSigmaLatitude,m_idMaxSigmaLatitude.toAscii().data());
7558  fp_out << buf;
7559  sprintf(buf, "RMS Sigma Longitude(m)%20.8lf\n",
7560  m_drms_sigmaLon);
7561  fp_out << buf;
7562  sprintf(buf, "MIN Sigma Longitude(m)%20.8lf at %s\n",
7563  m_dminSigmaLongitude,m_idMinSigmaLongitude.toAscii().data());
7564  fp_out << buf;
7565  sprintf(buf, "MAX Sigma Longitude(m)%20.8lf at %s\n\n",
7566  m_dmaxSigmaLongitude,m_idMaxSigmaLongitude.toAscii().data());
7567  fp_out << buf;
7568  if ( m_bSolveRadii ) {
7569  sprintf(buf, " RMS Sigma Radius(m)%20.8lf\n",
7570  m_drms_sigmaRad);
7571  fp_out << buf;
7572  sprintf(buf, " MIN Sigma Radius(m)%20.8lf at %s\n",
7573  m_dminSigmaRadius,m_idMinSigmaRadius.toAscii().data());
7574  fp_out << buf;
7575  sprintf(buf, " MAX Sigma Radius(m)%20.8lf at %s\n",
7576  m_dmaxSigmaRadius,m_idMaxSigmaRadius.toAscii().data());
7577  fp_out << buf;
7578  }
7579  else {
7580  sprintf(buf, " RMS Sigma Radius(m) N/A\n");
7581  fp_out << buf;
7582  sprintf(buf, " MIN Sigma Radius(m) N/A\n");
7583  fp_out << buf;
7584  sprintf(buf, " MAX Sigma Radius(m) N/A\n");
7585  fp_out << buf;
7586  }
7587 
7588  // output point data
7589  sprintf(buf, "\n\nPOINTS SUMMARY\n==============\n%103sSigma Sigma Sigma\n"
7590  " Label Status Rays RMS Latitude Longitude Radius"
7591  " Latitude Longitude Radius\n", "");
7592  fp_out << buf;
7593 
7594  int nRays = 0;
7595  double dLat, dLon, dRadius;
7596  double dSigmaLat, dSigmaLong, dSigmaRadius;
7597  double cor_lat_dd, cor_lon_dd, cor_rad_m;
7598  double cor_lat_m, cor_lon_m;
7599  double dLatInit, dLonInit, dRadiusInit;
7600  int nGoodRays;
7601  double dResidualRms;
7602  QString strStatus;
7603  int nPointIndex = 0;
7604 
7605  int nPoints = m_pCnet->GetNumPoints();
7606  for ( int i = 0; i < nPoints; i++ ) {
7607 
7608  const ControlPoint *point = m_pCnet->GetPoint(i);
7609  if ( point->IsIgnored() )
7610  continue;
7611 
7612  nRays = point->GetNumMeasures();
7613  dResidualRms = point->GetResidualRms();
7614  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
7615  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
7616  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
7617  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
7618  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
7619  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
7620  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
7621 
7622  if (point->GetType() == ControlPoint::Fixed)
7623  strStatus = "FIXED";
7624  else if (point->GetType() == ControlPoint::Constrained)
7625  strStatus = "CONSTRAINED";
7626  else if (point->GetType() == ControlPoint::Free)
7627  strStatus = "FREE";
7628  else
7629  strStatus = "UNKNOWN";
7630 
7631  sprintf(buf, "%16s%15s%5d of %d%6.2lf%16.8lf%16.8lf%16.8lf%16.8lf%16.8lf%16.8lf\n",
7632  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays, dResidualRms, dLat,
7633  dLon, dRadius * 0.001, dSigmaLat, dSigmaLong, dSigmaRadius);
7634  fp_out << buf;
7635  nPointIndex++;
7636  }
7637 
7638  // output point data
7639  sprintf(buf, "\n\nPOINTS DETAIL\n=============\n\n");
7640  fp_out << buf;
7641 
7642  nPointIndex = 0;
7643  for ( int i = 0; i < nPoints; i++ ) {
7644 
7645  const ControlPoint *point = m_pCnet->GetPoint(i);
7646  if ( point->IsIgnored() )
7647  continue;
7648 
7649  nRays = point->GetNumMeasures();
7650  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
7651  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
7652  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
7653  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
7654  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
7655  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
7656  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
7657 
7658  // point corrections and initial sigmas
7659  bounded_vector<double, 3>& corrections = m_Point_Corrections[nPointIndex];
7660  bounded_vector<double, 3>& apriorisigmas = m_Point_AprioriSigmas[nPointIndex];
7661 
7662  cor_lat_dd = corrections[0] * Isis::RAD2DEG;
7663  cor_lon_dd = corrections[1] * Isis::RAD2DEG;
7664  cor_rad_m = corrections[2] * 1000.0;
7665 
7666  cor_lat_m = corrections[0] * m_dRTM;
7667  cor_lon_m = corrections[1] * m_dRTM * cos(dLat*Isis::DEG2RAD);
7668 
7669  dLatInit = dLat - cor_lat_dd;
7670  dLonInit = dLon - cor_lon_dd;
7671  dRadiusInit = dRadius - (corrections[2] * 1000.0);
7672 
7673  if (point->GetType() == ControlPoint::Fixed)
7674  strStatus = "FIXED";
7675  else if (point->GetType() == ControlPoint::Constrained)
7676  strStatus = "CONSTRAINED";
7677  else if (point->GetType() == ControlPoint::Free)
7678  strStatus = "FREE";
7679  else
7680  strStatus = "UNKNOWN";
7681 
7682  sprintf(buf, " Label: %s\nStatus: %s\n Rays: %d of %d\n",
7683  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays);
7684  fp_out << buf;
7685 
7686  sprintf(buf, "\n Point Initial Total Total Final Initial Final\n"
7687  "Coordinate Value Correction Correction Value Accuracy Accuracy\n"
7688  " (dd/dd/km) (dd/dd/km) (Meters) (dd/dd/km) (Meters) (Meters)\n");
7689  fp_out << buf;
7690 
7691  sprintf(buf, " LATITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n",
7692  dLatInit, cor_lat_dd, cor_lat_m, dLat, apriorisigmas[0], dSigmaLat);
7693  fp_out << buf;
7694 
7695  sprintf(buf, " LONGITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n",
7696  dLonInit, cor_lon_dd, cor_lon_m, dLon, apriorisigmas[1], dSigmaLong);
7697  fp_out << buf;
7698 
7699  sprintf(buf, " RADIUS%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18.8lf\n\n",
7700  dRadiusInit * 0.001, corrections[2], cor_rad_m, dRadius * 0.001,
7701  apriorisigmas[2], dSigmaRadius);
7702 
7703  fp_out << buf;
7704  nPointIndex++;
7705  }
7706 
7707  fp_out.close();
7708 
7709  return true;
7710  }
7711 */
7712 
7724  bool BundleAdjust::OutputNoErrorPropagation() {
7725 
7726  QString ofname("bundleout.txt");
7727  if (!m_strOutputFilePrefix.isEmpty())
7728  ofname = m_strOutputFilePrefix + "_" + ofname;
7729 
7730  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
7731  if (!fp_out)
7732  return false;
7733 
7734  char buf[1056];
7735 
7736  //bool bHeld = false;
7737  std::vector<double> coefX(m_nNumberCamPosCoefSolved);
7738  std::vector<double> coefY(m_nNumberCamPosCoefSolved);
7739  std::vector<double> coefZ(m_nNumberCamPosCoefSolved);
7740  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved);
7741  std::vector<double> coefDEC(m_nNumberCamAngleCoefSolved);
7742  std::vector<double> coefTWI(m_nNumberCamAngleCoefSolved);
7743  std::vector<double> angles;
7744  Camera *pCamera = NULL;
7745  SpicePosition *pSpicePosition = NULL;
7746  SpiceRotation *pSpiceRotation = NULL;
7747  int nIndex = 0;
7748  int nImages = Images();
7749 
7750  OutputHeader(fp_out);
7751 
7752  sprintf(buf, "\nIMAGE EXTERIOR ORIENTATION ***J2000***\n======================================\n");
7753  fp_out << buf;
7754 
7755  for (int i = 0; i < nImages; i++) {
7756  //if (m_nHeldImages > 0 && m_pHeldSnList->HasSerialNumber(m_pSnList->SerialNumber(i)))
7757  // bHeld = true;
7758 
7759  pCamera = m_pCnet->Camera(i);
7760  if (!pCamera)
7761  continue;
7762 
7763  nIndex = ImageIndex(i);
7764 
7765  pSpicePosition = pCamera->instrumentPosition();
7766  if (!pSpicePosition)
7767  continue;
7768 
7769  pSpiceRotation = pCamera->instrumentRotation();
7770  if (!pSpiceRotation)
7771  continue;
7772 
7773  // for frame cameras we directly retrieve the Exterior Orientation (i.e. position
7774  // and orientation angles). For others (linescan, radar) we retrieve the polynomial
7775  // coefficients from which the Exterior Orientation paramters are derived.
7776  // This is incorrect...Correction below
7777  // For all instruments we retrieve the polynomial coefficients from which the
7778  // Exterior Orientation parameters are derived. For framing cameras, a single
7779  // coefficient for each coordinate is returned.
7780  if (m_spacecraftPositionSolveType > 0)
7781  pSpicePosition->GetPolynomial(coefX,coefY,coefZ);
7782  // else { // frame camera
7783  else { // This is for m_spacecraftPositionSolveType = None and no polynomial fit has occurred
7784  std::vector <double> coordinate(3);
7785  coordinate = pSpicePosition->GetCenterCoordinate();
7786  coefX.push_back(coordinate[0]);
7787  coefY.push_back(coordinate[1]);
7788  coefZ.push_back(coordinate[2]);
7789  }
7790 
7791  if (m_cmatrixSolveType > 0) {
7792 // angles = pSpiceRotation->Angles(3,1,3);
7793  pSpiceRotation->GetPolynomial(coefRA,coefDEC,coefTWI);
7794  }
7795  else { // frame camera
7796  angles = pSpiceRotation->GetCenterAngles();
7797  coefRA.push_back(angles.at(0));
7798  coefDEC.push_back(angles.at(1));
7799  coefTWI.push_back(angles.at(2));
7800  }
7801 
7802  sprintf(buf, "\nImage Full File Name: %s\n", m_pSnList->FileName(i).toAscii().data());
7803  fp_out << buf;
7804  sprintf(buf, "\n Image Serial Number: %s\n", m_pSnList->SerialNumber(i).toAscii().data());
7805  fp_out << buf;
7806  sprintf(buf, "\n Image Initial Total Final Initial Final\n"
7807  "Parameter Value Correction Value Accuracy Accuracy\n");
7808  fp_out << buf;
7809 
7810  if (m_nNumberCamPosCoefSolved > 0) {
7811  char strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
7812  std::ostringstream ostr;
7813  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
7814  if (i == 0)
7815  ostr << " " << strcoeff;
7816  else if (i == 1)
7817  ostr << " " << strcoeff << "t";
7818  else
7819  ostr << strcoeff << "t" << i;
7820  if (i == 0) {
7821  sprintf(buf, " X (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7822  ostr.str().c_str(), coefX[i] - m_Image_Corrections(nIndex),
7823  m_Image_Corrections(nIndex), coefX[i],
7824  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7825  }
7826  else {
7827  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7828  ostr.str().c_str(), coefX[i] - m_Image_Corrections(nIndex),
7829  m_Image_Corrections(nIndex), coefX[i],
7830  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7831  }
7832  fp_out << buf;
7833  ostr.str("");
7834  strcoeff--;
7835  nIndex++;
7836  }
7837  strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
7838  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
7839  if (i == 0)
7840  ostr << " " << strcoeff;
7841  else if (i == 1)
7842  ostr << " " << strcoeff << "t";
7843  else
7844  ostr << strcoeff << "t" << i;
7845  if (i == 0 ) {
7846  sprintf(buf, " Y (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7847  ostr.str().c_str(), coefY[i] - m_Image_Corrections(nIndex),
7848  m_Image_Corrections(nIndex), coefY[i],
7849  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7850  }
7851  else {
7852  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7853  ostr.str().c_str(), coefY[i] - m_Image_Corrections(nIndex),
7854  m_Image_Corrections(nIndex), coefY[i],
7855  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7856  }
7857  fp_out << buf;
7858  ostr.str("");
7859  strcoeff--;
7860  nIndex++;
7861  }
7862  strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
7863  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
7864  if (i == 0)
7865  ostr << " " << strcoeff;
7866  else if (i == 1)
7867  ostr << " " << strcoeff << "t";
7868  else
7869  ostr << strcoeff << "t" << i;
7870  if (i == 0) {
7871  sprintf(buf, " Z (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7872  ostr.str().c_str(), coefZ[i] - m_Image_Corrections(nIndex),
7873  m_Image_Corrections(nIndex), coefZ[i],
7874  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7875  }
7876  else {
7877  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7878  ostr.str().c_str(), coefZ[i] - m_Image_Corrections(nIndex),
7879  m_Image_Corrections(nIndex), coefZ[i],
7880  m_dGlobalSpacecraftPositionAprioriSigma[i], "N/A");
7881  }
7882  fp_out << buf;
7883  ostr.str("");
7884  strcoeff--;
7885  nIndex++;
7886  }
7887  }
7888  else {
7889  sprintf(buf, " X%17.8lf%21.8lf%20.8lf%18s%18s\n", coefX[0], 0.0, coefX[0], "N/A", "N/A");
7890  fp_out << buf;
7891  sprintf(buf, " Y%17.8lf%21.8lf%20.8lf%18s%18s\n", coefY[0], 0.0, coefY[0], "N/A", "N/A");
7892  fp_out << buf;
7893  sprintf(buf, " Z%17.8lf%21.8lf%20.8lf%18s%18s\n", coefZ[0], 0.0, coefZ[0], "N/A", "N/A");
7894  fp_out << buf;
7895  }
7896 
7897  if (m_nNumberCamAngleCoefSolved > 0) {
7898  char strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
7899  std::ostringstream ostr;
7900  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
7901  if (i == 0)
7902  ostr << " " << strcoeff;
7903  else if (i == 1)
7904  ostr << " " << strcoeff << "t";
7905  else
7906  ostr << strcoeff << "t" << i;
7907  if (i == 0) {
7908  sprintf(buf, " RA (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7909  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
7910  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
7911  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7912  }
7913  else {
7914  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7915  ostr.str().c_str(),(coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG,
7916  m_Image_Corrections(nIndex) * RAD2DEG, coefRA[i] * RAD2DEG,
7917  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7918  }
7919  fp_out << buf;
7920  ostr.str("");
7921  strcoeff--;
7922  nIndex++;
7923  }
7924  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
7925  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
7926  if (i == 0)
7927  ostr << " " << strcoeff;
7928  else if (i == 1)
7929  ostr << " " << strcoeff << "t";
7930  else
7931  ostr << strcoeff << "t" << i;
7932  if (i == 0) {
7933  sprintf(buf, "DEC (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7934  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7935  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7936  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7937  }
7938  else {
7939  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7940  ostr.str().c_str(),(coefDEC[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7941  m_Image_Corrections(nIndex)*RAD2DEG, coefDEC[i]*RAD2DEG,
7942  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7943  }
7944  fp_out << buf;
7945  ostr.str("");
7946  strcoeff--;
7947  nIndex++;
7948  }
7949  if (!m_bSolveTwist) {
7950  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7951  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7952  fp_out << buf;
7953  }
7954  else {
7955  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
7956  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
7957  if (i == 0)
7958  ostr << " " << strcoeff;
7959  else if (i == 1)
7960  ostr << " " << strcoeff << "t";
7961  else
7962  ostr << strcoeff << "t" << i;
7963  if (i == 0) {
7964  sprintf(buf, "TWI (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7965  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7966  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7967  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7968  }
7969  else {
7970  sprintf(buf, " (%s)%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7971  ostr.str().c_str(),(coefTWI[i] - m_Image_Corrections(nIndex))*RAD2DEG,
7972  m_Image_Corrections(nIndex)*RAD2DEG, coefTWI[i]*RAD2DEG,
7973  m_dGlobalCameraAnglesAprioriSigma[i], "N/A");
7974  }
7975  fp_out << buf;
7976  ostr.str("");
7977  strcoeff--;
7978  nIndex++;
7979  }
7980  }
7981  }
7982  else {
7983  sprintf(buf, " RA%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7984  coefRA[0]*RAD2DEG, 0.0, coefRA[0]*RAD2DEG, 0.0, "N/A");
7985  fp_out << buf;
7986  sprintf(buf, " DEC%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7987  coefDEC[0]*RAD2DEG, 0.0, coefDEC[0]*RAD2DEG, 0.0, "N/A");
7988  fp_out << buf;
7989  sprintf(buf, " TWIST%17.8lf%21.8lf%20.8lf%18.8lf%18s\n",
7990  coefTWI[0]*RAD2DEG, 0.0, coefTWI[0]*RAD2DEG, 0.0, "N/A");
7991  fp_out << buf;
7992  }
7993  }
7994 
7995  fp_out << "\n\n\n";
7996 
7997  // output point data
7998  sprintf(buf,"\nPOINTS SUMMARY\n==============\n%99sSigma Sigma Sigma\n"
7999  " Label Status Rays RMS Latitude Longitude Radius"
8000  " Latitude Longitude Radius\n","");
8001  fp_out << buf;
8002 
8003  int nRays = 0;
8004  double dResidualRms;
8005  double dLat,dLon,dRadius;
8006  double cor_lat_dd,cor_lon_dd,cor_rad_m;
8007  double cor_lat_m,cor_lon_m;
8008  double dLatInit,dLonInit,dRadiusInit;
8009  int nGoodRays;
8010 
8011  QString strStatus;
8012 
8013  int nPoints = m_pCnet->GetNumPoints();
8014  for (int i = 0; i < nPoints; i++) {
8015 
8016  const ControlPoint* point = m_pCnet->GetPoint(i);
8017  if (point->IsIgnored())
8018  continue;
8019 
8020  nRays = point->GetNumMeasures();
8021  dResidualRms = point->GetResidualRms();
8022  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
8023  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
8024  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
8025  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
8026 
8027  if (point->GetType() == ControlPoint::Fixed)
8028  strStatus = "FIXED";
8029  else if (point->GetType() == ControlPoint::Constrained)
8030  strStatus = "CONSTRAINED";
8031  else if (point->GetType() == ControlPoint::Free)
8032  strStatus = "FREE";
8033  else
8034  strStatus = "UNKNOWN";
8035 
8036  sprintf(buf, "%16s%12s%4d of %d%6.2lf%16.8lf%16.8lf%16.8lf%11s%16s%16s\n",
8037  point->GetId().toAscii().data(), strStatus.toAscii().data(), nGoodRays, nRays,
8038  dResidualRms, dLat, dLon, dRadius * 0.001,"N/A","N/A","N/A");
8039 
8040  fp_out << buf;
8041  }
8042 
8043  sprintf(buf,"\n\nPOINTS DETAIL\n=============\n\n");
8044  fp_out << buf;
8045 
8046  int nPointIndex = 0;
8047  for (int i = 0; i < nPoints; i++) {
8048 
8049  const ControlPoint* point = m_pCnet->GetPoint(i);
8050  if (point->IsIgnored())
8051  continue;
8052 
8053  nRays = point->GetNumMeasures();
8054  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
8055  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
8056  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().meters();
8057  nGoodRays = nRays - point->GetNumberOfRejectedMeasures();
8058 
8059  // point corrections and initial sigmas
8060  bounded_vector<double,3>& corrections = m_Point_Corrections[nPointIndex];
8061  bounded_vector<double,3>& apriorisigmas = m_Point_AprioriSigmas[nPointIndex];
8062 
8063  cor_lat_dd = corrections[0]*Isis::RAD2DEG;
8064  cor_lon_dd = corrections[1]*Isis::RAD2DEG;
8065  cor_rad_m = corrections[2]*1000.0;
8066 
8067  cor_lat_m = corrections[0]*m_dRTM;
8068  cor_lon_m = corrections[1]*m_dRTM*cos(dLat*Isis::DEG2RAD);
8069 
8070  dLatInit = dLat-cor_lat_dd;
8071  dLonInit = dLon-cor_lon_dd;
8072  dRadiusInit = dRadius-(corrections[2]*1000.0);
8073 
8074  if (point->GetType() == ControlPoint::Fixed)
8075  strStatus = "FIXED";
8076  else if (point->GetType() == ControlPoint::Constrained)
8077  strStatus = "CONSTRAINED";
8078  else if (point->GetType() == ControlPoint::Free)
8079  strStatus = "FREE";
8080  else
8081  strStatus = "UNKNOWN";
8082 
8083  sprintf(buf," Label: %s\nStatus: %s\n Rays: %d of %d\n",
8084  point->GetId().toAscii().data(),strStatus.toAscii().data(),nGoodRays,nRays);
8085  fp_out << buf;
8086 
8087  sprintf(buf,"\n Point Initial Total Total Final Initial Final\n"
8088  "Coordinate Value Correction Correction Value Accuracy Accuracy\n"
8089  " (dd/dd/km) (dd/dd/km) (Meters) (dd/dd/km) (Meters) (Meters)\n");
8090  fp_out << buf;
8091 
8092  sprintf(buf," LATITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18s\n",
8093  dLatInit, cor_lat_dd, cor_lat_m, dLat, apriorisigmas[0], "N/A");
8094  fp_out << buf;
8095 
8096  sprintf(buf," LONGITUDE%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18s\n",
8097  dLonInit, cor_lon_dd, cor_lon_m, dLon, apriorisigmas[1], "N/A");
8098  fp_out << buf;
8099 
8100  sprintf(buf," RADIUS%17.8lf%21.8lf%20.8lf%20.8lf%18.8lf%18s\n\n",
8101  dRadiusInit*0.001, corrections[2], cor_rad_m, dRadius*0.001, apriorisigmas[2], "N/A");
8102 
8103  fp_out << buf;
8104 
8105  nPointIndex++;
8106  }
8107 
8108  fp_out.close();
8109 
8110  return true;
8111  }
8112 
8113 
8117  bool BundleAdjust::OutputPointsCSV() {
8118  char buf[1056];
8119 
8120  QString ofname("bundleout_points.csv");
8121  if (!m_strOutputFilePrefix.isEmpty())
8122  ofname = m_strOutputFilePrefix + "_" + ofname;
8123 
8124  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
8125  if (!fp_out)
8126  return false;
8127 
8128  int nPoints = m_pCnet->GetNumPoints();
8129 
8130  double dLat, dLon, dRadius;
8131  double dX, dY, dZ;
8132  double dSigmaLat, dSigmaLong, dSigmaRadius;
8133  QString strStatus;
8134  double cor_lat_m;
8135  double cor_lon_m;
8136  double cor_rad_m;
8137  int nMeasures, nRejectedMeasures;
8138  double dResidualRms;
8139 
8140  // print column headers
8141  if (m_bErrorPropagation) {
8142  sprintf(buf, "Point,Point,Accepted,Rejected,Residual,3-d,3-d,3-d,Sigma,"
8143  "Sigma,Sigma,Correction,Correction,Correction,Coordinate,"
8144  "Coordinate,Coordinate\nID,,,,,Latitude,Longitude,Radius,"
8145  "Latitude,Longitude,Radius,Latitude,Longitude,Radius,X,Y,Z\n"
8146  "Label,Status,Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),"
8147  "(m),(m),(m),(km),(km),(km)\n");
8148  }
8149  else {
8150  sprintf(buf, "Point,Point,Accepted,Rejected,Residual,3-d,3-d,3-d,"
8151  "Correction,Correction,Correction,Coordinate,Coordinate,"
8152  "Coordinate\n,,,,,Latitude,Longitude,Radius,Latitude,"
8153  "Longitude,Radius,X,Y,Z\nLabel,Status,Measures,Measures,"
8154  "RMS,(dd),(dd),(km),(m),(m),(m),(km),(km),(km)\n");
8155  }
8156  fp_out << buf;
8157 
8158  int nPointIndex = 0;
8159  for (int i = 0; i < nPoints; i++) {
8160  const ControlPoint *point = m_pCnet->GetPoint(i);
8161 
8162  if (!point)
8163  continue;
8164 
8165  if (point->IsIgnored() || point->IsRejected())
8166  continue;
8167 
8168  dLat = point->GetAdjustedSurfacePoint().GetLatitude().degrees();
8169  dLon = point->GetAdjustedSurfacePoint().GetLongitude().degrees();
8170  dRadius = point->GetAdjustedSurfacePoint().GetLocalRadius().kilometers();
8171  dX = point->GetAdjustedSurfacePoint().GetX().kilometers();
8172  dY = point->GetAdjustedSurfacePoint().GetY().kilometers();
8173  dZ = point->GetAdjustedSurfacePoint().GetZ().kilometers();
8174  nMeasures = point->GetNumMeasures();
8175  nRejectedMeasures = point->GetNumberOfRejectedMeasures();
8176  dResidualRms = point->GetResidualRms();
8177 
8178  // point corrections and initial sigmas
8179  bounded_vector<double,3>& corrections = m_Point_Corrections[nPointIndex];
8180  cor_lat_m = corrections[0]*m_dRTM;
8181  cor_lon_m = corrections[1]*m_dRTM*cos(dLat*Isis::DEG2RAD);
8182  cor_rad_m = corrections[2]*1000.0;
8183 
8184  if (point->GetType() == ControlPoint::Fixed)
8185  strStatus = "FIXED";
8186  else if (point->GetType() == ControlPoint::Constrained)
8187  strStatus = "CONSTRAINED";
8188  else if (point->GetType() == ControlPoint::Free)
8189  strStatus = "FREE";
8190  else
8191  strStatus = "UNKNOWN";
8192 
8193  if (m_bErrorPropagation) {
8194  dSigmaLat = point->GetAdjustedSurfacePoint().GetLatSigmaDistance().meters();
8195  dSigmaLong = point->GetAdjustedSurfacePoint().GetLonSigmaDistance().meters();
8196  dSigmaRadius = point->GetAdjustedSurfacePoint().GetLocalRadiusSigma().meters();
8197 
8198  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",
8199  point->GetId().toAscii().data(), strStatus.toAscii().data(), nMeasures, nRejectedMeasures, dResidualRms, dLat, dLon, dRadius,
8200  dSigmaLat, dSigmaLong, dSigmaRadius, cor_lat_m, cor_lon_m, cor_rad_m, dX, dY, dZ);
8201  }
8202  else
8203  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",
8204  point->GetId().toAscii().data(), strStatus.toAscii().data(), nMeasures, nRejectedMeasures, dResidualRms, dLat, dLon, dRadius,
8205  cor_lat_m, cor_lon_m, cor_rad_m, dX, dY, dZ);
8206 
8207  fp_out << buf;
8208 
8209  nPointIndex++;
8210  }
8211 
8212  fp_out.close();
8213 
8214  return true;
8215  }
8216 
8217 
8222  bool BundleAdjust::OutputResiduals() {
8223  char buf[1056];
8224 
8225  QString ofname("residuals.csv");
8226  if (!m_strOutputFilePrefix.isEmpty())
8227  ofname = m_strOutputFilePrefix + "_" + ofname;
8228 
8229  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
8230  if (!fp_out)
8231  return false;
8232 
8233  // output column headers
8234  sprintf(buf, ",,,x image,y image,Measured,Measured,sample,line,Residual Vector\n");
8235  fp_out << buf;
8236  sprintf(buf, "Point,Image,Image,coordinate,coordinate,Sample,Line,residual,residual,Magnitude\n");
8237  fp_out << buf;
8238  sprintf(buf, "Label,Filename,Serial Number,(mm),(mm),(pixels),(pixels),(pixels),(pixels),(pixels),Rejected\n");
8239  fp_out << buf;
8240 
8241  int nImageIndex;
8242 
8243  // printf("output residuals!!!\n");
8244 
8245  int nObjectPoints = m_pCnet->GetNumPoints();
8246  for (int i = 0; i < nObjectPoints; i++) {
8247  const ControlPoint *point = m_pCnet->GetPoint(i);
8248  if (point->IsIgnored())
8249  continue;
8250 
8251  int nObservations = point->GetNumMeasures();
8252  for (int j = 0; j < nObservations; j++) {
8253  const ControlMeasure *measure = point->GetMeasure(j);
8254  if (measure->IsIgnored())
8255  continue;
8256 
8257  Camera *pCamera = measure->Camera();
8258  if (!pCamera)
8259  continue;
8260 
8261  // Determine the image index
8262  nImageIndex = m_pSnList->SerialNumberIndex(measure->GetCubeSerialNumber());
8263 
8264  if (measure->IsRejected())
8265  sprintf(buf, "%s,%s,%s,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,*\n",
8266  point->GetId().toAscii().data(), m_pSnList->FileName(nImageIndex).toAscii().data(), m_pSnList->SerialNumber(nImageIndex).toAscii().data(),
8267  measure->GetFocalPlaneMeasuredX(), measure->GetFocalPlaneMeasuredY(), measure->GetSample(),
8268  measure->GetLine(), measure->GetSampleResidual(), measure->GetLineResidual(),
8269  measure->GetResidualMagnitude());
8270  else
8271  sprintf(buf, "%s,%s,%s,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf\n",
8272  point->GetId().toAscii().data(), m_pSnList->FileName(nImageIndex).toAscii().data(), m_pSnList->SerialNumber(nImageIndex).toAscii().data(),
8273  measure->GetFocalPlaneMeasuredX(), measure->GetFocalPlaneMeasuredY(), measure->GetSample(),
8274  measure->GetLine(), measure->GetSampleResidual(), measure->GetLineResidual(), measure->GetResidualMagnitude());
8275  fp_out << buf;
8276  }
8277  }
8278 
8279  fp_out.close();
8280 
8281  return true;
8282  }
8283 
8287  bool BundleAdjust::OutputImagesCSV() {
8288  char buf[1056];
8289 
8290  QString ofname("bundleout_images.csv");
8291  if (!m_strOutputFilePrefix.isEmpty())
8292  ofname = m_strOutputFilePrefix + "_" + ofname;
8293 
8294  std::ofstream fp_out(ofname.toAscii().data(), std::ios::out);
8295  if (!fp_out)
8296  return false;
8297 
8298  // setup column headers
8299  std::vector<QString> output_columns;
8300 
8301  output_columns.push_back("Image,");
8302 
8303  output_columns.push_back("rms,");
8304  output_columns.push_back("rms,");
8305  output_columns.push_back("rms,");
8306 
8307  char strcoeff = 'a' + m_nNumberCamPosCoefSolved -1;
8308  std::ostringstream ostr;
8309  int ncoeff = 1;
8310  if (m_nNumberCamPosCoefSolved > 0)
8311  ncoeff = m_nNumberCamPosCoefSolved;
8312 
8313  for (int i = 0; i < ncoeff; i++) {
8314  if (i == 0)
8315  ostr << strcoeff;
8316  else if (i == 1)
8317  ostr << strcoeff << "t";
8318  else
8319  ostr << strcoeff << "t" << i;
8320  for (int j = 0; j < 5; j++) {
8321  if (ncoeff == 1)
8322  output_columns.push_back("X,");
8323  else {
8324  QString str = "X(";
8325  str += ostr.str().c_str();
8326  str += "),";
8327  output_columns.push_back(str);
8328  }
8329  }
8330  ostr.str("");
8331  strcoeff--;
8332  }
8333  strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
8334  for (int i = 0; i < ncoeff; i++) {
8335  if (i == 0)
8336  ostr << strcoeff;
8337  else if (i == 1)
8338  ostr << strcoeff << "t";
8339  else
8340  ostr << strcoeff << "t" << i;
8341  for (int j = 0; j < 5; j++) {
8342  if (ncoeff == 1)
8343  output_columns.push_back("Y,");
8344  else {
8345  QString str = "Y(";
8346  str += ostr.str().c_str();
8347  str += "),";
8348  output_columns.push_back(str);
8349  }
8350  }
8351  ostr.str("");
8352  strcoeff--;
8353  }
8354  strcoeff = 'a' + m_nNumberCamPosCoefSolved - 1;
8355  for (int i = 0; i < ncoeff; i++) {
8356  if (i == 0)
8357  ostr << strcoeff;
8358  else if (i == 1)
8359  ostr << strcoeff << "t";
8360  else
8361  ostr << strcoeff << "t" << i;
8362  for (int j = 0; j < 5; j++) {
8363  if (ncoeff == 1) {
8364  output_columns.push_back("Z,");
8365  }
8366  else {
8367  QString str = "Z(";
8368  str += ostr.str().c_str();
8369  str += "),";
8370  output_columns.push_back(str);
8371  }
8372  }
8373  ostr.str("");
8374  strcoeff--;
8375  if (!m_bSolveTwist)
8376  break;
8377  }
8378 
8379  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
8380  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8381  if(i == 0)
8382  ostr << strcoeff;
8383  else if (i == 1)
8384  ostr << strcoeff << "t";
8385  else
8386  ostr << strcoeff << "t" << i;
8387  for (int j = 0; j < 5; j++) {
8388  if (m_nNumberCamAngleCoefSolved == 1)
8389  output_columns.push_back("RA,");
8390  else {
8391  QString str = "RA(";
8392  str += ostr.str().c_str();
8393  str += "),";
8394  output_columns.push_back(str);
8395  }
8396  }
8397  ostr.str("");
8398  strcoeff--;
8399  }
8400  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
8401  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8402  if (i == 0)
8403  ostr << strcoeff;
8404  else if (i == 1)
8405  ostr << strcoeff << "t";
8406  else
8407  ostr << strcoeff << "t" << i;
8408  for (int j = 0; j < 5; j++) {
8409  if (m_nNumberCamAngleCoefSolved == 1)
8410  output_columns.push_back("DEC,");
8411  else {
8412  QString str = "DEC(";
8413  str += ostr.str().c_str();
8414  str += "),";
8415  output_columns.push_back(str);
8416  }
8417  }
8418  ostr.str("");
8419  strcoeff--;
8420  }
8421  strcoeff = 'a' + m_nNumberCamAngleCoefSolved - 1;
8422  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8423  if (i == 0)
8424  ostr << strcoeff;
8425  else if (i == 1)
8426  ostr << strcoeff << "t";
8427  else
8428  ostr << strcoeff << "t" << i;
8429  for (int j = 0; j < 5; j++) {
8430  if (m_nNumberCamAngleCoefSolved == 1 || !m_bSolveTwist) {
8431  output_columns.push_back("TWIST,");
8432  }
8433  else {
8434  QString str = "TWIST(";
8435  str += ostr.str().c_str();
8436  str += "),";
8437  output_columns.push_back(str);
8438  }
8439  }
8440  ostr.str("");
8441  strcoeff--;
8442  if (!m_bSolveTwist)
8443  break;
8444  }
8445 
8446  // print first column header to buffer and output to file
8447  int ncolumns = output_columns.size();
8448  for (int i = 0; i < ncolumns; i++) {
8449  QString str = output_columns.at(i);
8450  sprintf(buf, "%s", (const char*)str.toAscii().data());
8451  fp_out << buf;
8452  }
8453  sprintf(buf, "\n");
8454  fp_out << buf;
8455 
8456  output_columns.clear();
8457  output_columns.push_back("Filename,");
8458 
8459  output_columns.push_back("sample res,");
8460  output_columns.push_back("line res,");
8461  output_columns.push_back("total res,");
8462 
8463  int nparams = 3;
8464  if (m_nNumberCamPosCoefSolved)
8465  nparams = 3 * m_nNumberCamPosCoefSolved;
8466 
8467  int numCameraAnglesSolved = 2;
8468  if (m_bSolveTwist) numCameraAnglesSolved++;
8469  nparams += numCameraAnglesSolved*m_nNumberCamAngleCoefSolved;
8470  if (!m_bSolveTwist) nparams += 1; // Report on twist only
8471  for (int i = 0; i < nparams; i++) {
8472  output_columns.push_back("Initial,");
8473  output_columns.push_back("Correction,");
8474  output_columns.push_back("Final,");
8475  output_columns.push_back("Apriori Sigma,");
8476  output_columns.push_back("Adj Sigma,");
8477  }
8478 
8479  // print second column header to buffer and output to file
8480  ncolumns = output_columns.size();
8481  for (int i = 0; i < ncolumns; i++) {
8482  QString str = output_columns.at(i);
8483  sprintf(buf, "%s", (const char*)str.toAscii().data());
8484  fp_out << buf;
8485  }
8486  sprintf(buf, "\n");
8487  fp_out << buf;
8488 
8489  Camera *pCamera = NULL;
8490  SpicePosition *pSpicePosition = NULL;
8491  SpiceRotation *pSpiceRotation = NULL;
8492 
8493  int nImages = Images();
8494  double dSigma = 0.;
8495  int nIndex = 0;
8496  bool bSolveSparse = false;
8497  //bool bHeld = false;
8498  std::vector<double> coefX(m_nNumberCamPosCoefSolved);
8499  std::vector<double> coefY(m_nNumberCamPosCoefSolved);
8500  std::vector<double> coefZ(m_nNumberCamPosCoefSolved);
8501  std::vector<double> coefRA(m_nNumberCamAngleCoefSolved);
8502  std::vector<double> coefDEC(m_nNumberCamAngleCoefSolved);
8503  std::vector<double> coefTWI(m_nNumberCamAngleCoefSolved);
8504  std::vector<double> angles;
8505 
8506  output_columns.clear();
8507 
8508  gmm::row_matrix<gmm::rsvector<double> > lsqCovMatrix;
8509  if (m_strSolutionMethod == "OLDSPARSE" && m_bErrorPropagation) {
8510  // Get reference to the covariance matrix from the least-squares object
8511  lsqCovMatrix = m_pLsq->GetCovarianceMatrix();
8512  bSolveSparse = true;
8513  }
8514 
8515  // data structure to contain adjusted image parameter sigmas for CHOLMOD error propagation only
8516  vector<double> vImageAdjustedSigmas;
8517 
8518  std::vector<double> BFP(3);
8519 
8520  for (int i = 0; i < nImages; i++) {
8521 
8522  //if (m_nHeldImages > 0 &&
8523  // m_pHeldSnList->HasSerialNumber(m_pSnList->SerialNumber(i)) )
8524  // bHeld = true;
8525 
8526  pCamera = m_pCnet->Camera(i);
8527  if (!pCamera)
8528  continue;
8529 
8530  // ImageIndex(i) retrieves index into the normal equations matrix for
8531  // Image(i)
8532  nIndex = ImageIndex(i) ;
8533 
8534  if (m_bErrorPropagation && m_bConverged && (m_decompositionMethod == CHOLMOD))
8535  vImageAdjustedSigmas = m_Image_AdjustedSigmas.at(i);
8536 
8537  pSpicePosition = pCamera->instrumentPosition();
8538  if (!pSpicePosition)
8539  continue;
8540 
8541  pSpiceRotation = pCamera->instrumentRotation();
8542  if (!pSpiceRotation)
8543  continue;
8544 
8545  // for frame cameras we directly retrieve the J2000 Exterior Orientation
8546  // (i.e. position and orientation angles). For others (linescan, radar)
8547  // we retrieve the polynomial coefficients from which the Exterior
8548  // Orientation parameters are derived.
8549  if (m_spacecraftPositionSolveType > 0)
8550  pSpicePosition->GetPolynomial(coefX, coefY, coefZ);
8551  else { // not solving for position so report state at center of image
8552  std::vector <double> coordinate(3);
8553  coordinate = pSpicePosition->GetCenterCoordinate();
8554 
8555  coefX.push_back(coordinate[0]);
8556  coefY.push_back(coordinate[1]);
8557  coefZ.push_back(coordinate[2]);
8558  }
8559 
8560  if (m_cmatrixSolveType > 0)
8561  pSpiceRotation->GetPolynomial(coefRA,coefDEC,coefTWI);
8562 // else { // frame camera
8563  else if (pCamera->GetCameraType() != 3) {
8564 // This is for m_cmatrixSolveType = None (except Radar which has no pointing)
8565 // and no polynomial fit has occurred
8566  angles = pSpiceRotation->GetCenterAngles();
8567  coefRA.push_back(angles.at(0));
8568  coefDEC.push_back(angles.at(1));
8569  coefTWI.push_back(angles.at(2));
8570  }
8571 
8572  // clear column vector
8573  output_columns.clear();
8574 
8575  // add filename
8576  output_columns.push_back(m_pSnList->FileName(i).toAscii().data());
8577 
8578  // add rms of sample, line, total image coordinate residuals
8579  output_columns.push_back(
8580  toString(m_rmsImageSampleResiduals[i].Rms()));
8581  output_columns.push_back(
8582  toString(m_rmsImageLineResiduals[i].Rms()));
8583  output_columns.push_back(
8584  toString(m_rmsImageResiduals[i].Rms()));
8585 
8586  int nSigmaIndex = 0;
8587  if (m_nNumberCamPosCoefSolved > 0) {
8588  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
8589 
8590  if (m_bErrorPropagation && m_bConverged) {
8591  if (bSolveSparse)
8592  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8593  else if (m_decompositionMethod == CHOLMOD)
8594  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8595  else if (m_decompositionMethod == SPECIALK)
8596  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8597  }
8598 
8599  output_columns.push_back(
8600  toString(coefX[0] - m_Image_Corrections(nIndex)));
8601  output_columns.push_back(
8602  toString(m_Image_Corrections(nIndex)));
8603  output_columns.push_back(
8604  toString(coefX[i]));
8605  output_columns.push_back(
8606  toString(m_dGlobalSpacecraftPositionAprioriSigma[i]));
8607 
8608  if (m_bErrorPropagation && m_bConverged)
8609  output_columns.push_back(
8610  toString(dSigma));
8611  else
8612  output_columns.push_back("N/A");
8613  nIndex++;
8614  nSigmaIndex++;
8615  }
8616  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
8617 
8618  if (m_bErrorPropagation && m_bConverged) {
8619  if (bSolveSparse)
8620  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8621  else if (m_decompositionMethod == CHOLMOD)
8622  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8623  else if (m_decompositionMethod == SPECIALK)
8624  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8625  }
8626 
8627  output_columns.push_back(
8628  toString(coefY[0] - m_Image_Corrections(nIndex)));
8629  output_columns.push_back(
8630  toString(m_Image_Corrections(nIndex)));
8631  output_columns.push_back(
8632  toString(coefY[i]));
8633  output_columns.push_back(
8634  toString(m_dGlobalSpacecraftPositionAprioriSigma[i]));
8635 
8636  if (m_bErrorPropagation && m_bConverged)
8637  output_columns.push_back(
8638  toString(dSigma));
8639  else
8640  output_columns.push_back("N/A");
8641  nIndex++;
8642  nSigmaIndex++;
8643  }
8644  for (int i = 0; i < m_nNumberCamPosCoefSolved; i++) {
8645 
8646  if (m_bErrorPropagation && m_bConverged) {
8647  if (bSolveSparse)
8648  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8649  else if (m_decompositionMethod == CHOLMOD)
8650  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8651  else if (m_decompositionMethod == SPECIALK)
8652  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8653  }
8654 
8655  output_columns.push_back(
8656  toString(coefZ[0] - m_Image_Corrections(nIndex)));
8657  output_columns.push_back(
8658  toString(m_Image_Corrections(nIndex)));
8659  output_columns.push_back(
8660  toString(coefZ[i]));
8661  output_columns.push_back(
8662  toString(m_dGlobalSpacecraftPositionAprioriSigma[i]));
8663 
8664  if (m_bErrorPropagation && m_bConverged)
8665  output_columns.push_back(toString
8666  (dSigma));
8667  else
8668  output_columns.push_back("N/A");
8669  nIndex++;
8670  nSigmaIndex++;
8671  }
8672  }
8673  else {
8674  output_columns.push_back(toString(coefX[0]));
8675  output_columns.push_back(toString(0));
8676  output_columns.push_back(toString(coefX[0]));
8677  output_columns.push_back(toString(0));
8678  output_columns.push_back("N/A");
8679  output_columns.push_back(toString(coefY[0]));
8680  output_columns.push_back(toString(0));
8681  output_columns.push_back(toString(coefY[0]));
8682  output_columns.push_back(toString(0));
8683  output_columns.push_back("N/A");
8684  output_columns.push_back(toString(coefZ[0]));
8685  output_columns.push_back(toString(0));
8686  output_columns.push_back(toString(coefZ[0]));
8687  output_columns.push_back(toString(0));
8688  output_columns.push_back("N/A");
8689  }
8690 
8691  if (m_nNumberCamAngleCoefSolved > 0) {
8692  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8693 
8694  if (m_bErrorPropagation && m_bConverged) {
8695  if (bSolveSparse)
8696  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8697  else if (m_decompositionMethod == CHOLMOD)
8698  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8699  else if (m_decompositionMethod == SPECIALK)
8700  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8701  }
8702 
8703  output_columns.push_back(toString
8704  ((coefRA[i] - m_Image_Corrections(nIndex)) * RAD2DEG));
8705  output_columns.push_back(toString
8706  (m_Image_Corrections(nIndex) * RAD2DEG));
8707  output_columns.push_back(toString
8708  (coefRA[i] * RAD2DEG));
8709  output_columns.push_back(toString(
8710  m_dGlobalCameraAnglesAprioriSigma[i]));
8711 
8712  if (m_bErrorPropagation && m_bConverged)
8713  output_columns.push_back(toString
8714  (dSigma * RAD2DEG));
8715  else
8716  output_columns.push_back("N/A");
8717  nIndex++;
8718  nSigmaIndex++;
8719  }
8720  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8721 
8722  if (m_bErrorPropagation && m_bConverged) {
8723  if (bSolveSparse)
8724  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8725  else if (m_decompositionMethod == CHOLMOD)
8726  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8727  else if (m_decompositionMethod == SPECIALK)
8728  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8729  }
8730 
8731  output_columns.push_back(toString
8732  ((coefDEC[i] - m_Image_Corrections(nIndex)) * RAD2DEG));
8733  output_columns.push_back(toString
8734  (m_Image_Corrections(nIndex) * RAD2DEG));
8735  output_columns.push_back(toString
8736  (coefDEC[i] * RAD2DEG));
8737  output_columns.push_back(toString
8738  (m_dGlobalCameraAnglesAprioriSigma[i]));
8739 
8740  if (m_bErrorPropagation && m_bConverged)
8741  output_columns.push_back(toString
8742  (dSigma * RAD2DEG));
8743  else
8744  output_columns.push_back("N/A");
8745  nIndex++;
8746  nSigmaIndex++;
8747  }
8748  if (!m_bSolveTwist) {
8749  output_columns.push_back(toString
8750  (coefTWI[0]*RAD2DEG));
8751  output_columns.push_back(toString(0.0));
8752  output_columns.push_back(toString
8753  (coefTWI[0]*RAD2DEG));
8754  output_columns.push_back(toString(0.0));
8755  output_columns.push_back("N/A");
8756  }
8757  else {
8758  for (int i = 0; i < m_nNumberCamAngleCoefSolved; i++) {
8759 
8760  if (m_bErrorPropagation && m_bConverged) {
8761  if (bSolveSparse)
8762  dSigma = sqrt((double)(lsqCovMatrix(nIndex, nIndex)));
8763  else if (m_decompositionMethod == CHOLMOD)
8764  dSigma = sqrt(vImageAdjustedSigmas[nSigmaIndex]) * m_dSigma0;
8765  else if (m_decompositionMethod == SPECIALK)
8766  dSigma = sqrt((double)(m_Normals(nIndex, nIndex))) * m_dSigma0;
8767  }
8768 
8769  output_columns.push_back(toString
8770  ((coefTWI[i] - m_Image_Corrections(nIndex)) * RAD2DEG));
8771  output_columns.push_back(toString
8772  (m_Image_Corrections(nIndex) * RAD2DEG));
8773  output_columns.push_back(toString
8774  (coefTWI[i] * RAD2DEG));
8775  output_columns.push_back(toString
8776  (m_dGlobalCameraAnglesAprioriSigma[i]));
8777 
8778  if (m_bErrorPropagation && m_bConverged)
8779  output_columns.push_back(toString
8780  (dSigma * RAD2DEG));
8781  else
8782  output_columns.push_back("N/A");
8783  nIndex++;
8784  nSigmaIndex++;
8785  }
8786  }
8787  }
8788 
8789  else if (pCamera->GetCameraType() != 3) {
8790  output_columns.push_back(toString
8791  (coefRA[0]*RAD2DEG));
8792  output_columns.push_back(toString(0.0));
8793  output_columns.push_back(toString
8794  (coefRA[0]*RAD2DEG));
8795  output_columns.push_back(toString(0.0));
8796  output_columns.push_back("N/A");
8797  output_columns.push_back(toString
8798  (coefDEC[0]*RAD2DEG));
8799  output_columns.push_back(toString(0.0));
8800  output_columns.push_back(toString
8801  (coefDEC[0]*RAD2DEG));
8802  output_columns.push_back(toString(0.0));
8803  output_columns.push_back("N/A");
8804  output_columns.push_back(toString
8805  (coefTWI[0]*RAD2DEG));
8806  output_columns.push_back(toString(0.0));
8807  output_columns.push_back(toString
8808  (coefTWI[0]*RAD2DEG));
8809  output_columns.push_back(toString(0.0));
8810  output_columns.push_back("N/A");
8811  }
8812 
8813  // print column vector to buffer and output to file
8814  int ncolumns = output_columns.size();
8815  for (int i = 0; i < ncolumns; i++) {
8816  QString str = output_columns.at(i);
8817 
8818  if (i < ncolumns-1)
8819  sprintf(buf, "%s,", (const char*)str.toAscii().data());
8820  else
8821  sprintf(buf, "%s", (const char*)str.toAscii().data());
8822  fp_out << buf;
8823  }
8824  sprintf(buf, "\n");
8825  fp_out << buf;
8826  }
8827 
8828  fp_out.close();
8829 
8830  return true;
8831  }
8832 
8833 
8838  void BundleAdjust::SetSolutionMethod(QString str) {
8839  m_strSolutionMethod = str;
8840  FillPointIndexMap();
8841  }
8842 
8843 
8847  void BundleAdjust::maximumLikelihoodSetup( QList<QString> models, QList<double> quantiles ) {
8848  m_wFunc[0]=m_wFunc[1]=m_wFunc[2]=NULL; //initialize to NULL
8849  m_maxLikelihoodFlag[0]=m_maxLikelihoodFlag[1]=m_maxLikelihoodFlag[2]=false; //NULL flag by defualt
8850  if (models.size() == 0) { //MaximumLikeliHood Estimation not being used, so leave everything NULL
8851  m_cumPro=NULL;
8852  }
8853  else {
8854  m_cumPro = new StatCumProbDistDynCalc;
8855  m_cumPro->initialize(101); //set up the cum probibility solver to have a node at every percent of the distribution
8856  for (int i=0;i<models.size() && i<3;i++) {
8857  m_maxLikelihoodFlag[i] = true;
8858  m_wFunc[i] = new MaximumLikelihoodWFunctions;
8859  if (models[i].compare("HUBER") == 0)
8860  m_wFunc[i]->setModel(MaximumLikelihoodWFunctions::Huber);
8861  else if (models[i].compare("HUBER_MODIFIED") == 0)
8862  m_wFunc[i]->setModel(MaximumLikelihoodWFunctions::HuberModified);
8863  else if (models[i].compare("WELSCH") == 0)
8864  m_wFunc[i]->setModel(MaximumLikelihoodWFunctions::Welsch);
8865  else if (models[i].compare("CHEN") == 0)
8866  m_wFunc[i]->setModel(MaximumLikelihoodWFunctions::Chen);
8867  else {
8868  QString msg = "Unsuported Maximum Likelihood estimation model: " + models[i] + "\n";
8869  m_maxLikelihoodFlag[i] = false;
8870  throw IException(IException::Io, msg, _FILEINFO_);
8871  }
8872  }
8873  }
8874  for (int i=0;i<quantiles.size() && i<3;i++)
8875  m_maxLikelihoodQuan[i] = quantiles[i];
8876 
8877  //maximum likelihood estimation tiered solutions requiring multiple convergeances are support,
8878  // this index keeps track of which tier the solution is in
8879  m_maxLikelihoodIndex=0;
8880  }
8881 }