10 #include <QXmlStreamWriter> 14 #include "ControlList.h" 19 #include "ImageList.h" 27 #include "XmlStackedHandlerReader.h" 44 m_id =
new QUuid(QUuid::createUuid());
49 m_outputControlName=
"";
64 BundleSolutionInfo::BundleSolutionInfo(
Project *project,
68 m_id =
new QUuid(QUuid::createUuid());
73 m_outputControlName=
"";
79 xmlReader->setErrorHandler(
new XmlHandler(
this, project));
119 return m_txtBundleOutputFilename;
129 return m_csvSavedImagesFilename;
139 return m_csvSavedPointsFilename;
149 return m_csvSavedResidualsFilename;
193 oldInputFileName.
dir().dirName() +
"/" + oldInputFileName.
name());
198 oldOutputFileName.dir().dirName() +
"/" + oldOutputFileName.name());
204 m_outputControlName = newOutputFileName.expanded();
225 return m_id->toString().remove(QRegExp(
"[{}]"));
281 return m_outputControlName;
301 m_outputControlName =
name;
311 return m_outputControlName;
347 "Results for this bundle is NULL.",
403 std::vector<QString> outputColumns;
405 outputColumns.push_back(
"Image,");
406 outputColumns.push_back(
"rms,");
407 outputColumns.push_back(
"rms,");
408 outputColumns.push_back(
"rms,");
416 if (numberCamPosCoefSolved > 0)
417 nCoeff = numberCamPosCoefSolved;
419 for (
int i = 0; i < nCoeff; i++) {
420 for (
int j = 0; j < 5; j++) {
422 outputColumns.push_back(
"X,");
424 QString str =
"X(t" +
toString(i) +
"),";
425 outputColumns.push_back(str);
429 for (
int i = 0; i < nCoeff; i++) {
430 for (
int j = 0; j < 5; j++) {
432 outputColumns.push_back(
"Y,");
434 QString str =
"Y(t" +
toString(i) +
"),";
435 outputColumns.push_back(str);
439 for (
int i = 0; i < nCoeff; i++) {
440 for (
int j = 0; j < 5; j++) {
442 outputColumns.push_back(
"Z,");
445 QString str =
"Z(t" +
toString(i) +
"),";
446 outputColumns.push_back(str);
453 for (
int i = 0; i < numberCamAngleCoefSolved; i++) {
454 for (
int j = 0; j < 5; j++) {
455 if (numberCamAngleCoefSolved == 1)
456 outputColumns.push_back(
"RA,");
458 QString str =
"RA(t" +
toString(i) +
"),";
459 outputColumns.push_back(str);
463 for (
int i = 0; i < numberCamAngleCoefSolved; i++) {
464 for (
int j = 0; j < 5; j++) {
465 if (numberCamAngleCoefSolved == 1)
466 outputColumns.push_back(
"DEC,");
468 QString str =
"DEC(t" +
toString(i) +
"),";
469 outputColumns.push_back(str);
473 for (
int i = 0; i < numberCamAngleCoefSolved; i++) {
474 for (
int j = 0; j < 5; j++) {
475 if (numberCamAngleCoefSolved == 1) {
476 outputColumns.push_back(
"TWIST,");
479 QString str =
"TWIST(t" +
toString(i) +
"),";
480 outputColumns.push_back(str);
486 int ncolumns = outputColumns.size();
487 for (
int i = 0; i < ncolumns; i++) {
488 QString str = outputColumns.at(i);
489 sprintf(buf,
"%s", (
const char*)str.toLatin1().data());
495 outputColumns.clear();
496 outputColumns.push_back(
"Filename,");
498 outputColumns.push_back(
"sample res,");
499 outputColumns.push_back(
"line res,");
500 outputColumns.push_back(
"total res,");
505 if (numberCamPosCoefSolved)
506 nparams = 3 * numberCamPosCoefSolved;
509 int numCameraAnglesSolved = 3;
511 nparams += numCameraAnglesSolved*numberCamAngleCoefSolved;
512 for (
int i = 0; i < nparams; i++) {
513 outputColumns.push_back(
"Initial,");
514 outputColumns.push_back(
"Correction,");
515 outputColumns.push_back(
"Final,");
516 outputColumns.push_back(
"Apriori Sigma,");
517 outputColumns.push_back(
"Adj Sigma,");
521 ncolumns = outputColumns.size();
522 for (
int i = 0; i < ncolumns; i++) {
523 QString str = outputColumns.at(i);
524 sprintf(buf,
"%s", (
const char*)str.toLatin1().data());
556 for (
int i = 0; i < numObservations; i++) {
560 int numInnerConstraints = 0;
561 int numDistanceConstraints = 0;
568 int convergenceCriteria = 1;
570 sprintf(buf,
"JIGSAW: BUNDLE ADJUSTMENT\n=========================\n");
572 sprintf(buf,
"\n Run Time: %s",
575 sprintf(buf,
"\n Network Filename: %s",
579 sprintf(buf,
"\n Cube List: %s",
580 m_settings->cubeList().toStdString().c_str() );
584 sprintf(buf,
"\n Output Network Filename: %s",
587 sprintf(buf,
"\n Output File Prefix: %s",
588 m_settings->outputFilePrefix().toStdString().c_str() );
591 sprintf(buf,
"\n Network Id: %s",
594 sprintf(buf,
"\n Network Description: %s",\
597 sprintf(buf,
"\n Target: %s",
600 sprintf(buf,
"\n\n Linear Units: kilometers");
602 sprintf(buf,
"\n Angular Units: decimal degrees");
604 sprintf(buf,
"\n\nINPUT: SOLVE OPTIONS\n====================\n");
608 sprintf(buf,
"\n OBSERVATIONS: ON"):
609 sprintf(buf,
"\n OBSERVATIONS: OFF");
613 sprintf(buf,
"\n RADIUS: ON"):
614 sprintf(buf,
"\n RADIUS: OFF");
618 sprintf(buf,
"\n TARGET BODY: ON"):
619 sprintf(buf,
"\n TARGET BODY: OFF");
623 sprintf(buf,
"\n UPDATE: YES"):
624 sprintf(buf,
"\n UPDATE: NO");
628 sprintf(buf,
"\n ERROR PROPAGATION: ON"):
629 sprintf(buf,
"\n ERROR PROPAGATION: OFF");
633 sprintf(buf,
"\n CONTROL POINT COORDINATE TYPE FOR REPORTS: LATITUDINAL"):
634 sprintf(buf,
"\n CONTROL POINT COORDINATE TYPE FOR REPORTS: RECTANGULAR");
638 sprintf(buf,
"\n CONTROL POINT COORDINATE TYPE FOR BUNDLE: LATITUDINAL"):
639 sprintf(buf,
"\n CONTROL POINT COORDINATE TYPE FOR BUNDLE: RECTANGULAR");
643 sprintf(buf,
"\n OUTLIER REJECTION: ON");
645 sprintf(buf,
"\n REJECTION MULTIPLIER: %lf",
651 sprintf(buf,
"\n OUTLIER REJECTION: OFF");
653 sprintf(buf,
"\n REJECTION MULTIPLIER: N/A");
658 sprintf(buf,
"\n CONTROL POINT COORDINATE TYPE FOR REPORTS: %s",
662 sprintf(buf,
"\n CONTROL POINT COORDINATE TYPE FOR BUNDLE: %s",
665 sprintf(buf,
"\n\nMAXIMUM LIKELIHOOD ESTIMATION\n============================\n");
668 for (
int tier = 0; tier < 3; tier++) {
669 if (tier < m_statisticsResults->numberMaximumLikelihoodModels()) {
670 sprintf(buf,
"\n Tier %d Enabled: TRUE", tier);
672 sprintf(buf,
"\n Maximum Likelihood Model: %s",
675 maximumLikelihoodModelWFunc(tier).model()).toLatin1().data());
677 sprintf(buf,
"\n Quantile used for tweaking constant: %lf",
680 sprintf(buf,
"\n Quantile weighted R^2 Residual value: %lf",
683 sprintf(buf,
"\n Approx. weighted Residual cutoff: %s",
687 if (tier != 2) fpOut <<
"\n";
690 sprintf(buf,
"\n Tier %d Enabled: FALSE", tier);
695 sprintf(buf,
"\n\nINPUT: CONVERGENCE CRITERIA\n===========================\n");
697 sprintf(buf,
"\n SIGMA0: %e",
700 sprintf(buf,
"\n MAXIMUM ITERATIONS: %d",
701 m_settings->convergenceCriteriaMaximumIterations());
715 sprintf(buf,
"\n\nINPUT: CAMERA POINTING OPTIONS\n==============================\n");
717 switch (pointingSolveDegree) {
719 sprintf(buf,
"\n CAMSOLVE: NONE");
722 sprintf(buf,
"\n CAMSOLVE: ANGLES");
725 sprintf(buf,
"\n CAMSOLVE: ANGLES, VELOCITIES");
728 sprintf(buf,
"\n CAMSOLVE: ANGLES, VELOCITIES, ACCELERATIONS");
731 sprintf(buf,
"\n CAMSOLVE: ALL POLYNOMIAL COEFFICIENTS (%d)" 733 "\n CKSOLVEDEGREE: %d",
741 sprintf(buf,
"\n TWIST: ON"):
742 sprintf(buf,
"\n TWIST: OFF");
745 sprintf(buf,
"\n POLYNOMIAL OVER EXISTING POINTING: ON"):
746 sprintf(buf,
"\nPOLYNOMIAL OVER EXISTING POINTING : OFF");
749 sprintf(buf,
"\n\nINPUT: SPACECRAFT OPTIONS\n=========================\n");
751 switch (positionSolveDegree) {
753 sprintf(buf,
"\n SPSOLVE: NONE");
756 sprintf(buf,
"\n SPSOLVE: POSITION");
759 sprintf(buf,
"\n SPSOLVE: POSITION, VELOCITIES");
762 sprintf(buf,
"\n SPSOLVE: POSITION, VELOCITIES, ACCELERATIONS");
765 sprintf(buf,
"\n SPSOLVE: ALL POLYNOMIAL COEFFICIENTS (%d)" 767 "\n SPKSOLVEDEGREE: %d",
775 sprintf(buf,
"\n POLYNOMIAL OVER HERMITE SPLINE: ON"):
776 sprintf(buf,
"\nPOLYNOMIAL OVER HERMITE SPLINE : OFF");
779 sprintf(buf,
"\n\nINPUT: GLOBAL IMAGE PARAMETER UNCERTAINTIES\n===========================================\n");
783 switch (
m_settings->controlPointCoordTypeReports()) {
785 coord1Str =
"LATITUDE";
786 coord2Str =
"LONGITUDE";
787 coord3Str =
"RADIUS";
795 IString msg =
"Unknown surface point coordinate type enum [" 804 sprintf(buf,
"\n POINT %s SIGMA: N/A", coord1Str.toLatin1().data()):
805 sprintf(buf,
"\n POINT %s SIGMA: %lf (meters)", coord1Str.toLatin1().data(),
810 sprintf(buf,
"\n POINT %s SIGMA: N/A", coord2Str.toLatin1().data()):
811 sprintf(buf,
"\n POINT %s SIGMA: %lf (meters)", coord2Str.toLatin1().data(),
816 sprintf(buf,
"\n POINT %s SIGMA: N/A", coord3Str.toLatin1().data()):
817 sprintf(buf,
"\n POINT %s SIGMA: %lf (meters)", coord3Str.toLatin1().data(),
820 (positionSolveDegree < 1 || positionSigmas[0] ==
Isis::Null) ?
821 sprintf(buf,
"\n SPACECRAFT POSITION SIGMA: N/A"):
822 sprintf(buf,
"\n SPACECRAFT POSITION SIGMA: %lf (meters)",
826 (positionSolveDegree < 2 || positionSigmas[1] ==
Isis::Null) ?
827 sprintf(buf,
"\n SPACECRAFT VELOCITY SIGMA: N/A"):
828 sprintf(buf,
"\n SPACECRAFT VELOCITY SIGMA: %lf (m/s)",
832 (positionSolveDegree < 3 || positionSigmas[2] ==
Isis::Null) ?
833 sprintf(buf,
"\n SPACECRAFT ACCELERATION SIGMA: N/A"):
834 sprintf(buf,
"\n SPACECRAFT ACCELERATION SIGMA: %lf (m/s/s)",
838 (pointingSolveDegree < 1 || pointingSigmas[0] ==
Isis::Null) ?
839 sprintf(buf,
"\n CAMERA ANGLES SIGMA: N/A"):
840 sprintf(buf,
"\n CAMERA ANGLES SIGMA: %lf (dd)",
844 (pointingSolveDegree < 2 || pointingSigmas[1] ==
Isis::Null) ?
845 sprintf(buf,
"\n CAMERA ANGULAR VELOCITY SIGMA: N/A"):
846 sprintf(buf,
"\n CAMERA ANGULAR VELOCITY SIGMA: %lf (dd/s)",
850 (pointingSolveDegree < 3 || pointingSigmas[2] ==
Isis::Null) ?
851 sprintf(buf,
"\n CAMERA ANGULAR ACCELERATION SIGMA: N/A"):
852 sprintf(buf,
"\n CAMERA ANGULAR ACCELERATION SIGMA: %lf (dd/s/s)",
857 sprintf(buf,
"\n\nINPUT: TARGET BODY OPTIONS\n==============================\n");
861 sprintf(buf,
"\n POLE: RIGHT ASCENSION");
863 sprintf(buf,
"\n : DECLINATION\n");
867 sprintf(buf,
"\n POLE: RIGHT ASCENSION\n");
871 sprintf(buf,
"\n POLE: DECLINATION\n");
877 sprintf(buf,
"\n PRIME MERIDIAN: W0 (OFFSET)");
881 sprintf(buf,
"\n : WDOT (SPIN RATE)");
885 sprintf(buf,
"\n :W ACCELERATION");
892 sprintf(buf,
"\n RADII: MEAN");
896 sprintf(buf,
"\n RADII: TRIAXIAL");
902 sprintf(buf,
"\n\nJIGSAW: RESULTS\n===============\n");
904 sprintf(buf,
"\n Images: %6d",numImages);
906 sprintf(buf,
"\n Points: %6d",numValidPoints);
909 sprintf(buf,
"\n Total Measures: %6d",
914 sprintf(buf,
"\n Total Observations: %6d",
919 sprintf(buf,
"\n Good Observations: %6d",
923 sprintf(buf,
"\n Rejected Observations: %6d",
928 sprintf(buf,
"\n Constrained Point Parameters: %6d",
934 sprintf(buf,
"\n Constrained Image Parameters: %6d",
940 sprintf(buf,
"\n Constrained Target Parameters: %6d",
945 sprintf(buf,
"\n Unknowns: %6d",
949 if (numInnerConstraints > 0) {
950 sprintf(buf,
"\n Inner Constraints: %6d", numInnerConstraints);
954 if (numDistanceConstraints > 0) {
955 sprintf(buf,
"\n Distance Constraints: %d", numDistanceConstraints);
959 sprintf(buf,
"\n Degrees of Freedom: %6d", numDegreesOfFreedom);
962 sprintf(buf,
"\n Convergence Criteria: %6.3g",
966 if (convergenceCriteria == 1) {
967 sprintf(buf,
"(Sigma0)");
975 sprintf(buf,
"(Maximum reached)");
981 sprintf(buf,
" Error Propagation Elapsed Time: %6.4lf (seconds)\n",
984 sprintf(buf,
" Total Elapsed Time: %6.4lf (seconds)\n",
990 sprintf(buf,
"\n Residual Percentiles:\n");
996 for (
int bin = 1;bin < 34;bin++) {
997 double cumProb = double(bin) / 100.0;
1000 residualsCumulativeProbabilityDistribution().value(cumProb);
1003 residualsCumulativeProbabilityDistribution().value(cumProb + 0.33);
1006 residualsCumulativeProbabilityDistribution().value(cumProb + 0.66);
1007 sprintf(buf,
" Percentile %3d: %+8.3lf" 1008 " Percentile %3d: %+8.3lf" 1009 " Percentile %3d: %+8.3lf\n",
1011 bin + 33, resValue33,
1012 bin + 66, resValue66);
1017 QString msg =
"Failed to output residual percentiles for bundleout";
1021 sprintf(buf,
"\n Residual Box Plot:");
1023 sprintf(buf,
"\n minimum: %+8.3lf",
1026 sprintf(buf,
"\n Quartile 1: %+8.3lf",
1029 sprintf(buf,
"\n Median: %+8.3lf",
1032 sprintf(buf,
"\n Quartile 3: %+8.3lf",
1035 sprintf(buf,
"\n maximum: %+8.3lf\n",
1040 QString msg =
"Failed to output residual box plot for bundleout";
1045 sprintf(buf,
"\nIMAGE MEASURES SUMMARY\n==========================\n\n");
1047 sprintf(buf,
" Measures RMS(pixels)\n");
1049 sprintf(buf,
" ************************ " 1050 "**************************************\n");
1053 sprintf(buf,
" |Accepted | Total| |Samples | " 1054 "Lines | Total|\n");
1058 int numRejectedMeasures;
1061 Statistics rmsSamplesTotal,rmsLinesTotal,rmsTotals;
1063 for (
int i = 0; i < numObservations; i++) {
1067 for (
int j = 0; j < numImagesInObservation; j++) {
1072 rmsImageSampleResiduals()[imageIndex].Rms();
1074 rmsImageLineResiduals()[imageIndex].Rms();
1076 rmsImageResiduals()[imageIndex].Rms();
1077 rmsSamplesTotal.
AddData(rmsSampleResiduals);
1078 rmsLinesTotal.
AddData(rmsLineResiduals);
1079 rmsTotals.
AddData(rmsLandSResiduals);
1082 (bundleImage->serialNumber());
1085 GetNumberOfJigsawRejectedMeasuresInImage(bundleImage->serialNumber());
1087 numUsed = numMeasures - numRejectedMeasures;
1089 sprintf(buf,
"%30s" ,bundleImage->fileName().toLatin1().data());
1092 sprintf(buf,
"%5d %5d ",numUsed,numMeasures);
1095 sprintf(buf,
"%-15.4lf%-15.4lf%-15.4lf \n",
1096 rmsSampleResiduals,rmsLineResiduals,rmsLandSResiduals);
1103 sprintf(buf,
"\nTotal RMS:");
1107 sprintf(buf,
"%-15.4lf%-15.4lf%-15.4lf\n",
1108 rmsSamplesTotal.
Rms(),rmsLinesTotal.
Rms(),rmsTotals.
Rms());
1135 QString ofname =
"bundleout_images.csv";
1136 ofname =
m_settings->outputFilePrefix() + ofname;
1137 m_csvSavedImagesFilename = ofname;
1139 std::ofstream fpOut(ofname.toLatin1().data(), std::ios::out);
1151 bool errorProp =
false;
1156 for (
int i = 0; i < nObservations;i++ ) {
1163 int numImages = observation->size();
1165 for (
int j = 0; j < numImages; j++) {
1170 sprintf(buf,
"%s", image->fileName().toLatin1().data());
1175 fpOut <<
toString(rmsImageSampleResiduals[imgIndex].Rms()).toLatin1().data();
1179 fpOut <<
toString(rmsImageLineResiduals[imgIndex].Rms()).toLatin1().data();
1183 fpOut <<
toString(rmsImageResiduals[imgIndex].Rms()).toLatin1().data();
1187 QString observationString =
1188 observation->bundleOutputCSV(errorProp);
1191 if (observationString.right(1)==
",") {
1192 observationString.truncate(observationString.length()-1);
1195 fpOut << (
const char*) observationString.toLatin1().data();
1216 QString ofname =
"bundleout.txt";
1217 ofname =
m_settings->outputFilePrefix() + ofname;
1219 std::ofstream fpOut(ofname.toLatin1().data(), std::ios::out);
1224 m_txtBundleOutputFilename = ofname;
1233 bool berrorProp =
false;
1240 sprintf(buf,
"\nTARGET BODY\n==========================\n");
1243 sprintf(buf,
"\n Target Initial Total " 1244 "Final Initial Final\n" 1245 "Parameter Value Correction " 1246 "Value Accuracy Accuracy\n");
1249 QString targetString =
1250 m_settings->bundleTargetBody()->formatBundleOutputString(berrorProp);
1251 fpOut << (
const char*)targetString.toLatin1().data();
1255 sprintf(buf,
"\nIMAGE EXTERIOR ORIENTATION\n==========================\n");
1261 imagesAndParameters.insert(
"target",
m_settings->bundleTargetBody()->parameterList() );
1264 for (
int i = 0; i < nObservations; i++) {
1271 int numImages = observation->size();
1272 for (
int j = 0; j < numImages; j++) {
1274 sprintf(buf,
"\nImage Full File Name: %s\n", image->fileName().toLatin1().data());
1276 sprintf(buf,
"\nImage Serial Number: %s\n", image->serialNumber().toLatin1().data());
1279 sprintf(buf,
"Image Initial Total Final Accuracy\n");
1281 sprintf(buf,
"Parameter Value Correction Value Initial Final Units\n");
1285 "***************************************\n");
1288 observation->bundleOutputString(fpOut,berrorProp);
1290 foreach ( QString image, observation->imageNames() ) {
1291 imagesAndParameters.insert( image, observation->parameterList() );
1304 sprintf(buf,
"\n\n\nPOINTS UNCERTAINTY SUMMARY\n==========================\n\n");
1311 sprintf(buf,
"RMS Sigma %s(m)%20.8lf\n", coordName.toLatin1().data(),
1314 sprintf(buf,
"MIN Sigma %s(m)%20.8lf at %s\n", coordName.toLatin1().data(),
1318 sprintf(buf,
"MAX Sigma %s(m)%20.8lf at %s\n\n", coordName.toLatin1().data(),
1326 sprintf(buf,
"RMS Sigma %s(m)%20.8lf\n", coordName.toLatin1().data(),
1329 sprintf(buf,
"MIN Sigma %s(m)%20.8lf at %s\n", coordName.toLatin1().data(),
1333 sprintf(buf,
"MAX Sigma %s(m)%20.8lf at %s\n\n", coordName.toLatin1().data(),
1340 SurfacePoint::Three);
1342 sprintf(buf,
"RMS Sigma %s(m)%20.8lf\n", coordName.toLatin1().data(),
1345 sprintf(buf,
"MIN Sigma %s(m)%20.8lf at %s\n", coordName.toLatin1().data(),
1349 sprintf(buf,
"MAX Sigma %s(m)%20.8lf at %s\n", coordName.toLatin1().data(),
1355 sprintf(buf,
" RMS Sigma Radius(m) N/A\n");
1357 sprintf(buf,
" MIN Sigma Radius(m) N/A\n");
1359 sprintf(buf,
" MAX Sigma Radius(m) N/A\n");
1366 sprintf(buf,
"\n\nPOINTS SUMMARY\n==============\n%103s" 1367 "Sigma Sigma Sigma\n" 1368 " Label Status Rays RMS" 1369 " Latitude Longitude Radius" 1370 " Latitude Longitude Radius\n",
"");
1373 sprintf(buf,
"\n\nPOINTS SUMMARY\n==============\n%103s" 1374 "Sigma Sigma Sigma\n" 1375 " Label Status Rays RMS" 1376 " Point X Point Y Point Z" 1377 " Point X Point Y Point Z\n",
"");
1382 for (
int i = 0; i < nPoints; i++) {
1385 QString pointSummaryString =
1386 bundleControlPoint->formatBundleOutputSummaryString(berrorProp);
1387 fpOut << (
const char*)pointSummaryString.toLatin1().data();
1391 sprintf(buf,
"\n\nPOINTS DETAIL\n=============\n\n");
1394 bool solveRadius =
m_settings->solveRadius();
1396 for (
int i = 0; i < nPoints; i++) {
1400 QString pointDetailString =
1401 bundleControlPoint->formatBundleOutputDetailString(berrorProp,
1403 fpOut << (
const char*)pointDetailString.toLatin1().data();
1420 QString ofname =
"bundleout_points.csv";
1421 ofname =
m_settings->outputFilePrefix() + ofname;
1422 m_csvSavedPointsFilename = ofname;
1424 std::ofstream fpOut(ofname.toLatin1().data(), std::ios::out);
1431 double dLat, dLon, dRadius;
1433 double dSigmaLat, dSigmaLong, dSigmaRadius;
1438 int numMeasures, numRejectedMeasures;
1439 double dResidualRms;
1443 sprintf(buf,
",,,,,3-d,3-d,3-d,Sigma,Sigma,Sigma,Correction,Correction,Correction,Coordinate," 1444 "Coordinate,Coordinate\nPoint,Point,Accepted,Rejected,Residual,Latitude,Longitude," 1445 "Radius,Latitude,Longitude,Radius,Latitude,Longitude,Radius,X,Y,Z\nLabel,Status," 1446 "Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),(m),(m),(m),(km),(km),(km)\n");
1449 sprintf(buf,
",,,,,3-d,3-d,3-d,Correction,Correction,Correction,Coordinate,Coordinate," 1450 "Coordinate\nPoint,Point,Accepted,Rejected,Residual,Latitude,Longitude,Radius," 1451 "Latitude,Longitude,Radius,X,Y,Z\nLabel,Status,Measures,Measures,RMS,(dd),(dd),(km)," 1452 "(m),(m),(m),(km),(km),(km)\n");
1456 for (
int i = 0; i < numPoints; i++) {
1459 if (!bundlecontrolpoint) {
1463 if (bundlecontrolpoint->isRejected()) {
1467 dLat = bundlecontrolpoint->adjustedSurfacePoint().GetLatitude().degrees();
1468 dLon = bundlecontrolpoint->adjustedSurfacePoint().GetLongitude().degrees();
1469 dRadius = bundlecontrolpoint->adjustedSurfacePoint().GetLocalRadius().kilometers();
1470 dX = bundlecontrolpoint->adjustedSurfacePoint().GetX().kilometers();
1471 dY = bundlecontrolpoint->adjustedSurfacePoint().GetY().kilometers();
1472 dZ = bundlecontrolpoint->adjustedSurfacePoint().GetZ().kilometers();
1473 numMeasures = bundlecontrolpoint->numberOfMeasures();
1474 numRejectedMeasures = bundlecontrolpoint->numberOfRejectedMeasures();
1475 dResidualRms = bundlecontrolpoint->residualRms();
1478 boost::numeric::ublas::bounded_vector< double, 3 > corrections = bundlecontrolpoint->
1481 cor_lat_m = bundlecontrolpoint->adjustedSurfacePoint().LatitudeToMeters(corrections[0]);
1482 cor_lon_m = bundlecontrolpoint->adjustedSurfacePoint().LongitudeToMeters(corrections[1]);
1483 cor_rad_m = corrections[2]*1000.0;
1486 strStatus =
"FIXED";
1489 strStatus =
"CONSTRAINED";
1495 strStatus =
"UNKNOWN";
1499 dSigmaLat = bundlecontrolpoint->adjustedSurfacePoint().GetLatSigmaDistance().meters();
1500 dSigmaLong = bundlecontrolpoint->adjustedSurfacePoint().GetLonSigmaDistance().meters();
1501 dSigmaRadius = bundlecontrolpoint->adjustedSurfacePoint().GetLocalRadiusSigma().meters();
1503 sprintf(buf,
"%s,%s,%d,%d,%6.2lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf," 1504 "%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf\n",
1505 bundlecontrolpoint->id().toLatin1().data(), strStatus.toLatin1().data(),
1506 numMeasures, numRejectedMeasures, dResidualRms, dLat, dLon, dRadius, dSigmaLat,
1507 dSigmaLong, dSigmaRadius, cor_lat_m, cor_lon_m, cor_rad_m, dX, dY, dZ);
1510 sprintf(buf,
"%s,%s,%d,%d,%6.2lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf," 1511 "%16.8lf,%16.8lf\n",
1512 bundlecontrolpoint->id().toLatin1().data(), strStatus.toLatin1().data(),
1513 numMeasures, numRejectedMeasures, dResidualRms, dLat, dLon, dRadius, cor_lat_m,
1514 cor_lon_m, cor_rad_m, dX, dY, dZ);
1533 QString ofname =
"residuals.csv";
1534 ofname =
m_settings->outputFilePrefix() + ofname;
1535 m_csvSavedResidualsFilename = ofname;
1537 std::ofstream fpOut(ofname.toLatin1().data(), std::ios::out);
1544 sprintf(buf,
",,,x image,y image,Measured,Measured,sample,line,Residual Vector\n");
1546 sprintf(buf,
"Point,Image,Image,coordinate,coordinate," 1547 "Sample,Line,residual,residual,Magnitude\n");
1549 sprintf(buf,
"Label,Filename,Serial Number,(mm),(mm)," 1550 "(pixels),(pixels),(pixels),(pixels),(pixels),Rejected\n");
1556 int numMeasures = 0;
1561 for (
int i = 0; i < numPoints; i++) {
1563 numMeasures = bundleControlPoint->size();
1565 if (bundleControlPoint->rawControlPoint()->IsIgnored()) {
1569 for (
int j = 0; j < numMeasures; j++) {
1570 bundleMeasure = bundleControlPoint->at(j);
1572 Camera *measureCamera = bundleMeasure->camera();
1573 if (!measureCamera) {
1577 if (bundleMeasure->isRejected()) {
1578 sprintf(buf,
"%s,%s,%s,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,*\n",
1579 bundleControlPoint->id().toLatin1().data(),
1580 bundleMeasure->parentBundleImage()->fileName().toLatin1().data(),
1581 bundleMeasure->cubeSerialNumber().toLatin1().data(),
1582 bundleMeasure->focalPlaneMeasuredX(),
1583 bundleMeasure->focalPlaneMeasuredY(),
1584 bundleMeasure->sample(),
1585 bundleMeasure->line(),
1586 bundleMeasure->sampleResidual(),
1587 bundleMeasure->lineResidual(),
1588 bundleMeasure->residualMagnitude());
1591 sprintf(buf,
"%s,%s,%s,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf\n",
1592 bundleControlPoint->id().toLatin1().data(),
1593 bundleMeasure->parentBundleImage()->fileName().toLatin1().data(),
1594 bundleMeasure->cubeSerialNumber().toLatin1().data(),
1595 bundleMeasure->focalPlaneMeasuredX(),
1596 bundleMeasure->focalPlaneMeasuredY(),
1597 bundleMeasure->sample(),
1598 bundleMeasure->line(),
1599 bundleMeasure->sampleResidual(),
1600 bundleMeasure->lineResidual(),
1601 bundleMeasure->residualMagnitude());
1635 QString relativePath;
1636 QString relativeBundlePath;
1645 if (oldPath != newPath) {
1647 QDir bundleDir(newPath);
1648 if (!bundleDir.mkpath(bundleDir.path())) {
1650 QString(
"Failed to create directory [%1]")
1651 .arg(bundleSolutionInfoRoot.
path()),
1656 if (!QFile::copy(oldFile, newFile)) {
1658 QString(
"Failed to copy file [%1] to new file [%2]")
1662 newFile = newPath +
"/" +
FileName(m_txtBundleOutputFilename).
name();
1663 if (!QFile::copy(m_txtBundleOutputFilename, newFile)) {
1665 QString(
"Failed to copy file [%1] to new file [%2]")
1666 .arg(m_txtBundleOutputFilename).arg(newFile),
1669 newFile = newPath +
"/" +
FileName(m_csvSavedImagesFilename).
name();
1670 if (!QFile::copy(m_csvSavedImagesFilename, newFile)) {
1672 QString(
"Failed to copy file [%1] to new file [%2]")
1673 .arg(m_csvSavedImagesFilename).arg(newFile),
1676 newFile = newPath +
"/" +
FileName(m_csvSavedPointsFilename).
name();
1677 if (!QFile::copy(m_csvSavedPointsFilename, newFile)) {
1679 QString(
"Failed to copy file [%1] to new file [%2]")
1680 .arg(m_csvSavedPointsFilename).arg(newFile),
1683 newFile = newPath +
"/" +
FileName(m_csvSavedResidualsFilename).
name();
1684 if (!QFile::copy(m_csvSavedResidualsFilename, newFile)) {
1686 QString(
"Failed to copy file [%1] to new file [%2]")
1687 .arg(m_csvSavedResidualsFilename).arg(newFile),
1695 if (relativePath.startsWith(
"/")) {
1696 relativePath.remove(0,1);
1702 if (relativeBundlePath.startsWith(
"/")) {
1703 relativeBundlePath.remove(0,1);
1705 relativeBundlePath +=
"/";
1710 stream.writeStartElement(
"bundleSolutionInfo");
1712 stream.writeStartElement(
"generalAttributes");
1713 stream.writeTextElement(
"id",
m_id->toString());
1714 stream.writeTextElement(
"name",
m_name);
1715 stream.writeTextElement(
"runTime",
runTime());
1717 stream.writeTextElement(
"inputFileName",
1719 stream.writeTextElement(
"bundleOutTXT",
1720 relativeBundlePath +
FileName(m_txtBundleOutputFilename).
name());
1721 stream.writeTextElement(
"imagesCSV",
1722 relativeBundlePath +
FileName(m_csvSavedImagesFilename).
name());
1723 stream.writeTextElement(
"pointsCSV",
1724 relativeBundlePath +
FileName(m_csvSavedPointsFilename).
name());
1725 stream.writeTextElement(
"residualsCSV",
1726 relativeBundlePath +
FileName(m_csvSavedResidualsFilename).
name());
1727 stream.writeEndElement();
1738 stream.writeStartElement(
"imageLists");
1742 stream.writeEndElement();
1746 stream.writeStartElement(
"outputControl");
1748 stream.writeEndElement();
1751 stream.writeEndElement();
1765 m_xmlHandlerProject = project;
1785 m_xmlHandlerCharacters += ch;
1786 return XmlStackedHandler::characters(ch);
1801 const QString &localName,
1802 const QString &qName,
1803 const QXmlAttributes &atts) {
1804 m_xmlHandlerCharacters =
"";
1806 if (XmlStackedHandler::startElement(namespaceURI, localName, qName, atts)) {
1808 if (localName ==
"bundleSettings") {
1809 m_xmlHandlerBundleSolutionInfo->m_settings =
1812 else if (localName ==
"bundleResults") {
1813 m_xmlHandlerBundleSolutionInfo->m_statisticsResults =
new BundleResults(m_xmlHandlerProject,
1816 else if (localName ==
"imageList") {
1817 m_xmlHandlerBundleSolutionInfo->m_adjustedImages->append(
1818 new ImageList(m_xmlHandlerProject, reader()));
1820 else if (localName ==
"outputControl") {
1821 FileName outputControlPath =
FileName(m_xmlHandlerProject->bundleSolutionInfoRoot() +
"/" 1822 + m_xmlHandlerBundleSolutionInfo->runTime());
1824 m_xmlHandlerBundleSolutionInfo->m_outputControl =
new Control(outputControlPath, reader());
1841 const QString &localName,
1842 const QString &qName) {
1844 QString projectRoot;
1845 if (m_xmlHandlerProject) {
1846 projectRoot = m_xmlHandlerProject->projectRoot() +
"/";
1849 if (localName ==
"id") {
1851 assert(m_xmlHandlerBundleSolutionInfo->m_id);
1852 delete m_xmlHandlerBundleSolutionInfo->m_id;
1853 m_xmlHandlerBundleSolutionInfo->m_id =
new QUuid(m_xmlHandlerCharacters);
1855 else if (localName ==
"name") {
1856 m_xmlHandlerBundleSolutionInfo->m_name = m_xmlHandlerCharacters;
1858 else if (localName ==
"runTime") {
1859 m_xmlHandlerBundleSolutionInfo->m_runTime = m_xmlHandlerCharacters;
1861 else if (localName ==
"inputFileName") {
1862 assert(m_xmlHandlerBundleSolutionInfo->m_inputControlNetFileName == NULL);
1863 m_xmlHandlerBundleSolutionInfo->m_inputControlNetFileName =
new FileName(
1864 projectRoot + m_xmlHandlerCharacters);
1866 else if (localName ==
"bundleOutTXT") {
1867 m_xmlHandlerBundleSolutionInfo->m_txtBundleOutputFilename =
1868 projectRoot + m_xmlHandlerCharacters;
1870 else if (localName ==
"imagesCSV") {
1871 m_xmlHandlerBundleSolutionInfo->m_csvSavedImagesFilename =
1872 projectRoot + m_xmlHandlerCharacters;
1874 else if (localName ==
"pointsCSV") {
1875 m_xmlHandlerBundleSolutionInfo->m_csvSavedPointsFilename =
1876 projectRoot + m_xmlHandlerCharacters;
1878 else if (localName ==
"residualsCSV") {
1879 m_xmlHandlerBundleSolutionInfo->m_csvSavedResidualsFilename =
1880 projectRoot + m_xmlHandlerCharacters;
1883 m_xmlHandlerCharacters =
"";
1884 return XmlStackedHandler::endElement(namespaceURI, localName, qName);
1897 SurfacePoint::CoordIndex coordIdx)
const {
1899 switch (
m_settings->controlPointCoordTypeReports()) {
1902 case SurfacePoint::One:
1903 coordName =
" Latitude";
1905 case SurfacePoint::Two:
1906 coordName =
"Longitude";
1908 case SurfacePoint::Three:
1909 coordName =
" Radius";
1912 IString msg =
"Unknown surface point index enum [" 1920 case SurfacePoint::One:
1921 coordName =
"POINT X";
1923 case SurfacePoint::Two:
1924 coordName =
"POINT Y";
1926 case SurfacePoint::Three:
1927 coordName =
"POINT Z";
1930 IString msg =
"Unknown surface point index enum [" 1937 IString msg =
"Unknown surface point coordinate type enum [" This represents an ISIS control net in a project-based GUI interface.
Control * control() const
Returns bundle output Control object.
void setRunTime(QString runTime)
Sets the run time, and the name if a name is not already set.
QString path() const
Returns the path of the file name.
virtual bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts)
Handle an XML start element.
double meters() const
Get the distance in meters.
double max()
Returns the maximum observation so far included in the dynamic calculation.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
void updateFileName(Project *)
TODO: change description below to something more like english.
Distance minSigmaCoord2Distance() const
Returns the minimum sigma distance for coordinate 2.
Internalizes a list of images and allows for operations on the entire list.
bool outputText()
Outputs a text file with the results of the BundleAdjust.
const double Null
Value for an Isis Null pixel.
QString maxSigmaCoord3PointId() const
Returns the maximum sigma point id for coordinate 3.
The main project for ipce.
QString outputControlName() const
Returns m_outputControlName.
int numberObservations() const
Returns the number of observations.
QList< ImageList * > imageList()
Returns the images used in the bundle.
const BundleObservationVector & observations() const
Returns a reference to the observations used by the BundleAdjust.
A Constrained point is a Control Point whose lat/lon/radius is somewhat established and should not be...
static QString CurrentLocalTime()
Returns the current local time This time is taken directly from the system clock, so if the system cl...
A Fixed point is a Control Point whose lat/lon is well established and should not be changed...
File name manipulation and expansion.
void save(QXmlStreamWriter &stream, const Project *project) const
Saves the BundleResults object to an XML file.
XmlHandler(BundleSolutionInfo *bundleSolutionInfo, Project *project)
Create an XML Handler (reader) that can populate the BundleSolutionInfo class data.
Container class for BundleAdjustment results.
BundleSettingsQsp m_settings
Bundle settings.
BundleSettingsQsp bundleSettings()
Returns bundle settings.
int numberCameraPositionCoefficientsSolved() const
Accesses the number of camera position coefficients in the solution.
QString savedResidualsFilename()
Returns filename of output bundle residuals csv file.
double sigmaCoord1StatisticsRms() const
Returns the RMS of the adjusted sigmas for coordinate 1.
double value(double cumProb)
Provides the value of the variable that has the given cumulative probility (according the current est...
QString weightedResidualCutoff()
Method to return a string represtentation of the weighted residual cutoff (if it exists) for the Maxi...
bool outputHeader(std::ofstream &fpOut)
Output header for bundle results file.
double sigmaCoord3StatisticsRms() const
Returns the RMS of the adjusted sigmas for coordinate 3.
QString minSigmaCoord1PointId() const
Returns the minimum sigma point id for coordinate 1.
QString m_name
Name of the bundle. Defaults to the id.
QString name() const
Returns the name of the file excluding the path and the attributes in the file name.
bool solvePositionOverHermite() const
Whether or not the polynomial for solving will be fit over an existing Hermite spline.
QList< ImageList * > * m_images
Input image list.
QString name() const
Returns the name of the bundle.
QString surfacePointCoordName(SurfacePoint::CoordinateType type, SurfacePoint::CoordIndex coordInx) const
Determine the control point coordinate name.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
QString savedPointsFilename()
Returns filename of output bundle points csv file.
This error is for when a programmer made an API call that was illegal.
A type of error that occurred when performing an actual I/O operation.
void save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const
Method to write this Control object's member data to an XML stream.
bool outputImagesCSV()
Outputs the bundleout_images.csv file which contains Jigsaw data about the images within each observa...
static QString cnetRoot(QString projectRoot)
Appends the root directory name 'cnets' to the project.
QString maxSigmaCoord1PointId() const
Returns the maximum sigma point id for coordinate 1.
QString id() const
Get a unique, identifying string associated with this BundleSolutionInfo object.
Distance maxSigmaCoord3Distance() const
Returns the maximum sigma distance for coordinate 3.
ControlNetQsp outputControlNet() const
Returns a shared pointer to the output control network.
QList< ImageList * > adjustedImages() const
Returns the list of images that were adjusted after a bundle.
void setOutputStatistics(BundleResults statisticsResults)
Sets the stat results.
bool outputImagesCSVHeader(std::ofstream &fpOut)
Outputs the header for the bundleout_images.csv file.
A Free point is a Control Point that identifies common measurements between two or more cubes...
QVector< BundleControlPointQsp > & bundleControlPoints()
Returns a reference to the BundleControlPoint vector.
Planetocentric latitudinal (lat/lon/rad) coordinates.
MaximumLikelihoodWFunctions maximumLikelihoodModelWFunc(int modelIndex) const
Returns the maximum likelihood model at the given index.
BundleResults * m_statisticsResults
Bundle statistical results.
BundleSolutionInfo * m_xmlHandlerBundleSolutionInfo
The bundleSolutionInfo object.
QString runTime() const
Returns the run time.
int ckDegree() const
Accesses the degree of polynomial fit to original camera angles (ckDegree).
This class is used to accumulate statistics on double arrays.
double elapsedTime() const
Returns the elapsed time for the bundle adjustment.
QString outputControlNetFileName() const
Returns the name of the output control network.
void setName(QString name)
Sets the name of the bundle.
StatCumProbDistDynCalc residualsCumulativeProbabilityDistribution() const
Returns the cumulative probability distribution of the residuals used for reporting.
int numberConstrainedImageParameters() const
Returns the number of constrained image parameters.
int ckSolveDegree() const
Accesses the degree of the camera angles polynomial being fit to in the bundle adjustment (ckSolveDeg...
Distance minSigmaCoord3Distance() const
Returns the minimum sigma distance for coordinate 3.
int spkSolveDegree() const
Accesses the degree of thecamera position polynomial being fit to in the bundle adjustment (spkSolveD...
double sigmaCoord2StatisticsRms() const
Returns the RMS of the adjusted sigmas for coordinate 2.
static QString coordinateTypeToString(CoordinateType type)
Converts the given SurfacePoint::CoordinateType enumeration to a string.
double maximumLikelihoodModelQuantile(int modelIndex) const
Returns the quantile of the maximum likelihood model at the given index.
#define _FILEINFO_
Macro for the filename and line number.
QList< Statistics > rmsImageSampleResiduals() const
Returns the list of RMS image sample residuals statistics.
QUuid * m_id
A unique ID for this BundleSolutionInfo object (useful for others to reference this object when savin...
QSharedPointer< BundleSettings > BundleSettingsQsp
Definition for a BundleSettingsQsp, a shared pointer to a BundleSettings object.
virtual void pushContentHandler(XmlStackedHandler *newHandler)
Push a contentHandler and maybe continue parsing...
void setOutputControlName(QString name)
Sets m_outputControlName.
This class is used to read an images.xml file into an image list.
void addAdjustedImages(ImageList *images)
Adds a list of images that were adjusted (their labels were updated).
Container class for BundleAdjustment settings.
A type of error that cannot be classified as any of the other error types.
bool solvePolyOverPointing() const
Whether or not the solve polynomial will be fit over the existing pointing polynomial.
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
double Rms() const
Computes and returns the rms.
void setOutputControl(Control *outputControl)
Returns the name of the output control network.
QString minSigmaCoord2PointId() const
Returns the minimum sigma point id for coordinate 2.
QString projectRoot() const
Get the top-level folder of the project.
QDir dir() const
Returns the path of the file's parent directory as a QDir object.
FileName * m_inputControlNetFileName
Input control network file name.
QString m_xmlHandlerCharacters
List of characters that have been handled.
QList< Statistics > rmsImageResiduals() const
Returns the list of RMS image residuals statistics.
Distance minSigmaCoord1Distance() const
Returns the minimum sigma distance for coordinate 1.
bool converged() const
Returns whether or not the bundle adjustment converged.
double elapsedTimeErrorProp() const
Returns the elapsed time for error propagation.
QList< double > aprioriPositionSigmas() const
Accesses the a priori position sigmas.
QString newProjectRoot() const
Get the top-level folder of the new project.
Body-fixed rectangular x/y/z coordinates.
void setCorrMatImgsAndParams(QMap< QString, QStringList > imgsAndParams)
Set the images and their associated parameters of the correlation matrix.
CoordinateType
Defines the coordinate typ, units, and coordinate index for some of the output methods.
Control * m_outputControl
Output control.
This class is used to modify and manage solve settings for 1 to many BundleObservations.
int numberRejectedObservations() const
Returns the number of observation that were rejected.
QList< Statistics > rmsImageLineResiduals() const
Returns the list of RMS image line residuals statistics.
virtual bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName)
Handle an XML end element.
QString minSigmaCoord3PointId() const
Returns the minimum sigma point id for coordinate 3.
bool outputResiduals()
Outputs image coordinate residuals to a csv file.
QString toString() const
Returns a QString of the full file name including the file path, excluding the attributes with any Is...
~BundleSolutionInfo()
Destructor.
void save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const
Saves the BundleSolutionInfo to the project.
QString m_runTime
Run time of the bundle adjustment.
QList< ImageList * > * m_adjustedImages
Adjusted image list.
int numberConstrainedTargetParameters() const
Return the number of constrained target parameters.
BundleResults bundleResults()
Returns the bundle results.
virtual bool characters(const QString &ch)
Adds characters to m_xmlHandlerCharacters.
int numberCameraAngleCoefficientsSolved() const
Accesses the number of camera angle coefficients in the solution.
Adds specific functionality to C++ strings.
Namespace for ISIS/Bullet specific routines.
double min()
Returns the maximum observation so far included in the dynamic calculation.
A container class for statistical results from a BundleAdjust solution.
Distance maxSigmaCoord2Distance() const
Returns the maximum sigma distance for coordinate 2.
QString savedBundleOutputFilename()
Returns bundleout text filename.
int numberConstrainedPointParameters() const
Returns the number of constrained point parameters.
int iterations() const
Returns the number of iterations taken by the BundleAdjust.
double tweakingConstant() const
Returns the current tweaking constant.
QString maxSigmaCoord2PointId() const
Returns the maximum sigma point id for coordinate 2.
QString bundleSolutionInfoRoot() const
Accessor for the root directory of the results data.
static QString modelToString(Model model)
Static method to return a string represtentation for a given MaximumLikelihoodWFunctions::Model enum...
static QString bundleSolutionInfoRoot(QString projectRoot)
Appends the root directory name 'bundle' to the project results directory.
QString inputControlNetFileName() const
Returns the name of the input control network.
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
QString savedImagesFilename()
Returns filename of output bundle images csv file.
Manage a stack of content handlers for reading XML files.
int spkDegree() const
Accesses the degree of the polynomial fit to the original camera position (spkDegree).
QString fileName() const
Access the name of the control network file associated with this Control.
bool solveTwist() const
Accesses the flag for solving for twist.
double sigma0() const
Returns the Sigma0 of the bundle adjustment.
Distance maxSigmaCoord1Distance() const
Returns the maximum sigma distance for coordinate 1.
QList< double > aprioriPointingSigmas() const
Accesses the a priori pointing sigmas.
int numberUnknownParameters() const
Returns the number of unknown parameters.
bool outputPointsCSV()
Outputs point data to a csv file.