Ejemplo n.º 1
0
/**
 * Calculates the lat/lon of the ControlNet.
 *
 * @param incubes The filename of the list of cubes in the ControlNet
 * @param cnet    The filename of the ControlNet
 */
void setControlPointLatLon(SerialNumberList &snl, ControlNet &cnet) {
  CubeManager manager;
  manager.SetNumOpenCubes(50);   //Should keep memory usage to around 1GB

  Progress progress;
  progress.SetText("Calculating Lat/Lon");
  progress.SetMaximumSteps(cnet.GetNumPoints());
  progress.CheckStatus();

  for (int cp = 0; cp < cnet.GetNumPoints(); cp++) {
    ControlPoint *point = cnet.GetPoint(cp);
    ControlMeasure *cm = point->GetRefMeasure();

    Cube *cube = manager.OpenCube(snl.FileName(cm->GetCubeSerialNumber()));
    try {
      cube->camera()->SetImage(cm->GetSample(), cm->GetLine());
      g_surfacePoints[point->GetId()] = cube->camera()->GetSurfacePoint();
    }
    catch (IException &e) {
      QString msg = "Unable to create camera for cube file [";
      msg += snl.FileName(cm->GetCubeSerialNumber()) + "]";
      throw IException(e, IException::Unknown, msg, _FILEINFO_);
    }
    cube = NULL; //Do not delete, manager still has ownership

    progress.CheckStatus();
  }

  manager.CleanCubes();
}
Ejemplo n.º 2
0
//Helper function to load camera range.
void LoadCameraRange() {
  UserInterface &ui = Application::GetUserInterface();
  QString file = ui.GetFileName("FROM");

  // Get the map projection file provided by the user
  Pvl userMap;
  userMap.read(ui.GetFileName("MAP"));

  // Open the input cube, get the camera object, and the cam map projection
  Cube c;
  c.open(file);
  Camera *cam = c.camera();

  // Make the target info match the user mapfile
  double minrad, maxrad, minaz, maxaz;
  cam->ringRange(minrad, maxrad, minaz, maxaz, userMap);

  // Set ground range parameters in UI
  ui.Clear("MINRINGRAD");
  ui.PutDouble("MINRINGRAD", minrad);
  ui.Clear("MAXRINGRAD");
  ui.PutDouble("MAXRINGRAD", maxrad);
  ui.Clear("MINRINGLON");
  ui.PutDouble("MINRINGLON", minaz);
  ui.Clear("MAXRINGLON");
  ui.PutDouble("MAXRINGLON", maxaz);

  // Set default ground range param to camera
  ui.Clear("DEFAULTRANGE");
  ui.PutAsString("DEFAULTRANGE", "CAMERA");
}
Ejemplo n.º 3
0
void IsisMain() {
  // Set the input image, get the camera model
  Process p;
  Cube *icube = p.SetInputCube("FROM");
  Camera *cam = icube->camera();

  // Get the ra/dec range and resolution
  double minRa, maxRa, minDec, maxDec;
  cam->RaDecRange(minRa, maxRa, minDec, maxDec);
  double res = cam->RaDecResolution();

  // Get the center ra/dec
  cam->SetImage(icube->sampleCount() / 2.0, icube->lineCount() / 2.0);
  double centerRa  = cam->RightAscension();
  double centerDec = cam->Declination();

  // Compute the rotation
  cam->SetRightAscensionDeclination(centerRa, centerDec + 2.0 * res);
  double x = cam->Sample() - icube->sampleCount() / 2.0;
  double y = cam->Line() - icube->lineCount() / 2.0;
  double rot = atan2(-y, x) * 180.0 / Isis::PI;
  rot = 90.0 - rot;
  if(rot < 0.0) rot += 360.0;

  // Setup and log results
  PvlGroup results("Range");
  results += PvlKeyword("MinimumRightAscension", toString(minRa), "degrees");
  results += PvlKeyword("MaximumRightAscension", toString(maxRa), "degrees");
  results += PvlKeyword("MinimumDeclination", toString(minDec), "degrees");
  results += PvlKeyword("MaximumDeclination", toString(maxDec), "degrees");
  results += PvlKeyword("MinimumRightAscension", Projection::ToHMS(minRa), "hms");
  results += PvlKeyword("MaximumRightAscension", Projection::ToHMS(maxRa), "hms");
  results += PvlKeyword("MinimumDeclination", Projection::ToDMS(minDec), "dms");
  results += PvlKeyword("MaximumDeclination", Projection::ToDMS(maxDec), "dms");
  results += PvlKeyword("Resolution", toString(res), "degrees/pixel");
  Application::Log(results);

  // Setup and log orientation
  PvlGroup orient("Orientation");
  orient += PvlKeyword("CenterSample", toString(icube->sampleCount() / 2.0));
  orient += PvlKeyword("CenterLine", toString(icube->lineCount() / 2.0));
  orient += PvlKeyword("CenterRightAscension", toString(centerRa), "degrees");
  orient += PvlKeyword("CenterDeclination", toString(centerDec), "degrees");
  orient += PvlKeyword("CelestialNorthClockAngle", toString(rot), "degrees");
  orient += PvlKeyword("Resolution", toString(res), "degrees/pixel");
  Application::Log(orient);

  // Write the output file if requested
  UserInterface ui = Application::GetUserInterface();
  if(ui.WasEntered("TO")) {
    Pvl temp;
    temp.addGroup(results);
    temp.addGroup(orient);
    temp.write(ui.GetFileName("TO", "txt"));
  }

  p.EndProcess();
}
Ejemplo n.º 4
0
void IsisMain() {
  UserInterface &ui = Application::GetUserInterface();
  try {
    // Open the cube
    Cube cube;
    cube.open(ui.GetFileName("FROM"), "rw");

    //check for existing polygon, if exists delete it
    if(cube.label()->hasObject("Polygon")) {
      cube.label()->deleteObject("Polygon");
    }

    // Get the camera, interpolate to a parabola
    Camera *cam = cube.camera();
    if(cam->DetectorMap()->LineRate() == 0.0) {
      QString msg = "[" + ui.GetFileName("FROM") + "] is not a line scan camera";
      throw IException(IException::User, msg, _FILEINFO_);
    }
    cam->instrumentRotation()->SetPolynomial();

    // Get the instrument pointing keyword from the kernels group and update
    // its value to table.
    Isis::PvlGroup kernels =
      cube.label()->findGroup("Kernels", Isis::Pvl::Traverse);

    // Save original kernels in keyword before changing to "Table" in the kernels group
    PvlKeyword origCk = kernels["InstrumentPointing"];

    // Write out the "Table" label to the tabled kernels in the kernels group
    kernels["InstrumentPointing"] = "Table";

    // And finally write out the original kernels after Table
    for (int i = 0;  i < origCk.size();  i++) {
      kernels["InstrumentPointing"].addValue(origCk[i]);
    }

    cube.putGroup(kernels);

    // Pull out the pointing cache as a table and write it
    Table cmatrix = cam->instrumentRotation()->Cache("InstrumentPointing");
    cmatrix.Label().addComment("Smoothed using spicefit");
    cube.write(cmatrix);
    cube.close();
  }
  catch(IException &e) {
    QString msg = "Unable to fit pointing for [" + ui.GetFileName("FROM") + "]";
    throw IException(IException::User, msg, _FILEINFO_);
  }
}
Ejemplo n.º 5
0
// Helper function to get output summing mode from input cube (FROM)
void LoadInputSummingMode() {
  UserInterface &ui = Application::GetUserInterface();

  // Get camera from cube to match
  QString file = ui.GetFileName("FROM");
  // Open the input cube and get the camera object
  Cube c;
  c.open(file);
  Camera *cam = c.camera();

  ui.Clear("SUMMINGMODE");
  ui.PutDouble("SUMMINGMODE", cam->DetectorMap()->SampleScaleFactor());

  ui.Clear("SOURCE");
  ui.PutAsString("SOURCE", "FROMUSER");
}
Ejemplo n.º 6
0
/**
 * @brief Initializes an ISIS cube converting it into a SPICE segment
 *
 * This method is called to extract the perinent contents of an ISIS cube file
 * and accumulate generic information that is used to create the output SPICE
 * kernel segment.  Other specific kernel types can use this class as its base
 * class and add to it additional elements to complete the needed content for
 * the NAIF kernel.
 *
 * @param cube ISIS cube file to accumulate information from
 */
void SpiceSegment::init(Cube &cube) {

  _kernels.UnLoad();  // Unload all active, owned kernels
  init();            // Init local variables

  _fname = cube.fileName();

  //  Extract ISIS CK blob and transform to CK 3 content
  NaifStatus::CheckErrors();
  try {

    // Order is somewhat important here.  The call to initialize Kernels
    // object checks the NAIF pool for existance.  It logs their NAIF
    // status as loaded which may cause trouble from here on...
    Pvl *label = cube.label();
    _kernels.Init(*label);
    Camera *camera = cube.camera();

    //  Determine segment ID from product ID if it exists, otherwise basename
    if ( _name.isEmpty() ) {
      _name = getKeyValue(*label, "ProductId");
      if (_name.isEmpty() ) {
        _name = FileName(_fname).baseName();
      }
    }

    // Get instrument and target ids
    QString value("");
    value = getKeyValue(*label, "InstrumentId");
    if (!value.isEmpty()) { _instId = value; }
    value = getKeyValue(*label, "TargetName");
    if (!value.isEmpty()) { _target = value; }

    // Get default times for sorting purposes
    setStartTime(camera->cacheStartTime().Et());
    setEndTime(camera->cacheEndTime().Et());

  } catch ( IException &ie  ) {
    ostringstream mess;
    mess << "Failed to construct Spice Segment basics from ISIS file " << _fname;
    throw IException(ie, IException::User, mess.str(), _FILEINFO_);
  }

  return;
}
Ejemplo n.º 7
0
//Helper function to get camera resolution.
void LoadCameraRes() {
  UserInterface &ui = Application::GetUserInterface();
  QString file = ui.GetFileName("FROM");

  // Open the input cube, get the camera object, and the cam map projection
  Cube c;
  c.open(file);
  Camera *cam = c.camera();
  Pvl camMap;
  cam->BasicMapping(camMap);
  PvlGroup &camGrp = camMap.findGroup("Mapping");

  ui.Clear("RESOLUTION");
  ui.PutDouble("RESOLUTION", camGrp["PixelResolution"]);

  ui.Clear("PIXRES");
  ui.PutAsString("PIXRES", "MPP");
}
Ejemplo n.º 8
0
// Helper function to get output summing mode from cube to MATCH
void LoadMatchSummingMode() {
  QString file;
  UserInterface &ui = Application::GetUserInterface();

  // Get camera from cube to match
  if((ui.GetString("SOURCE") == "FROMMATCH") && (ui.WasEntered("MATCH"))) {
    file = ui.GetFileName("MATCH");
  }
  else {
    file = ui.GetFileName("FROM");
  }

// Open the input cube and get the camera object
  Cube c;
  c.open(file);
  Camera *cam = c.camera();

  ui.Clear("SUMMINGMODE");
  ui.PutDouble("SUMMINGMODE", cam->DetectorMap()->SampleScaleFactor());

  ui.Clear("SOURCE");
  ui.PutAsString("SOURCE", "FROMUSER");
}
Ejemplo n.º 9
0
void IsisMain() {
  // We will be processing by line
  ProcessByBrick p;
  UserInterface &ui = Application::GetUserInterface();

  // Use the def file for filter constants
  Pvl uvvisDef("$clementine1/calibration/uvvis/uvvis.def");

  // Setup the input and output cubes
  Cube *icube = p.SetInputCube("FROM");

  Cube *dccube;
  if(ui.WasEntered("DCFILE")) {
    dccube = p.SetInputCube("DCFILE");
  }
  else {
    QString dcfileloc = "$clementine1/calibration/uvvis/";
    dcfileloc += "dark_5_15_96.cub";
    CubeAttributeInput cubeAtt;
    dccube = p.SetInputCube(dcfileloc, cubeAtt);
  }

  QString filter = (QString)(icube->group("BandBin"))["FilterName"];
  filter = filter.toLower();

  Cube *ffcube;
  if(ui.WasEntered("FFFILE")) {
    ffcube = p.SetInputCube("FFFILE");
  }
  else {
    // compute default fffile
    double compressRatio = (icube->group("Instrument"))["EncodingCompressionRatio"];

    // check to see if cube is compressed or uncompressed
    if(compressRatio == 1.0) {
      QString fffileLoc = "$clementine1/calibration/uvvis/";
      fffileLoc += "lu" + filter + "_uncomp_flat_long.cub";
      CubeAttributeInput cubeAtt;
      ffcube = p.SetInputCube(fffileLoc, cubeAtt);
    }
    else {
      QString fffileLoc = "$clementine1/calibration/uvvis/";
      fffileLoc += "lu" + filter + "_comp_flat_long.cub";
      CubeAttributeInput cubeAtt;
      ffcube = p.SetInputCube(fffileLoc, cubeAtt);
    }
  }

  Cube *ocube = p.SetOutputCube("TO");

  avgFF = uvvisDef.findGroup("Filter" + filter.toUpper())["AVGFF"];
  cr = uvvisDef.findGroup("Filter" + filter.toUpper())["CO"];
  gain = uvvisDef.findGroup(QString("GainModeID") + QString(icube->group("Instrument")["GainModeID"][0]))["GAIN"];

  useDcconst = ui.WasEntered("DCCONST");
  if(useDcconst) {
    dcconst = ui.GetDouble("DCCONST");
  }
  else {
    dcconst = 0.0;
  }

  conv = ui.GetBoolean("CONV");
  exposureDuration = icube->group("Instrument")["ExposureDuration"];
  offsetModeID = icube->group("Instrument")["OffsetModeID"];

  if(((QString)icube->group("Instrument")["FocalPlaneTemperature"]).compare("UNK") == 0) {
    //if FocalPlaneTemp is unknown set it to zero
    focalPlaneTemp = 0.0;
  }
  else {
    focalPlaneTemp = icube->group("Instrument")["FocalPlaneTemperature"];
  }

  Camera *cam = icube->camera();
  bool camSuccess = cam->SetImage(icube->sampleCount() / 2, icube->lineCount() / 2);

  if(!camSuccess) {
    throw IException(IException::Unknown, "Unable to calculate the Solar Distance for this cube.", _FILEINFO_);
  }

  dist = cam->SolarDistance();

  // If temp. correction set to true, or focal plane temp is zero then use temperature correction
  if(ui.GetBoolean("TCOR") || abs(focalPlaneTemp) <= DBL_EPSILON) {
    // Temperature correction requires the use of the mission phase
    //   (PRELAUNCH, EARTH, LUNAR) and the product ID.
    QString productID = (QString)(icube->group("Archive")["ProductID"]);
    QChar missionPhase = ((QString)((icube->group("Archive"))["MissionPhase"])).at(0);
    QString n1subQString(productID.mid(productID.indexOf('.') + 1, productID.length() - 1));
    QString n2subQString(productID.mid(4, productID.indexOf('.') - 5));
    int n1 = toInt(n1subQString);
    int n2 = toInt(n2subQString);
    int phase = 0;

    if(missionPhase == 'L') {
      phase = 0;
    }
    else if(missionPhase == 'E') {
      phase = 1;
    }
    else if(missionPhase == 'P') {
      phase = 2;
    }
    else {
      throw IException(IException::Unknown, "Invalid Mission Phase", _FILEINFO_);
    }

    // This formula makes the primary search critera the original product ID's extension,
    //   the secondary search criteria the mission phase and finally the numerical part of the
    //   original product ID.
    int imageID = (100000 * n1) + (10000 * phase) + n2;
    FixTemp(imageID);
  }

  if(focalPlaneTemp <= 0.0) {
    focalPlaneTemp = 272.5;
  }

  // Start the processing
  p.SetBrickSize(icube->sampleCount(), icube->lineCount(), 1);
  p.StartProcess(UvVisCal);

  // Add the radiometry group
  PvlGroup calgrp("Radiometry");
  calgrp += PvlKeyword("FlatFieldFile", ffcube->fileName());

  if(ui.GetString("DARKCURRENT").compare("DCFILE") == 0) {
    calgrp += PvlKeyword("DarkCurrentFile", dccube->fileName());
  }
  else {
    calgrp += PvlKeyword("DarkCurrentConstant", toString(dcconst));
  }

  calgrp += PvlKeyword("CorrectedFocalPlaneTemp", toString(focalPlaneTemp));
  calgrp += PvlKeyword("C1", toString(avgFF));
  calgrp += PvlKeyword("C2", toString(C2));
  calgrp += PvlKeyword("C3", toString(C3));
  calgrp += PvlKeyword("C4", toString(C4));
  calgrp += PvlKeyword("C5", toString(C5));
  calgrp += PvlKeyword("CR", toString(cr));
  calgrp += PvlKeyword("FrameTransferTimePerRow", toString(cr));
  calgrp += PvlKeyword("Gain", toString(gain));
  calgrp += PvlKeyword("CorrectedExposureDuration", toString(correctedExposureDuration));
  calgrp += PvlKeyword("ConvertToRadiance", toString(conv));

  calgrp += PvlKeyword("ACO", toString(ACO));
  calgrp += PvlKeyword("BCO", toString(BCO));
  calgrp += PvlKeyword("CCO", toString(CCO));
  calgrp += PvlKeyword("DCO", toString(DCO));

  ocube->putGroup(calgrp);
  p.EndProcess();
}
Ejemplo n.º 10
0
void IsisMain() {
  // Open the match cube and get the camera model on it
  ProcessRubberSheet m;
  Cube *mcube = m.SetInputCube("MATCH");
  Cube *ocube = m.SetOutputCube("TO");

  // Set up the default reference band to the middle of the cube
  // If we have even bands it will be close to the middle
  int referenceBand = ocube->bandCount();
  referenceBand += (referenceBand % 2);
  referenceBand /= 2;

  // See if the user wants to override the reference band
  UserInterface &ui = Application::GetUserInterface();
  if(ui.WasEntered("REFBAND")) {
    referenceBand = ui.GetInteger("REFBAND");
  }

  // Using the Camera method out of the object opack will not work, because the
  // filename required by the Camera is not passed by the process class in this
  // case.  Use the CameraFactory to create the Camera instead to get around this
  // problem.
  Camera *outcam = CameraFactory::Create(*(mcube->label()));

  // Set the reference band we want to match
  PvlGroup instgrp = mcube->group("Instrument");
  if(!outcam->IsBandIndependent()) {
    PvlKeyword rBand("ReferenceBand", toString(referenceBand));
    rBand.addComment("# All bands are aligned to reference band");
    instgrp += rBand;
    mcube->putGroup(instgrp);
    delete outcam;
    outcam = NULL;
  }

  // Only recreate the output camera if it was band dependent
  if(outcam == NULL) outcam = CameraFactory::Create(*(mcube->label()));

  // We might need the instrument group later, so get a copy before clearing the input
  //   cubes.
  m.ClearInputCubes();

  Cube *icube = m.SetInputCube("FROM");
  incam = icube->camera();

  // Set up the transform object which will simply map
  // output line/samps -> output lat/lons -> input line/samps
  Transform *transform = new cam2cam(icube->sampleCount(),
                                     icube->lineCount(),
                                     incam,
                                     ocube->sampleCount(),
                                     ocube->lineCount(),
                                     outcam);


  // Add the reference band to the output if necessary
  ocube->putGroup(instgrp);

  // Set up the interpolator
  Interpolator *interp = NULL;
  if(ui.GetString("INTERP") == "NEARESTNEIGHBOR") {
    interp = new Interpolator(Interpolator::NearestNeighborType);
  }
  else if(ui.GetString("INTERP") == "BILINEAR") {
    interp = new Interpolator(Interpolator::BiLinearType);
  }
  else if(ui.GetString("INTERP") == "CUBICCONVOLUTION") {
    interp = new Interpolator(Interpolator::CubicConvolutionType);
  }

  // See if we need to deal with band dependent camera models
  if(!incam->IsBandIndependent()) {
    m.BandChange(BandChange);
  }

  // Warp the cube
  m.StartProcess(*transform, *interp);
  m.EndProcess();

  // Cleanup
  delete transform;
  delete interp;
}
Ejemplo n.º 11
0
//! This function corrects the DNs in a given brick.
//! It also stores results in frameletOffsetsForBand every time the
//! band changes so it doesn't have to re-project at every framelet.
//! Equivalent changes are calculated for the next framelet... that is,
//! equivalent pixels. This function both calculates and applies these.
void RemoveSeam(Buffer &out, int framelet, int band,
                bool matchIsEven) {
  // Apply fixes from last pass. Basically all changes happen in two
  //   places, because the DNs exist in two cubes, this is the second
  //   place.
  for(int fix = 0; fix < nextFrameletFixes.size(); fix ++) {
    QPair<int, int> fixLoc = nextFrameletFixes[fix].first;
    double fixDn = nextFrameletFixes[fix].second;

    try {
      int outIndex = out.Index(fixLoc.first, fixLoc.second, band);
      out[outIndex] = fixDn;
    }
    catch(IException &) {
    }
  }

  nextFrameletFixes.clear();

  // Match == goodData. "goodData" is the top of the next framelet.
  Cube *goodDataCube = (matchIsEven) ? evenCube : oddCube;
  // "badData" is the bottom of the current framelet, what we were given.
  Cube *badDataCube  = (matchIsEven) ? oddCube  : evenCube;

  Camera *goodCam = goodDataCube->camera();
  Camera *badCam  = badDataCube->camera();

  // Verify we're at the correct band
  goodCam->SetBand(band);
  badCam->SetBand(band);

  // Absolute line number for top of framelets.
  int goodDataStart = frameletSize * (framelet + 1);
  int badDataStart = frameletSize * framelet;

  // Start corrections to the current brick at this line
  int badLineStart = goodDataStart - overlapSize - 1;
  // End corrections to the current brick at this line
  int badLineEnd = goodDataStart - 1;

  int offsetSample = 0;
  int offsetLine = 0;

  // Loop left to right, top to bottom of problematic area at bottom of framelet
  for(int badLine = badLineStart; badLine <= badLineEnd; badLine ++) {
    for(int sample = 1; sample <= out.SampleDimension(); sample ++) {
      // A fair good data weight is the % across problematic area so fair
      double goodDataWeight = (double)(badLine - badLineStart) /
                             (double)(badLineEnd - badLineStart);

      // But good data is good, so let's bias it towards the good data
      goodDataWeight *= 2;
      if(goodDataWeight > 1) goodDataWeight = 1;

      // Bad data weight is the inverse of the good data's weight.
      double badDataWeight = 1.0 - goodDataWeight;

      int outIndex = out.Index(sample, badLine, band);
      // This is the indexing scheme for frameletOffsetsForBand
      int optimizeIndex = (badLine - badLineStart) * out.SampleDimension() +
                          sample - 1;

      // Does the optimized (pre-calculated) translation from bad to good
      //  exist?
      if(optimizeIndex < frameletOffsetsForBand.size()) {
        // This offset any good? If not then do nothing.
        if(!frameletOffsetsForBand[optimizeIndex].Valid())
          continue;

        // Use optimization!
        offsetSample = frameletOffsetsForBand[optimizeIndex].SampleOffset();
        offsetLine = frameletOffsetsForBand[optimizeIndex].LineOffset();

        ASSERT(frameletOffsetsForBand[optimizeIndex].Sample() == sample);
      }
      // There is no pre-calculated translation, calculate it
      else if(badCam->SetImage(sample, badLine)) {
        double lat = badCam->UniversalLatitude();
        double lon = badCam->UniversalLongitude();

        if(goodCam->SetUniversalGround(lat, lon)) {
          double goodSample = goodCam->Sample();
          double goodLine = goodCam->Line();

          // Set the current offset for correction
          offsetSample = (int)(goodSample - sample + 0.5);
          offsetLine = (int)(goodLine - badLine + 0.5);

          // Remember this calculation for future passes
          frameletOffsetsForBand.push_back(Offset(sample, badLine - badDataStart,
                                                  offsetSample, offsetLine));
        }
        else {
          // Don't do anything since we failed at this pixel; it will be copied
          //   from the input directly
          frameletOffsetsForBand.push_back(Offset());
          continue;
        }
      }

      // Translate current sample,line (bad) to (good) data's sample,line
      double goodSample = offsetSample + sample;
      double goodLine = offsetLine + badLine;

      // Get the pixel we're missing (good)
      Portal p(1, 1, goodDataCube->pixelType());
      p.SetPosition(goodSample, goodLine, band);
      goodDataCube->read(p);

      // Attempt to apply weighted average
      if(!Isis::IsSpecial(p[0]) && !Isis::IsSpecial(out[outIndex])) {
        out[outIndex] = p[0] * goodDataWeight + out[outIndex] * badDataWeight;
      }
      else if(!Isis::IsSpecial(p[0])) {
        out[outIndex] = p[0];
      }

      // Apply change to next framelet also
      QPair<int, int> fixLoc((int)(goodSample + 0.5),
                             (int)(goodLine   + 0.5));
      QPair< QPair<int, int>, double > fix(fixLoc, out[outIndex]);
      nextFrameletFixes.push_back(fix);
    }
  }
}
Ejemplo n.º 12
0
/** The ISIS smtk main application */
void IsisMain() {
  UserInterface &ui = Application::GetUserInterface();

  // Open the first cube.  It is the left hand image.
  Cube lhImage;
  CubeAttributeInput &attLeft = ui.GetInputAttribute("FROM");
  vector<QString> bandLeft = attLeft.bands();
  lhImage.setVirtualBands(bandLeft);
  lhImage.open(ui.GetFileName("FROM"),"r");

  // Open the second cube, it is geomertricallty altered.  We will be matching the
  // first to this one by attempting to compute a sample/line offsets
  Cube rhImage;
  CubeAttributeInput &attRight = ui.GetInputAttribute("MATCH");
  vector<QString> bandRight = attRight.bands();
  rhImage.setVirtualBands(bandRight);
  rhImage.open(ui.GetFileName("MATCH"),"r");

  // Ensure only single bands
  if (lhImage.bandCount() != 1 || rhImage.bandCount() != 1) {
    QString msg = "Input Cubes must have only one band!";
    throw IException(IException::User,msg,_FILEINFO_);
  }

  //  Both images must have a Camera and can also have a Projection.  We will
  //  only deal with a Camera, however as a projected, non-mosaicked image
  //  uses a Projection internal to the Camera object.
  Camera *lhCamera = NULL;
  Camera *rhCamera = NULL;
  try {
    lhCamera = lhImage.camera();
    rhCamera = rhImage.camera();
  }
  catch (IException &ie) {
    QString msg = "Both input images must have a camera";
    throw IException(ie, IException::User, msg, _FILEINFO_);
  }

  //  Since we are generating a DEM, we must turn off any existing
  //  DEM that may have been initialized with spiceinit.
  lhCamera->IgnoreElevationModel(true);
  rhCamera->IgnoreElevationModel(true);

  // Get serial number
  QString serialLeft = SerialNumber::Compose(lhImage, true);
  QString serialRight = SerialNumber::Compose(rhImage, true);

//  This still precludes band to band registrations.
  if (serialLeft == serialRight) {
    QString sLeft = FileName(lhImage.fileName()).name();
    QString sRight = FileName(rhImage.fileName()).name();
    if (sLeft == sRight) {
      QString msg = "Cube Serial Numbers must be unique - FROM=" + serialLeft +
                   ", MATCH=" + serialRight;
      throw IException(IException::User,msg,_FILEINFO_);
    }
    serialLeft = sLeft;
    serialRight = sRight;
  }

  Progress prog;
  prog.SetText("Finding Initial Seeds");

  int nl = lhImage.lineCount();
  int ns = lhImage.sampleCount();
  BigInt numAttemptedInitialPoints = 0;

  //  Declare Gruen matcher
  SmtkMatcher matcher(ui.GetFileName("REGDEF"), &lhImage, &rhImage);

  // Get line/sample linc/sinc parameters
  int space   = ui.GetInteger("SPACE");
  int linc (space), sinc(space);

  // Do we have a seed points from a control net file?
  bool useseed = ui.WasEntered("CNET");

  // Base points on an input cnet
  SmtkQStack gstack;
  double lastEigen(0.0);
  if (useseed) {
    ControlNet cnet(ui.GetFileName("CNET"));
    prog.SetMaximumSteps(cnet.GetNumPoints());
    prog.CheckStatus();

    gstack.reserve(cnet.GetNumPoints());

    for (int cpIndex = 0; cpIndex < cnet.GetNumPoints(); cpIndex ++) {
      ControlPoint *cp = cnet.GetPoint(cpIndex);

      if (!cp->IsIgnored()) {
        ControlMeasure *cmLeft(0), *cmRight(0);
        for(int cmIndex = 0; cmIndex < cp->GetNumMeasures(); cmIndex ++) {
          ControlMeasure *cm = cp->GetMeasure(cmIndex);
          if (!cm->IsIgnored()) {
            if (cm->GetCubeSerialNumber() == serialLeft)
              cmLeft = cp->GetMeasure(cmIndex);
            if (cm->GetCubeSerialNumber() == serialRight)
              cmRight = cp->GetMeasure(cmIndex);
          }
        }

        //  If we have both left and right images in the control point, save it
        if ( (cmLeft != 0) && (cmRight != 0) ) {
          Coordinate left = Coordinate(cmLeft->GetLine(), cmLeft->GetSample());
          Coordinate right = Coordinate(cmRight->GetLine(), cmRight->GetSample());
          SmtkPoint spnt = matcher.Create(left, right);

          // Insert the point (unregistered)
          if ( spnt.isValid() ) {
            int line = (int) cmLeft->GetLine();
            int samp = (int) cmLeft->GetSample();
            matcher.isValid(spnt);
            gstack.insert(qMakePair(line, samp), spnt);
            lastEigen = spnt.GoodnessOfFit();
          }
        }
      }

      prog.CheckStatus();
    }
  }
  else {
  // We want to create a grid of control points that is N rows by M columns.

    int rows = (lhImage.lineCount() + linc - 1)/linc;
    int cols = (lhImage.sampleCount() + sinc - 1)/sinc;

    prog.SetMaximumSteps(rows * cols);
    prog.CheckStatus();

    // First pass stack and eigen value statistics
    SmtkQStack fpass;
    fpass.reserve(rows * cols);
    Statistics temp_mev;

    // Loop through grid of points and get statistics to compute
    // initial set of points
    for (int line = linc / 2 + 1; line < nl; line += linc) {
      for (int samp = sinc / 2 + 1 ; samp < ns; samp += sinc) {
        numAttemptedInitialPoints ++;
        SmtkPoint spnt = matcher.Register(Coordinate(line,samp));
        if ( spnt.isValid() ) {
          matcher.isValid(spnt);
          fpass.insert(qMakePair(line, samp), spnt);
          temp_mev.AddData(spnt.GoodnessOfFit());
        }
        prog.CheckStatus();
      }
    }

    //  Now select a subset of fpass points as the seed points
    cout << "Number of Potential Seed Points: " << fpass.size() << "\n";
    cout << "Min / Max Eigenvalues Matched: " << temp_mev.Minimum() << ", "
         << temp_mev.Maximum() << "\n";

    // How many seed points are requested
    double nseed = ui.GetDouble("NSEED");
    int inseed;
    if (nseed >= 1.0) inseed = (int) nseed;
    else if (nseed > 0.0) inseed = (int) (nseed * (double) (fpass.size()));
    else inseed = (int) ((double) (fpass.size()) * 0.05);

    double seedsample = ui.GetDouble("SEEDSAMPLE");

    // Generate a new stack
    gstack.reserve(inseed);
    while ((gstack.size() < inseed) && (!fpass.isEmpty() )) {
      SmtkQStack::iterator bestm;
      if (seedsample <= 0.0) {
        bestm = matcher.FindSmallestEV(fpass);
      }
      else {
        bestm = matcher.FindExpDistEV(fpass, seedsample, temp_mev.Minimum(),
                                      temp_mev.Maximum());
      }

      //  Add point to stack
      if (bestm != fpass.end()) {
        Coordinate right = bestm.value().getRight();
        matcher.isValid(bestm.value());
        gstack.insert(bestm.key(), bestm.value());
        lastEigen = bestm.value().GoodnessOfFit();
        fpass.erase(bestm);
      }
    }

    // If a user wants to see the seed network, write it out here
    if (ui.WasEntered("OSEEDNET")) {
      WriteCnet(ui.GetFileName("OSEEDNET"), gstack,
                lhCamera->target()->name(), serialLeft, serialRight);
    }

  }

  ///////////////////////////////////////////////////////////////////////
  // All done with seed points.  Sanity check ensures we actually found
  // some.
  ///////////////////////////////////////////////////////////////////////
  if (gstack.size() <= 0) {
    QString msg = "No seed points found - may need to check Gruen parameters.";
    throw IException(IException::User, msg, _FILEINFO_);
  }

  //  Report seed point status
  if (!useseed) {
    cout << "Number of Seed Points used: " << gstack.size() << "\n";
    cout << "EV of last Seed Point:      " << lastEigen << "\n";
  }
  else {
    cout << "Number of Manual Seed Points:   " << gstack.size() << "\n";
  }

  // Use seed points (in stack) to grow
  SmtkQStack bmf;
  bmf.reserve(gstack.size());  // Probably need much more but for starters...

  BigInt numOrigPoints = gstack.size();
  BigInt passpix2 = 0;

  int subcbox = ui.GetInteger("SUBCBOX");
  int halfBox((subcbox-1)/2);
  while (!gstack.isEmpty()) {

    SmtkQStackIter cstack = matcher.FindSmallestEV(gstack);

    // Print number on stack
    if ((gstack.size() % 1000) == 0) {
      cout << "Number on Stack: " << gstack.size()
           << ". " << cstack.value().GoodnessOfFit() << "\n";
    }

    // Test to see if already determined
    SmtkQStackIter bmfPt = bmf.find(cstack.key());
    if (bmfPt == bmf.end()) {
      // Its not in the final stack, process it

      //  Retrieve the point
      SmtkPoint spnt = cstack.value();
      //  Register if its not already registered
      if (!spnt.isRegistered()) {
        spnt = matcher.Register(spnt, spnt.getAffine());
      }

      // Still must check for validity if the point was just registered,
      // otherwise should be good
      if ( spnt.isValid() ) {
        passpix2++;
        bmf.insert(cstack.key(), spnt);  // inserts (0,0) offset excluded below
        int line   = cstack.key().first;
        int sample = cstack.key().second;

        //  Determine match points
        double eigen(spnt.GoodnessOfFit());
        for (int sampBox = -halfBox ; sampBox <= halfBox ; sampBox++ ) {
          int csamp = sample + sampBox;
          for (int lineBox = -halfBox ; lineBox <= halfBox ; lineBox++) {
            int cline = line + lineBox;
            if ( !( (sampBox == 0) && (lineBox == 0)) ) {// Already added above
              SmtkQPair dupPair(cline, csamp);
              SmtkQStackIter temp = bmf.find(dupPair);
              SmtkPoint bmfpnt;
              if (temp != bmf.end()) {
                if (temp.value().GoodnessOfFit() > eigen) {
                  // Create cloned point with better fit
                  bmfpnt = matcher.Clone(spnt, Coordinate(cline,csamp));
                }
              }
              else {  // ISIS2 is BMF(SAMP,LINE,7) .EQ VALID_MAX4)
                // Clone new point for insert
                bmfpnt = matcher.Clone(spnt, Coordinate(cline,csamp));
              }

              //  Add if good point
              if (bmfpnt.isValid()) {
                bmf.insert(dupPair, bmfpnt);
              }
            }
          }
        }

        // Grow stack with spacing adding info to stack
        for (int i = -1 ; i <= 1 ; i ++) {  // Sample
          for (int j = -1 ; j <= 1 ; j ++) {  // Line
            // Don't re-add the original sample, line
            if ( !((i == 0) && (j == 0)) ) {
              //  Grow based upon spacing
              double ssamp = sample + (i * space);
              double sline = line   + (j * space);
              Coordinate pnt = Coordinate(sline, ssamp);
              SmtkPoint gpnt = matcher.Clone(spnt, pnt);

              if ( gpnt.isValid() ) {
                SmtkQPair growpt((int) sline, (int) ssamp);

                // double check we don't have a finalized result at this position
                SmtkQStackIter temp = bmf.find(growpt);
                if(temp == bmf.end()) {
                  gstack.insert(growpt, gpnt);
                }
              }
            }
          }
        }
      }
    }

    // Remove the current point from the grow stack (hole)
    gstack.erase(cstack);
  }

/////////////////////////////////////////////////////////////////////////
// All done with creating points.  Perform output options.
/////////////////////////////////////////////////////////////////////////

  // If a TO parameter was specified, create DEM with errors
  if (ui.WasEntered("TO")) {
    //  Create the output DEM
    cout << "\nCreating output DEM from " << bmf.size() << " points.\n";
    Process  p;
    Cube *icube = p.SetInputCube("FROM");
    Cube *ocube = p.SetOutputCube("TO", icube->sampleCount(),
                                  icube->lineCount(), 3);
    p.ClearInputCubes();

    int boxsize = ui.GetInteger("BOXSIZE");
    double plotdist = ui.GetDouble("PLOTDIST");

    TileManager dem(*ocube), eigen(*ocube), stErr(*ocube);
    dem.SetTile(1, 1);      //  DEM Data/elevation
    stErr.SetTile(1, 2);    //  Error in stereo computation
    eigen.SetTile(1, 3);    //  Eigenvalue of the solution

    int nBTiles(eigen.Tiles()/3);  // Total tiles / 3 bands

    prog.SetText("Creating DEM");
    prog.SetMaximumSteps(nBTiles);
    prog.CheckStatus();

    Statistics stAng;
    while ( !eigen.end() ) {   // Must use the last band for this!!
      PointPlot tm = for_each(bmf.begin(), bmf.end(), PointPlot(dem, plotdist));
      tm.FillPoints(*lhCamera, *rhCamera, boxsize, dem, stErr, eigen, &stAng);

      ocube->write(dem);
      ocube->write(stErr);
      ocube->write(eigen);

      dem.next();
      stErr.next();
      eigen.next();

      prog.CheckStatus();
    }

    //  Report Stereo separation angles
    PvlGroup stresultsPvl("StereoSeparationAngle");
    stresultsPvl += PvlKeyword("Minimum", toString(stAng.Minimum()), "deg");
    stresultsPvl += PvlKeyword("Average", toString(stAng.Average()), "deg");
    stresultsPvl += PvlKeyword("Maximum", toString(stAng.Maximum()), "deg");
    stresultsPvl += PvlKeyword("StandardDeviation", toString(stAng.StandardDeviation()), "deg");
    Application::Log(stresultsPvl);

    // Update the label with BandBin keywords
    PvlKeyword filter("FilterName", "Elevation", "meters");
    filter.addValue("ElevationError", "meters");
    filter.addValue("GoodnessOfFit", "unitless");
    PvlKeyword center("Center", "1.0");
    center.addValue("1.0");
    center.addValue("1.0");

    PvlGroup &bandbin = ocube->label()->findGroup("BandBin", PvlObject::Traverse);
    bandbin.addKeyword(filter, PvlContainer::Replace);
    bandbin.addKeyword(center, PvlContainer::Replace);
    center.setName("Width");
    bandbin.addKeyword(center, PvlContainer::Replace);


    p.EndProcess();
  }

  // If a cnet file was entered, write the ControlNet pvl to the file
  if (ui.WasEntered("ONET")) {
    WriteCnet(ui.GetFileName("ONET"), bmf, lhCamera->target()->name(), serialLeft,
              serialRight);
  }

  // Create output data
  PvlGroup totalPointsPvl("Totals");
  totalPointsPvl += PvlKeyword("AttemptedPoints", toString(numAttemptedInitialPoints));
  totalPointsPvl += PvlKeyword("InitialSuccesses", toString(numOrigPoints));
  totalPointsPvl += PvlKeyword("GrowSuccesses", toString(passpix2));
  totalPointsPvl += PvlKeyword("ResultingPoints", toString(bmf.size()));

  Application::Log(totalPointsPvl);

  Pvl arPvl = matcher.RegistrationStatistics();
  PvlGroup smtkresultsPvl("SmtkResults");
  smtkresultsPvl += PvlKeyword("SpiceOffImage", toString(matcher.OffImageErrorCount()));
  smtkresultsPvl += PvlKeyword("SpiceDistanceError", toString(matcher.SpiceErrorCount()));
  arPvl.addGroup(smtkresultsPvl);

  for(int i = 0; i < arPvl.groups(); i++) {
    Application::Log(arPvl.group(i));
  }

  // add the auto registration information to print.prt
  PvlGroup autoRegTemplate = matcher.RegTemplate();
  Application::Log(autoRegTemplate);

  // Don't need the cubes opened anymore
  lhImage.close();
  rhImage.close();
}
Ejemplo n.º 13
0
int main() {
  Preference::Preferences(true);
  QString inputFile = "$mgs/testData/ab102401.lev2.cub";
  Cube cube;
  cube.open(inputFile);
  Camera *c = NULL;
  c = cube.camera();
  Pvl pvl = *cube.label();
  MyCamera cam(cube);
  double line = 453.0;
  double sample = 534.0;
  Latitude lat(18.221, Angle::Degrees);
  Longitude lon(226.671, Angle::Degrees);
  double ra = 347.016;
  double dec = -51.2677;

  cout << endl << "Camera* from: " << inputFile << endl;
  QList<QPointF> ifovOffsets = c->PixelIfovOffsets();
  cout << "Pixel Ifov: " << endl;
  foreach (QPointF offset, ifovOffsets) {
    cout << offset.x() << " , " << offset.y() << endl;
  }
  cout << "Line: " << line << ", Sample: " << sample << endl;
  cout << "Lat: " << lat.degrees() << ", Lon: " << lon.degrees() << endl;
  cout << "RightAscension: " << ra << ", Declination: " << dec << endl << endl;

  cout << "SetImage (sample, line): " << c->SetImage(sample, line)
       << endl << endl;

  cout << "NorthAzimuth: " << c->NorthAzimuth() << endl;
  cout << "SunAzimuth: " << c->SunAzimuth() << endl;
  cout << "SpacecraftAzimuth: " << c->SpacecraftAzimuth() << endl;
  cout << "OffNadirAngle: " << c->OffNadirAngle() << endl << endl;

  cout << "GroundAzimuth in North: " << c->GroundAzimuth(18.221, 226.671, 20.0, 230.0) << endl;
  cout << "GroundAzimuth in North: " << c->GroundAzimuth(20.0, 226.671, 20.0, 230.0) << endl;
  cout << "GroundAzimuth in North: " << c->GroundAzimuth(18.221, 355.0, 20.0, 6.671) << endl;
  cout << "GroundAzimuth in North: " << c->GroundAzimuth(18.221, 6.671, 20.0, 355.0) << endl;
  cout << "GroundAzimuth in North: " << c->GroundAzimuth(18.221, 6.671, 20.0, 6.671) << endl;
  cout << "GroundAzimuth in South: " << c->GroundAzimuth(-18.221, 226.671, -20.0, 230.0) << endl;
  cout << "GroundAzimuth in South: " << c->GroundAzimuth(-20.0, 226.671, -20.0, 230.0) << endl;
  cout << "GroundAzimuth in South: " << c->GroundAzimuth(-18.221, 355.0, -20.0, 6.671) << endl;
  cout << "GroundAzimuth in South: " << c->GroundAzimuth(-18.221, 6.671, -20.0, 355.0) << endl;
  cout << "GroundAzimuth in South: " << c->GroundAzimuth(-18.221, 6.671, -20.0, 6.671) << endl << endl;

  cout << "SetUniversalGround(lat, lon): "
       << c->SetGround(lat, lon) << endl;

  cout << "SetRightAscensionDeclination(ra, dec): "
       << c->SetRightAscensionDeclination(ra, dec) << endl;
  cout << "HasProjection: " << c->HasProjection() << endl;
  cam.IsBandIndependent();
  cout << "ReferenceBand: " << c->ReferenceBand() << endl;
  cout << "HasReferenceBand: " << c->HasReferenceBand() << endl;
  cam.SetBand(7);
  cout << "Sample: " << setprecision(3) << c->Sample() << endl;
  cout << "Line: " << setprecision(3) << c->Line() << endl;

  try {
    double lat = 0, lon = 0;
    cout << "GroundRange: "
         << c->GroundRange(lat, lat, lon, lon, pvl) << endl;
    cout << "IntersectsLongitudeDomain: "
         << c->IntersectsLongitudeDomain(pvl) << endl;
  }
  catch(IException &e) {
    cout << "No mapping group found, so GroundRange and " << endl
         << "IntersectsLongitudeDomain cannot run." << endl;
  }

  cout << "PixelResolution: " << c->PixelResolution() << endl;
  cout << "LineResolution: " << c->LineResolution() << endl;
  cout << "SampleResolution: " << c->SampleResolution() << endl;
  cout << "DetectorResolution: " << c->DetectorResolution() << endl;
  cout << "LowestImageResolution: " << setprecision(4)
       << c->LowestImageResolution() << endl;
  cout << "HighestImageResolution: " << setprecision(3)
       << c->HighestImageResolution() << endl;
  cout << "Calling BasicMapping (pvl)..." << endl;
  c->BasicMapping(pvl);

  double pixRes2 = pvl.findGroup("Mapping")["PixelResolution"];
  pixRes2 *= 10000000;
  pixRes2 = round(pixRes2);
  pixRes2 /= 10000000;
  pvl.findGroup("Mapping")["PixelResolution"] = toString(pixRes2);

  cout << "BasicMapping PVL: " << endl << pvl << endl << endl;
  cout << "FocalLength: " << c->FocalLength() << endl;
  cout << "PixelPitch: " << c->PixelPitch() << endl;
  cout << "Samples: " << c->Samples() << endl;
  cout << "Lines: " << c->Lines() << endl;
  cout << "Bands: " << c->Bands() << endl;
  cout << "ParentLines: " << c->ParentLines() << endl;
  cout << "ParentSamples: " << c->ParentSamples() << endl;


  try {
    cout << c->RaDecRange(ra, ra, dec, dec) << endl;
  }
  catch(IException &e) {
    e.print();
  }

  try {
    cout << c->RaDecResolution() << endl;
  }
  catch(IException &e) {
    e.print();
  }

  cout << "Calling Distortion, FocalPlane, ";
  cout << "Detector, Ground, and Sky Map functions... ";
  c->DistortionMap();
  c->FocalPlaneMap();
  c->DetectorMap();
  c->GroundMap();
  c->SkyMap();
  cout << "Done." << endl;

  cout << "Calling IgnoreProjection (false)..." << endl;
  c->IgnoreProjection(false);

  cout << endl << "Testing SetUniversalGround(lat,lon,radius)..." << endl;
  lat.setDegrees(18.221);
  lon.setDegrees(226.671);
  double radius = 3414033.72108798;
  c->SetUniversalGround(lat.degrees(), lon.degrees(), radius);
  c->SetGround(SurfacePoint(lat, lon, Distance(radius, Distance::Meters)));
  cout << "Has intersection " << c->HasSurfaceIntersection() << endl;
  cout << "Latitude = " << c->UniversalLatitude() << endl;
  cout << "Longitude = " << c->UniversalLongitude() << endl;
  cout << "Radius = " << c->LocalRadius().meters() << endl;
  double p[3];
  c->Coordinate(p);
  cout << "Point = " << setprecision(4)
       << p[0] << " " << p[1] << " " << p[2] << endl << endl;

  cout << "Test Forward/Reverse Camera Calculations At Center Of Image..."
       << endl;
  sample = c->Samples() / 2.0;
  line = c->Lines() / 2.0;
  cout << "Sample = " << setprecision(3) << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << c->SetImage(sample, line) << endl;
  cout << "Latitude = " << c->UniversalLatitude() << endl;
  cout << "Longitude = " << c->UniversalLongitude() << endl;
  cout << "Radius = " << c->LocalRadius().meters() << endl;
  c->Coordinate(p);
  cout << "Point = " << setprecision(4)
       << p[0] << " " << p[1] << " " << p[2] << endl;
  cout << "SetUniversalGround (lat, lon, radius): "
       << c->SetUniversalGround(c->UniversalLatitude(), c->UniversalLongitude(),
                                c->LocalRadius().meters())
       << endl;
  cout << "Sample = " << c->Sample() << endl;
  cout << "Line = " << c->Line() << endl << endl;

  cout << endl << "/---------- Test Polar Boundary Conditions" << endl;
  inputFile = "$clementine1/testData/lub5992r.292.lev1.phot.cub";
  cube.close();
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam2 = CameraFactory::Create(cube);
  cube.close();

  cout << endl;
  cout << "Camera* from: " << inputFile << endl;
  ifovOffsets = cam2->PixelIfovOffsets();
  cout << "Pixel Ifov: " << endl;
  foreach (QPointF offset, ifovOffsets) {
    cout << offset.x() << " , " << offset.y() << endl;
  }
  cout << "Basic Mapping: " << endl;
  Pvl camMap;
  cam2->BasicMapping(camMap);

  double minLat = camMap.findGroup("Mapping")["MinimumLatitude"];
  minLat *= 100;
  minLat = round(minLat);
  minLat /= 100;
  camMap.findGroup("Mapping")["MinimumLatitude"] = toString(minLat);

  double pixRes = camMap.findGroup("Mapping")["PixelResolution"];
  pixRes *= 100;
  pixRes = round(pixRes);
  pixRes /= 100;
  camMap.findGroup("Mapping")["PixelResolution"] = toString(pixRes);

  double minLon = camMap.findGroup("Mapping")["MinimumLongitude"];
  minLon *= 100000000000.0;
  minLon = round(minLon);
  minLon /= 100000000000.0;
  camMap.findGroup("Mapping")["MinimumLongitude"] = toString(minLon);

  cout << camMap << endl;

  cout << endl;
  cout << "180 Domain Range: " << endl;
  double minlat, maxlat, minlon, maxlon;
  camMap.findGroup("Mapping")["LongitudeDomain"][0] = "180";
  cam2->GroundRange(minlat, maxlat, minlon, maxlon, camMap);
  cout << "Latitude Range: " << minlat << " to " << maxlat << endl;
  cout << "Longitude Range: " << minlon << " to " << maxlon
            << endl << endl;

  cout << "Test Forward/Reverse Camera Calculations At Center Of Image..."
       << endl;
  sample = cam2->Samples() / 2.0;
  line = cam2->Lines() / 2.0;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam2->SetImage(sample, line) << endl;
  cout << "Latitude = " << cam2->UniversalLatitude() << endl;
  cout << "Longitude = " << cam2->UniversalLongitude() << endl;
  cout << "Radius = " << cam2->LocalRadius().meters() << endl;
  cam2->Coordinate(p);
  cout << "Point = " << p[0] << " " << p[1] << " " << p[2] << endl;
  cout << "SetUniversalGround (cam2->UniversalLatitude(), "
          "cam2->UniversalLongitude()): "
       << cam2->SetUniversalGround(cam2->UniversalLatitude(),
                                   cam2->UniversalLongitude())
       << endl;
  cout << "Sample = " << cam2->Sample() << endl;
  cout << "Line = " << cam2->Line() << endl << endl;

  cube.close();
  delete cam2;

  cube.close();
  cout << endl << "/---------- Test Local Photometric Angles..." << endl << endl;
  cout << "Flat DEM Surface..." << endl;
  inputFile = "$base/testData/f319b18_ideal_flat.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam3 = CameraFactory::Create(cube);
  cube.close();

  sample = cam3->Samples() / 2.0;
  line = cam3->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam3->SetImage(sample, line) << endl;
  double normal[3];
  cam3->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  Angle phase;
  Angle incidence;
  Angle emission;
  bool success;
  cam3->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam3;

  cout << endl << "45 Degree DEM Surface Facing Left..." << endl;
  inputFile = "$base/testData/f319b18_ideal_45left.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam4 = CameraFactory::Create(cube);
  cube.close();

  sample = cam4->Samples() / 2.0;
  line = cam4->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam4->SetImage(sample, line) << endl;
  cam4->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam4->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam4;

  cout << endl << "45 Degree DEM Surface Facing Top..." << endl;
  inputFile = "$base/testData/f319b18_ideal_45top.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam5 = CameraFactory::Create(cube);
  cube.close();

  sample = cam5->Samples() / 2.0;
  line = cam5->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam5->SetImage(sample, line) << endl;
  cam5->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam5->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam5;

  cout << endl << "45 Degree DEM Surface Facing Right..." << endl;
  inputFile = "$base/testData/f319b18_ideal_45right.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam6 = CameraFactory::Create(cube);
  cube.close();

  sample = cam6->Samples() / 2.0;
  line = cam6->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam6->SetImage(sample, line) << endl;
  cam6->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam6->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam6;

  cout << endl << "45 Degree DEM Surface Facing Bottom..." << endl;
  inputFile = "$base/testData/f319b18_ideal_45bottom.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam7 = CameraFactory::Create(cube);
  cube.close();

  sample = cam7->Samples() / 2.0;
  line = cam7->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam7->SetImage(sample, line) << endl;
  cam7->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam7->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam7;

  cout << endl << "80 Degree DEM Surface Facing Left..." << endl;
  inputFile = "$base/testData/f319b18_ideal_80left.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam8 = CameraFactory::Create(cube);
  cube.close();

  sample = cam8->Samples() / 2.0;
  line = cam8->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam8->SetImage(sample, line) << endl;
  cam8->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam8->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam8;

  cout << endl << "80 Degree DEM Surface Facing Top..." << endl;
  inputFile = "$base/testData/f319b18_ideal_80top.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam9 = CameraFactory::Create(cube);
  cube.close();

  sample = cam9->Samples() / 2.0;
  line = cam9->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam9->SetImage(sample, line) << endl;
  cam9->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam9->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam9;

  cout << endl << "80 Degree DEM Surface Facing Right..." << endl;
  inputFile = "$base/testData/f319b18_ideal_80right.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam10 = CameraFactory::Create(cube);
  cube.close();

  sample = cam10->Samples() / 2.0;
  line = cam10->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam10->SetImage(sample, line) << endl;
  cam10->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam10->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam10;

  cout << endl << "80 Degree DEM Surface Facing Bottom..." << endl;
  inputFile = "$base/testData/f319b18_ideal_80bottom.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam11 = CameraFactory::Create(cube);
  cube.close();

  sample = cam11->Samples() / 2.0;
  line = cam11->Lines() / 2.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam11->SetImage(sample, line) << endl;
  cam11->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam11->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam11;

  cout << endl << "Point Does Not Intersect DEM..." << endl;
  inputFile = "$base/testData/f319b18_ideal_flat.cub";
  cube.open(inputFile);
  pvl = *cube.label();
  Camera *cam12 = CameraFactory::Create(cube);
  cube.close();

  sample = 1.0;
  line = 1.0;
  cout << "Camera* from: " << inputFile << endl;
  cout << "Sample = " << sample << endl;
  cout << "Line = " << line << endl;
  cout << "SetImage (sample, line): " << cam12->SetImage(sample, line) << endl;
  cam12->GetLocalNormal(normal);
  cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl;
  cam12->LocalPhotometricAngles(phase,emission,incidence,success);
  if (success) {
    cout << "Phase = " << phase.degrees() << endl;
    cout << "Emission = " << emission.degrees() << endl;
    cout << "Incidence = " << incidence.degrees() << endl;
  } 
  else {
    cout << "Angles could not be calculated." << endl;
  }
  delete cam12;

  //  Test PixelIfov for Vims which sets the field of view if it in hires mode.  The Ifov is
  //  rectangular instead of square.
  inputFile = "$base/testData/CM_1515945709_1.ir.cub";
  cube.open(inputFile);
  Camera *cam13 = CameraFactory::Create(cube);
  cube.close();

  cout << endl << endl << "Testing non-square pixel Ifov using Hires vims cube" << endl;
  cout << "Camera* from: " << inputFile << endl;
  ifovOffsets = cam13->PixelIfovOffsets();
  cout << "Pixel Ifov: " << endl;
  foreach (QPointF offset, ifovOffsets) {
    cout << offset.x() << " , " << offset.y() << endl;
  }
  delete cam13;
}
Ejemplo n.º 14
0
void IsisMain() {
  UserInterface &ui = Application::GetUserInterface();
  double  time0,//start time
          time1,//end time
          alti,  //altitude of the spacecraftmore
          fmc,  //forward motion compensation rad/sec
          horV,  //horizontal velocity km/sec
          radV,  //radial velocity km/sec
          rollV,//roll speed in rad/sec
          led;  //line exposure duration in seconds

  Cube  panCube;
  iTime  isisTime;
  QString iStrTEMP;

  int i,j,k,scFrameCode,insCode;

  QString mission;

  SpicePosition *spPos;
  SpiceRotation *spRot;

  //int nlines,nsamples,nbands;

  double deg2rad = acos(-1.0)/180.0;

  ProcessImport jp;
  FileName transFile("$apollo15/translations/apollopantranstable.trn");
  PvlTranslationTable transTable(transFile);
  PvlGroup kernels_pvlG;

  //scFrameCode and insCode from user input
  mission = ui.GetString("MISSION");
  if (mission == "APOLLO12") scFrameCode = -912000;
  if (mission == "APOLLO14") scFrameCode = -914000;
  if (mission == "APOLLO15") scFrameCode = -915000;
  if (mission == "APOLLO16") scFrameCode = -916000;
  if (mission == "APOLLO17") scFrameCode = -917000;

  insCode = scFrameCode - 230;

  try {
    panCube.open(ui.GetFileName("FROM"),"rw");
  }
  catch (IException &e) {
    throw IException(IException::User,
                     "Unable to open the file [" + ui.GetFileName("FROM") + "] as a cube.",
                     _FILEINFO_);
  }

  ////////////////////////////////////////////build the cube header instrament group
  PvlGroup inst_pvlG("Instrument");

  PvlKeyword keyword;

  //four that are the same for every panaramic mission
  keyword.setName("SpacecraftName");
  keyword.setValue(mission);
  inst_pvlG.addKeyword(keyword);

  keyword.setName("InstrumentName");
  keyword.setValue(transTable.Translate("InstrumentName","whatever"));
  inst_pvlG.addKeyword(keyword);

  keyword.setName("InstrumentId");
  keyword.setValue(transTable.Translate("InstrumentId","whatever"));
  inst_pvlG.addKeyword(keyword);

  keyword.setName("TargetName");
  keyword.setValue(transTable.Translate("TargetName","whatever"));
  inst_pvlG.addKeyword(keyword);

  //three that need to be calculated from input values
  horV = ui.GetDouble("VEL_HORIZ");
  radV = ui.GetDouble("VEL_RADIAL");
  alti = ui.GetDouble("CRAFT_ALTITUDE");

  //caculate the LineExposureDuration (led)
  if( ui.WasEntered("V/H_OVERRIDE") )
    fmc = ui.GetDouble("V/H_OVERRIDE")/1000.0;
  else
    //forward motion compensation is directly equivalent to V/H
    fmc = sqrt(horV*horV + radV*radV)/alti;  
  rollV = fmc*ROLLC;  //roll angular velcoity is equal to  V/H * constant    (units rad/sec)
  //led = rad/mm * sec/rad = radians(2.5)/FIDL / rollV    (final units: sec/mm)
  led = (2.5*acos(-1.0)/180.0)/rollV/FIDL;  

  //use led and the number of mm to determine the start and stop times
  isisTime = ui.GetString("GMT");

  //calculate starting and stoping times
  time0 = isisTime.Et() - led*FIDL*21.5;
  time1 = time0 + led*FIDL*43;

  isisTime = time0;
  keyword.setName("StartTime");
  keyword.setValue(iStrTEMP=isisTime.UTC());
  inst_pvlG.addKeyword(keyword);

  isisTime = time1;
  keyword.setName("StopTime");
  keyword.setValue(iStrTEMP=isisTime.UTC());
  inst_pvlG.addKeyword(keyword);

  keyword.setName("LineExposureDuration");
  //converted led to msec/mm--negative sign to account for the anti-parallel time and line axes
  keyword.setValue(iStrTEMP=toString(-led),"sec/mm");  
  inst_pvlG.addKeyword(keyword);

  panCube.putGroup(inst_pvlG);

  ///////////////////////////////////The kernals group
  kernels_pvlG.setName("Kernels");
  kernels_pvlG.clear();

  keyword.setName("NaifFrameCode");
  keyword.setValue(toString(insCode));
  kernels_pvlG.addKeyword(keyword);

  keyword.setName("LeapSecond");
  keyword.setValue( transTable.Translate("LeapSecond","File1") );
  kernels_pvlG.addKeyword(keyword);

  keyword.setName("TargetAttitudeShape");
  keyword.setValue( transTable.Translate("TargetAttitudeShape", "File1") );
  keyword.addValue( transTable.Translate("TargetAttitudeShape", "File2") );
  keyword.addValue( transTable.Translate("TargetAttitudeShape", "File3") );
  kernels_pvlG.addKeyword(keyword);

  keyword.setName("TargetPosition");
  keyword.setValue("Table");
  keyword.addValue( transTable.Translate("TargetPosition", "File1") );
  keyword.addValue( transTable.Translate("TargetPosition", "File2") );
  kernels_pvlG.addKeyword(keyword);

  keyword.setName("ShapeModel");
  keyword.setValue( transTable.Translate("ShapeModel", "File1") );
  kernels_pvlG.addKeyword(keyword);

  keyword.setName("InstrumentPointing");
  keyword.setValue("Table");
  kernels_pvlG.addKeyword(keyword);

  keyword.setName("InstrumentPosition");
  keyword.setValue("Table");
  kernels_pvlG.addKeyword(keyword);

  keyword.setName("InstrumentAddendum");
  keyword.setValue( transTable.Translate("InstrumentAddendum",mission));
  kernels_pvlG.addKeyword(keyword);

  panCube.putGroup(kernels_pvlG);

  //Load all the kernals
  Load_Kernel(kernels_pvlG["TargetPosition"]);
  Load_Kernel(kernels_pvlG["TargetAttitudeShape"]);
  Load_Kernel(kernels_pvlG["LeapSecond"]);

  //////////////////////////////////////////attach a target rotation table
  char frameName[32];
  SpiceInt frameCode;
  SpiceBoolean found;
  //get the framecode from the body code (301=MOON)
  cidfrm_c(301, sizeof(frameName), &frameCode, frameName, &found);  
  if(!found) {
    QString naifTarget = QString("IAU_MOOM");
    namfrm_c(naifTarget.toAscii().data(), &frameCode);
    if(frameCode == 0) {
      QString msg = "Can not find NAIF code for [" + naifTarget + "]";
      throw IException(IException::Io, msg, _FILEINFO_);
    }
  }
  spRot = new SpiceRotation(frameCode);
  //create a table from starttime to endtime (streched by 3%) with NODES entries
  spRot->LoadCache(time0-0.015*(time1-time0), time1+0.015*(time1-time0), NODES);  
  Table tableTargetRot = spRot->Cache("BodyRotation");
  tableTargetRot.Label() += PvlKeyword("Description", "Created by apollopaninit");
  panCube.write(tableTargetRot);


  //////////////////////////////////////////////////attach a sun position table
  spPos = new SpicePosition(10,301);  //Position of the sun (10) WRT to the MOON (301)
  //create a table from starttime to endtime (stretched by 3%) with NODES entries
  spPos->LoadCache(time0-0.015*(time1-time0), time1+0.015*(time1-time0), NODES);  
  Table tableSunPos = spPos->Cache("SunPosition");
  tableSunPos.Label() += PvlKeyword("SpkTableStartTime", toString(time0-0.015*(time1-time0)));
  tableSunPos.Label() += PvlKeyword("SpkTablleEndTime", toString(time1+0.015*(time1-time0)));
  tableSunPos.Label() += PvlKeyword("Description", "Created by apollopaninit");
  panCube.write(tableSunPos);  //attach the table to the cube


  /////////////Finding the principal scan line position and orientation
  //get the radii of the MOON
  SpiceInt tempRadii = 0;
  bodvcd_c(301,"RADII",3,&tempRadii,R_MOON);  //units are km
  double  omega,phi,kappa;

  std::vector<double>  posSel;  //Seleno centric position
  std::vector<double> sunPos;  //sunPosition used to transform to J2000
  std::vector<double> posJ20;  //camera position in J2000
  posSel.resize(3);
  sunPos.resize(3);
  posJ20.resize(3);

  double  temp,
          vel[3] = { 0.0, 0.0, 0.0 },  //the total velocity vector (combined Horizonatal and normal components) 
                   //  in km/sec
          M[3][3] = { { 0.0, 0.0, 0.0 },
                      { 0.0, 0.0, 0.0 },
                      { 0.0, 0.0, 0.0 } },    //rotation matrix
          zDir[] = { 0.0, 0.0, 1.0 },  //selenographic Z axis
          northPN[3]  = { 0.0, 0.0, 0.0 }, //normal to the plane containing all the north/south directions, 
                      //  that is plane containing 
                      //  the origin, the z axis, and the primary point of intersection
          northL[3] = { 0.0, 0.0, 0.0 },    //north direction vector in local horizontal plane
          azm[3] = { 0.0, 0.0, 0.0 },   //azm direction of the veclocity vector in selenographic coordinates
          azmP[3] = { 0.0, 0.0, 0.0 },  //azm rotated (partially) and projected into the image plane
          norm[3] = { 0.0, 0.0, 0.0 },  //normal to the local horizontal plane
          look[3] = { 0.0, 0.0, 0.0 };  //unit direction vector in the pincipal cameral look direction, 
                    //  parallel to the vector from the center of the moon through the spacecraft

  double  pos0[3] = { 0.0, 0.0, 0.0 },  //coordinate of the camera position
          pInt[3] = { 0.0, 0.0, 0.0 };  //coordinate of the principle intersection point

  /////////////////calculating the camera position for the center (principal scan line)
  pos0[1] = ui.GetDouble("LON_NADIR")*deg2rad;
  pos0[0] = ui.GetDouble("LAT_NADIR")*deg2rad;
  pos0[2] = ui.GetDouble("CRAFT_ALTITUDE");  //units are km
  Geographic2GeocentricLunar(pos0,pos0);    //function is written so the input can also be the 
                                            //  output

  /////////////////////calculating the camera orientation for the center (principal) scan line
  pInt[1] = ui.GetDouble("LON_INT")*deg2rad;
  pInt[0] = ui.GetDouble("LAT_INT")*deg2rad;
  pInt[2] = 0.0;
  Geographic2GeocentricLunar(pInt,pInt); //function is written so the input can also be the output
  //calculate the unit look direction vector in object space
  look[0] = -pos0[0] + pInt[0];
  look[1] = -pos0[1] + pInt[1];
  look[2] = -pos0[2] + pInt[2];
  temp = sqrt(look[0]*look[0] + look[1]*look[1] + look[2]*look[2]);
  look[0] /= temp;
  look[1] /= temp;
  look[2] /= temp;
  //the local normal vector is equal to pInt0/|pInt0|
  temp = sqrt(pInt[0]*pInt[0] + pInt[1]*pInt[1] + pInt[2]*pInt[2]);
  norm[0] = pInt[0]/temp;
  norm[1] = pInt[1]/temp;
  norm[2] = pInt[2]/temp;
  //omega and phi are defined so that M(phi)M(omega)look = [0 0 -1]  leaving only the roation 
  //  around z axis to be found
  omega = -atan2(look[1], look[2]);  //omega rotation to zero look[1]
  phi   = atan2(-look[0], sin(omega)*look[1] - cos(omega)*look[2]);  //phi rotation to zero look[0]
  //use the horizontal velocity vector direction to solve for the last rotation; we will make the 
  //  image x axis parallel to the in-image-plane projection of the horizontal direction of flight.
  //  The local normal cross the selenogrpahic z gives northPN (normal to the plane containing all 
  //  the north/south directions), that is, the plane containing the origin, the z axis, and the 
  //  primary point of intersection.
  crossp(northPN,norm,northL);   
  //The normal to the plane containing all the north/south directions cross the local normal 
  //  direction gives the local north/south direction in the local normal plane
  crossp(norm, zDir, northPN); 
  if (northL[2] < 0) {  //if by chance we got the south direction change the signs
    northL[0] = -northL[0];
    northL[1] = -northL[1];
    northL[2] = -northL[2];
  }
  //define the rotation matrix to convert northL to the azimuth of flight.
  //  A left handed rotation of "VEL_AZM" around the positive normal direction will convert northL 
  //  to azm
  MfromVecLeftAngle(M,norm,ui.GetDouble("VEL_AZM")*deg2rad);    
  azm[0] = M[0][0]*northL[0] + M[0][1]*northL[1] + M[0][2]*northL[2];
  azm[1] = M[1][0]*northL[0] + M[1][1]*northL[1] + M[1][2]*northL[2];
  azm[2] = M[2][0]*northL[0] + M[2][1]*northL[1] + M[2][2]*northL[2];
  //apply the two rotations we already know
  MfromLeftEulers(M,omega,phi,0.0);
  azmP[0] = M[0][0]*azm[0] + M[0][1]*azm[1] + M[0][2]*azm[2];
  azmP[1] = M[1][0]*azm[1] + M[1][1]*azm[1] + M[1][2]*azm[2];
  azmP[2] = M[2][0]*azm[2] + M[2][1]*azm[1] + M[2][2]*azm[2];
  //subtract that portion of the azm that is perpindicular to the image plane (also the portion 
  //  which is parallel to look) making azm a vector parrallel to the image plane
  //  Further, since we're now rotated into some coordinate system that differs from 
  //  the image coordinate system by only a kappa rotation making the vector parrallel to the 
  //  image plan is as simple as zeroing the z component (and as pointless to further calculations 
  //  as a nat's fart in hurricane) nevertheless it completes the logical transition
  azmP[2] = 0.0;  

  //finally the kappa rotation that will make azmP parallel (including sign) to the camera x axis                  
  kappa = -atan2(-azmP[1], azmP[0]);  


  ////////////////////Add an instrument position table
  //Define the table records
  TableRecord recordPos;  // reacord to be added to table
  // add x,y,z position labels and ephemeris time et to record
  TableField x("J2000X", TableField::Double);  
  TableField y("J2000Y", TableField::Double);
  TableField z("J2000Z", TableField::Double);
  TableField t("ET", TableField::Double);
  recordPos += x;
  recordPos += y;
  recordPos += z;
  recordPos += t;
  Table tablePos("InstrumentPosition", recordPos);
  //now that the azm and norm vectors are defined 
  //  the total velocity vector can be calcualted (km/sec)
  vel[0] = horV*azm[0] + radV * norm[0];
  vel[1] = horV*azm[1] + radV * norm[1];
  vel[2] = horV*azm[2] + radV * norm[2];
  //we'll provide a two ellement table (more is redundant because the motion is modeled as linear 
  //  at this point)  we'll extend the nodes 3% beyond the edges of the images to be sure 
  //  rounding errors don't cause problems
  temp = 0.515*(time1-time0);  //3% extension
  posSel[0] = pos0[0] - temp*vel[0];    //selenocentric coordinate calculation
  posSel[1] = pos0[1] - temp*vel[1];
  posSel[2] = pos0[2] - temp*vel[2];
  //converting to J2000
  temp = time0 - 0.005*(time1-time0);  //et just before the first scan line
  spPos->SetEphemerisTime(temp);
  spRot->SetEphemerisTime(temp);
  //Despite being labeled as J2000, the coordinates for the instrument position are in fact in 
  //  target centric coordinated rotated to a system centered at the target with aces parallel 
  //  to J2000, whatever that means
  posJ20 = spRot->J2000Vector(posSel); //J2000Vector calls rotates the position vector into J2000,
                                       //  completing the transformation
  recordPos[0] = posJ20[0];
  recordPos[1] = posJ20[1];
  recordPos[2] = posJ20[2];
  recordPos[3] = temp;  //temp = et (right now anyway)
  tablePos += recordPos;
  tablePos.Label() += PvlKeyword("SpkTableStartTime",toString(temp));
  //now the other node
  temp = 0.515*(time1-time0);      //3% extension
  posSel[0] = pos0[0] + temp*vel[0];    //selenocentric coordinate calculation
  posSel[1] = pos0[1] + temp*vel[1];
  posSel[2] = pos0[2] + temp*vel[2];
  //converting to J2000
  temp = time1 + 0.015*(time1-time0);  //et just after the last scan line
  spPos->SetEphemerisTime(temp);
  spRot->SetEphemerisTime(temp);
  //Despite being labeled as J2000, the coordinates for the instrument position are in fact 
  //  in target centric coordinated rotated to a system centered at the target with aces 
  //  parallel to J2000, whatever that means
  posJ20 = spRot->J2000Vector(posSel); //J2000Vector calls rotates the position vector into J2000,
                                       //  completing the transformation
  recordPos[0] = posJ20[0];
  recordPos[1] = posJ20[1];
  recordPos[2] = posJ20[2];
  recordPos[3] = temp;  //temp = et (right now anyway)
  tablePos += recordPos;
  tablePos.Label() += PvlKeyword("SpkTableEndTime",toString(temp));
  tablePos.Label() += PvlKeyword("CacheType","Linear");
  tablePos.Label() += PvlKeyword("Description","Created by apollopaninit");
  panCube.write(tablePos);  //now attach it to the table

  /////////////////////////////attach a camera pointing table
  double  cacheSlope,  //time between epoches in the table
          rollComb,  //magnitude of roll relative to the center in the middle of the epoch
          relT,  //relative time at the center of each epoch
          Q[NODES][5],  //NODES four ellement unit quarternions and et (to be calculated).
          gimVec[3],  //the direction of the gimbal rotation vector (to the cameras persepective 
                      //  this is always changing because the camera is mounted to the roll frame 
                      //  assembly which is mounted to the gimbal)
          M0[3][3],  //rotation matrix of the previous epoch
          Mtemp1[3][3],  //intermediate step in the multiplication of rotation matricies
          Mtemp2[3][3],  //intermediate step in the multiplication of rotation matricies
          Mdg[3][3],  //incremental rotation due the the gimbal motion in the camera frame
          Mdr[3][3];  //the contribution of the roll motion in the camera frame during time 
                      //  cacheSlope
  std::vector <double> M_J2toT;  //rotation matrix from J2000 to the target frame
  M_J2toT.resize(9);
  //Table Definition
  TableField q0("J2000Q0", TableField::Double);
  TableField q1("J2000Q1", TableField::Double);
  TableField q2("J2000Q2", TableField::Double);
  TableField q3("J2000Q3", TableField::Double);
  TableField et("ET", TableField::Double);
  TableRecord recordRot;
  recordRot += q0;
  recordRot += q1;
  recordRot += q2;
  recordRot += q3;
  recordRot += et;
  Table tableRot("InstrumentPointing",recordRot);
  //From the cameras perspective the gimbal motion is around a constantly changing axis, 
  //  this is handled by combining a series of incremental rotations
  MfromLeftEulers(M0, omega, phi, kappa);  //rotation matrix in the center Q[(NOPDES-1)/2]
  spRot->SetEphemerisTime(isisTime.Et());
  M_J2toT = spRot->Matrix();   //this actually gives the rotation from J2000 to target centric
  for(j=0; j<3; j++)    //reformating M_J2toT to a 3x3
    for(k=0; k<3; k++)
      Mtemp1[j][k] = M_J2toT[3*j+k];
  mxm_c(M0, Mtemp1, Mtemp2);
  M2Q(Mtemp2, Q[(NODES-1)/2]);  //save the middle scan line quarternion

  Q[(NODES-1)/2][4] = (time1 + time0)/2.0;  //time in the center of the image
  //the total time is scaled up slightly so that nodes will extend just beyond the edge of the image
  cacheSlope = 1.03*(time1 - time0)/(NODES-1);    
  //Mdr is constant for all the forward time computations
  MfromLeftEulers(Mdr,cacheSlope*rollV,0.0,0.0);  
  for (i=(NODES-1)/2+1; i<NODES; i++) {    //moving foward in time first
    Q[i][4] = Q[i-1][4] + cacheSlope;    //new time epoch
    //epoch center time relative to the center line
    relT = double(i - (NODES-1)/2 - 0.5)*cacheSlope;  
    rollComb = relT*rollV;
    gimVec[0] = 0.0;      //gimbal rotation vector direction in the middle of the epoch
    gimVec[1] =  cos(rollComb);
    gimVec[2] = -sin(rollComb);
    //incremental rotation due to the gimbal (forward motion compensation)
    MfromVecLeftAngle(Mdg, gimVec, fmc*cacheSlope);    
    //the new rotation matrix is Transpose(Mdr)*Transpose(Mdg)*M0--NOTE the order swap and 
    //  transposes are needed because both Mdr and Mdg were caculated in image space and need to be 
    //  transposed to apply to object space
    mtxm_c(Mdg, M0, Mtemp1);  
    //M0 is now what would typically be considered the rotation matrix of an image.  It rotates a 
    //  vector from the target centric space into camera space.  However, what is standard to 
    //  include in the cube labels is a rotation from camera space to J2000.  M0 is therefore the 
    //  transpose of the first part of this rotation.  Transpose(M0) is the rotation from camera 
    //  space to target centric space
    mtxm_c(Mdr, Mtemp1, M0);  
    //now adding the rotation from the target frame to J2000
    spRot->SetEphemerisTime(Q[i][4]);
    //this actually gives the rotation from J2000 to target centric--hence the mxmt_c function being 
    //  used later
    M_J2toT = spRot->Matrix();   
    for(j=0; j<3; j++)  //reformating M_J2toT to a 3x3
      for(k=0; k<3; k++)
        Mtemp1[j][k] = M_J2toT[3*j+k];
    mxm_c(M0, Mtemp1, Mtemp2);
    M2Q(Mtemp2, Q[i]);    //convert to a quarterion
  }

  MfromLeftEulers(M0, omega, phi, kappa);  //rotation matrix in the center Q[(NOPDES-1)/2]
  //Mdr is constant for all the backward time computations
  MfromLeftEulers(Mdr, -cacheSlope*rollV, 0.0, 0.0);    
  for (i=(NODES-1)/2-1; i>=0; i--) {  //moving backward in time
    Q[i][4] = Q[i+1][4] - cacheSlope;  //new time epoch
    //epoch center time relative to the center line
    relT = double(i  - (NODES-1)/2 + 0.5)*cacheSlope;  
    rollComb = relT*rollV;
    gimVec[0] = 0.0;      //gimbal rotation vector direction in the middle of the epoch
    gimVec[1] =  cos(rollComb);
    gimVec[2] = -sin(rollComb);
    //incremental rotation due to the gimbal (forward motion compensation)
    MfromVecLeftAngle(Mdg, gimVec, -fmc*cacheSlope);    
    //the new rotation matrix is Transpose(Mdr)*Transpose(Mdg)*M0    NOTE the order swap and 
    //  transposes are needed because both Mdr and Mdg were caculated in image space and need to be
    //  transposed to apply to object space
    mtxm_c(Mdg, M0, Mtemp1);  
    //M0 is now what would typically be considered the rotation matrix of an image.  It rotates a 
    //  vector from the target centric space into camera space.  However, what is standard to 
    //  include in the cube labels is a rotation from camera space to J2000.  M0 is therefore the 
    //  transpose of the first part of this rotation.  Transpose(M0) is the rotation from camera 
    //  space to target centric space
    mtxm_c(Mdr, Mtemp1, M0);  
    //now adding the rotation from the target frame to J2000
    spRot->SetEphemerisTime(Q[i][4]);
    M_J2toT = spRot->Matrix();
    for(j=0; j<3; j++)  //reformating M_J2toT to a 3x3
      for(k=0; k<3; k++)
        Mtemp1[j][k] = M_J2toT[3*j+k];
    mxm_c(M0, Mtemp1, Mtemp2);
    M2Q(Mtemp2, Q[i]);    //convert to a quarterion
  }
  //fill in the table
  for (i=0; i<NODES; i++) {
    recordRot[0] = Q[i][0];
    recordRot[1] = Q[i][1];
    recordRot[2] = Q[i][2];
    recordRot[3] = Q[i][3];
    recordRot[4] = Q[i][4];
    tableRot += recordRot;
  }
  tableRot.Label() += PvlKeyword("CkTableStartTime", toString(Q[0][4]));
  tableRot.Label() += PvlKeyword("CkTableEndTime", toString(Q[NODES-1][4]));
  tableRot.Label() += PvlKeyword("Description", "Created by appollopan2isis");

  keyword.setName("TimeDependentFrames");
  keyword.setValue(toString(scFrameCode));
  keyword.addValue("1");
  tableRot.Label() += keyword;

  keyword.setName("ConstantFrames");
  keyword.setValue(toString(insCode));
  keyword.addValue(toString(scFrameCode));
  tableRot.Label() += keyword;

  keyword.setName("ConstantRotation");
  keyword.setValue("1");
  for (i=1;i<9;i++)
    if (i%4 == 0) keyword.addValue("1");
    else keyword.addValue("0");
  tableRot.Label() += keyword;
  panCube.write(tableRot);


  /////////////////////////Attach a table with all the measurements of the fiducial mark locations.
  Chip patternS,searchS;   //scaled pattern and search chips
  Cube  fidC;  //Fiducial image

  //line and sample coordinates for looping through the panCube
  double l=1,s=1,sample,line,sampleInitial=1,lineInitial=1,play;  

  int  regStatus,
       fidn,
       panS,
       refL,  //number of lines in the patternS
       refS;  //number of samples in the patternS
  Pvl pvl;

  bool foundFirst=false;

  QString fileName;

  panS = panCube.sampleCount();

  //Table definition
  TableRecord recordFid;
  TableField indexFid("FID_INEX",TableField::Integer);
  TableField xFid("X_COORD",TableField::Double);
  TableField yFid("Y_COORD",TableField::Double);
  recordFid += indexFid;
  recordFid += xFid;
  recordFid += yFid;
  Table tableFid("Fiducial Measurement",recordFid);

  //read the image resolutions and scale the constants acordingly
  double  resolution = ui.GetDouble("MICRONS"),    //pixel size in microns
          scale            = SCALE  *5.0/resolution,  //reduction scale for fast autoregistrations
          searchHeight     = SEARCHh*5.0/resolution,  //number of lines (in 5-micron-pixels) in 
                                                      //  search space for the first fiducial
          searchCellSize   = SEARCHc*5.0/resolution,  //height/width of search chips block
          averageSamples   = AVERs  *5.0/resolution,  //scaled smaples between fiducials
          averageLines     = AVERl  *5.0/resolution;  //scaled average distance between the top and 
                                                      //bottom fiducials

  if( 15.0/resolution < 1.5) play=1.5;
  else play = 15.0/resolution; 

  //copy the patternS chip (the entire ApolloPanFiducialMark.cub)
  FileName fiducialFileName("$apollo15/calibration/ApolloPanFiducialMark.cub");
  fidC.open(fiducialFileName.expanded(),"r");
  if( !fidC.isOpen() ) {
    QString msg = "Unable to open the fiducial patternS cube: ApolloPanFiducialMark.cub\n";
    throw IException(IException::User, msg, _FILEINFO_);
  }
  refL = fidC.lineCount();
  refS = fidC.sampleCount();
  //scaled pattern chip for fast matching
  patternS.SetSize(int((refS-2)/SCALE), int((refL-2)/SCALE));  
  patternS.TackCube((refS-1)/2, (refL-1)/2);
  patternS.Load(fidC, 0, SCALE);

  //parameters for maximum correlation autoregestration  
  // see:  file:///usgs/pkgs/isis3nightly2011-09-21/isis/doc/documents/patternSMatch/patternSMatch.html#DistanceTolerance
  FileName fiducialPvl("$apollo15/templates/apolloPanFiducialFinder.pvl");
  pvl.read(fiducialPvl.expanded());  //read in the autoreg parameters
  AutoReg *arS = AutoRegFactory::Create(pvl);

  *arS->PatternChip()   = patternS;  //patternS chip is constant

  //set up a centroid measurer
  CentroidApolloPan centroid(resolution);
  Chip inputChip,selectionChip;
  inputChip.SetSize(int(ceil(200*5.0/resolution)), int(ceil(200*5.0/resolution)));
  fileName = ui.GetFileName("FROM");
  if( panCube.pixelType() == 1)  //UnsignedByte
    centroid.setDNRange(12, 1e99);  //8 bit bright target
  else
    centroid.setDNRange(3500, 1e99);  //16 bit bright target

  Progress progress;
  progress.SetText("Locating Fiducials");
  progress.SetMaximumSteps(91);

  //Search for the first fiducial, search sizes are constanst
  searchS.SetSize(int(searchCellSize/scale),int(searchCellSize/scale));  
  //now start searching along a horizontal line for the first fiducial mark
  for(l = searchCellSize/2;
      l<searchHeight+searchCellSize/2.0 && !foundFirst;
      l+=searchCellSize-125*5.0/resolution) {
    for (s = searchCellSize/2;
         s < averageSamples + searchCellSize/2.0 && !foundFirst;
         s += searchCellSize-125*5.0/resolution) {
      searchS.TackCube(s, l);
      searchS.Load(panCube, 0, scale);
      *arS->SearchChip() = searchS;
      regStatus = arS->Register();
      if (regStatus == AutoReg::SuccessPixel) {
        inputChip.TackCube(arS->CubeSample(), arS->CubeLine());
        inputChip.Load(panCube, 0, 1);
        inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine());
        //continuous dynamic range selection
        centroid.selectAdaptive(&inputChip, &selectionChip);    
        //elliptical trimming/smoothing
        if (centroid.elipticalReduction(&selectionChip, 95, play, 2000)) {  
          //center of mass to reduce selection to a single measure
          centroid.centerOfMass(&selectionChip, &sample, &line);    
          inputChip.SetChipPosition(sample, line);
          sampleInitial = inputChip.CubeSample();
          lineInitial   = inputChip.CubeLine();
          foundFirst = true;  //once the first fiducial is found stop
        }
      }
    }
  }
  if(s>=averageLines+searchCellSize/2.0) {
     QString msg = "Unable to locate a fiducial mark in the input cube [" + fileName + 
                  "].  Check FROM and MICRONS parameters.";
     throw IException(IException::Io, msg, _FILEINFO_);
     return;
  }
  progress.CheckStatus();

  //record first fiducial measurement in the table
  recordFid[0] = 0;
  recordFid[1] = sampleInitial;
  recordFid[2] = lineInitial;
  tableFid += recordFid;
  for (s= sampleInitial, l=lineInitial, fidn=0;  s<panS;  s+=averageSamples, fidn++) {
     //corrections for half spacing of center fiducials
     if (fidn == 22) s -= averageSamples/2.0;
     if (fidn == 23) s -= averageSamples/2.0;

     //look for the bottom fiducial
     searchS.TackCube(s,l+averageLines);
     searchS.Load(panCube, 0, scale);
     *arS->SearchChip()   = searchS;
     regStatus = arS->Register();
     if (regStatus == AutoReg::SuccessPixel) {
       inputChip.TackCube(arS->CubeSample(), arS->CubeLine());
       inputChip.Load(panCube,0,1);
       inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine());
     }
     else {  //if autoreg is unsuccessful, a larger window will be used
       inputChip.TackCube(s, l+averageLines);
       inputChip.Load(panCube, 0, 1);
       inputChip.SetCubePosition(s, l+averageLines);
     }
     centroid.selectAdaptive(&inputChip, &selectionChip);  //continuous dynamic range selection
     //elliptical trimming/smoothing... if this fails move on
     if (centroid.elipticalReduction(&selectionChip, 95, play, 2000) != 0 ) {      
       //center of mass to reduce selection to a single measure
       centroid.centerOfMass(&selectionChip, &sample, &line);      
       inputChip.SetChipPosition(sample, line);
       sample = inputChip.CubeSample();
       line   = inputChip.CubeLine();
       recordFid[0] = fidn*2+1;
       recordFid[1] = sample;
       recordFid[2] = line;
       tableFid += recordFid;
     }
     progress.CheckStatus();

     //look for the top fiducial
     if (s == sampleInitial) //first time through the loop?
       continue;  //then the top fiducial was already found
     searchS.TackCube(s, l);
     searchS.Load(panCube, 0, scale);
     *arS->SearchChip()   = searchS;
     regStatus = arS->Register();
     if (regStatus == AutoReg::SuccessPixel) {
       inputChip.TackCube(arS->CubeSample(), arS->CubeLine());
       inputChip.Load(panCube, 0, 1);
       inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine());
     }
     else {  //if autoreg is unsuccessful, a larger window will be used
       inputChip.TackCube(s, l);
       inputChip.Load(panCube, 0, 1);
       inputChip.SetCubePosition(s, l);
     }
     centroid.selectAdaptive(&inputChip, &selectionChip);//continuous dynamic range selection
     //inputChip.Write("inputTemp.cub");//debug
     //selectionChip.Write("selectionTemp.cub");//debug
     //elliptical trimming/smoothing... if this fails move on
     if (centroid.elipticalReduction(&selectionChip, 95, play, 2000) !=0) {    
       //center of mass to reduce selection to a single measure
       centroid.centerOfMass(&selectionChip, &sample, &line);  
       inputChip.SetChipPosition(sample, line);
       //when finding the top fiducial both s and l are refined for a successful measurement, 
       //  this will help follow trends in the scaned image
       s = inputChip.CubeSample(); 
       l = inputChip.CubeLine();
       recordFid[0] = fidn*2;
       recordFid[1] = s;
       recordFid[2] = l;
       tableFid += recordFid;
     }
     progress.CheckStatus();
  }

  panCube.write(tableFid);
  //close the new cube
  panCube.close(false);
  panCube.open(ui.GetFileName("FROM"),"rw");
 
  delete spPos;
  delete spRot;

  //now instantiate a camera to make sure all of this is working
  ApolloPanoramicCamera* cam = (ApolloPanoramicCamera*)(panCube.camera());
  //log the residual report from interior orientation 
  PvlGroup residualStats("InteriorOrientationStats");
  residualStats += PvlKeyword("FiducialsFound",  toString(tableFid.Records()));
  residualStats += PvlKeyword("ResidualMax",  toString(cam->intOriResidualMax()),"pixels");
  residualStats += PvlKeyword("ResidualMean", toString(cam->intOriResidualMean()),"pixels");
  residualStats += PvlKeyword("ResidualStdev", toString(cam->intOriResidualStdev()),"pixels");

  Application::Log( residualStats ); 


  return;
}
Ejemplo n.º 15
0
void IsisMain() {
  Process p;
  Cube *icube = p.SetInputCube("FROM");
  Camera *cam = icube->camera();

  UserInterface &ui = Application::GetUserInterface();

  QString from = ui.GetFileName("FROM");
  int sinc = ui.GetInteger("SINC");
  int linc = ui.GetInteger("LINC");
  CameraStatistics camStats(cam, sinc, linc, from);

  // Send the Output to the log area
  Pvl statsPvl = camStats.toPvl();
  for (int i = 0; i < statsPvl.groups(); i++) {
    Application::Log(statsPvl.group(i));
  }

  if(ui.WasEntered("TO")) {
    QString outfile = FileName(ui.GetFileName("TO")).expanded();
    bool exists = FileName(outfile).fileExists();
    bool append = ui.GetBoolean("APPEND");

    // If the user chose a format of PVL, then write to the output file ("TO")
    if(ui.GetString("FORMAT") == "PVL") {
      (append) ? statsPvl.append(outfile) : statsPvl.write(outfile);
    }
    else {
      // Create a flatfile of the data with columhn headings the flatfile is
      // comma-delimited and can be imported in to spreadsheets
      ofstream os;
      bool writeHeader = true;
      if(append) {
        os.open(outfile.toAscii().data(), ios::app);
        if(exists) {
          writeHeader = false;
        }
      }
      else {
        os.open(outfile.toAscii().data(), ios::out);
      }

      // if new file or append and no file exists then write header
      if(writeHeader) {
        os << "Filename," <<
           "LatitudeMinimum," <<
           "LatitudeMaximum," <<
           "LatitudeAverage," <<
           "LatitudeStandardDeviation," <<
           "LongitudeMinimum," <<
           "LongitudeMaximum," <<
           "LongitudeAverage," <<
           "LongitudeStandardDeviation," <<
           "SampleResolutionMinimum," <<
           "SampleResolutionMaximum," <<
           "SampleResolutionAverage," <<
           "SampleResolutionStandardDeviation," <<
           "LineResolutionMinimum," <<
           "LineResolutionMaximum," <<
           "LineResolutionAverage," <<
           "LineResolutionStandardDeviation," <<
           "ResolutionMinimum," <<
           "ResolutionMaximum," <<
           "ResolutionAverage," <<
           "ResolutionStandardDeviation," <<
           "AspectRatioMinimum," <<
           "AspectRatioMaximum," <<
           "AspectRatioAverage," <<
           "AspectRatioStandardDeviation," <<
           "PhaseMinimum," <<
           "PhaseMaximum," <<
           "PhaseAverage," <<
           "PhaseStandardDeviation," <<
           "EmissionMinimum," <<
           "EmissionMaximum," <<
           "EmissionAverage," <<
           "EmissionStandardDeviation," <<
           "IncidenceMinimum," <<
           "IncidenceMaximum," <<
           "IncidenceAverage," <<
           "IncidenceStandardDeviation," <<
           "LocalSolarTimeMinimum," <<
           "LocalSolarTimeMaximum," <<
           "LocalSolarTimeAverage," <<
           "LocalSolarTimeStandardDeviation," <<
           "LocalRadiusMaximum," <<
           "LocalRadiusMaximum," <<
           "LocalRadiusAverage," <<
           "LocalRadiusStandardDeviation," <<
           "NorthAzimuthMinimum," <<
           "NorthAzimuthMaximum," <<
           "NorthAzimuthAverage," <<
           "NorthAzimuthStandardDeviation," << endl;
      }
      os << FileName(from).expanded() << ",";
      //call the function to write out the values for each group
      writeFlat(os, camStats.getLatStat());
      writeFlat(os, camStats.getLonStat());
      writeFlat(os, camStats.getSampleResStat());
      writeFlat(os, camStats.getLineResStat());
      writeFlat(os, camStats.getResStat());
      writeFlat(os, camStats.getAspectRatioStat());
      writeFlat(os, camStats.getPhaseStat());
      writeFlat(os, camStats.getEmissionStat());
      writeFlat(os, camStats.getIncidenceStat());
      writeFlat(os, camStats.getLocalSolarTimeStat());
      writeFlat(os, camStats.getLocalRaduisStat());
      writeFlat(os, camStats.getNorthAzimuthStat());
      os << endl;
    }
  }

  if(ui.GetBoolean("ATTACH")) {

    QString cam_name = "CameraStatistics";

    //Creates new CameraStatistics Table
    TableField fname("Name", Isis::TableField::Text, 20);
    TableField fmin("Minimum", Isis::TableField::Double);
    TableField fmax("Maximum", Isis::TableField::Double);
    TableField favg("Average", Isis::TableField::Double);
    TableField fstd("StandardDeviation", Isis::TableField::Double);

    TableRecord record;
    record += fname;
    record += fmin;
    record += fmax;
    record += favg;
    record += fstd;

    Table table(cam_name, record);

    // Place all the gathered camera statistics in a table and attach it to the
    // cube. Skip "User Parameters" group.
    for (int i = 1; i < statsPvl.groups(); i++) {
      PvlGroup &group = statsPvl.group(i);

      int entry = 0;
      record[entry] = group.name();
      entry++;
      for (int j = 0; j < group.keywords(); j++) {
        record[entry] = toDouble(group[j][0]);
        entry++;
      }
      table += record;
    }

    icube->reopen("rw");
    icube->write(table);
    p.WriteHistory(*icube);
    icube->close();
  }
}
Ejemplo n.º 16
0
void IsisMain() {

    // Use a regular Process
    Process p;

    // Get user parameters and error check
    UserInterface &ui = Application::GetUserInterface();
    QString from = ui.GetFileName("FROM");
    QString to = FileName(ui.GetFileName("TO")).expanded();
//TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS
//  double HRSCNadirCenterTime = ui.GetDouble("HRSC_NADIRCENTERTIME");

    // Open input cube and Make sure this is a lev1 image (ie, not map projected)
    Cube cube;
    cube.open(from);

    if (cube.isProjected()) {
        QString msg = "Input images is a map projected cube ... not a level 1 image";
        throw IException(IException::User, msg, _FILEINFO_);
    }

    // Initialize the camera
    Cube *input = p.SetInputCube("FROM");
    Pvl *cubeHeader = input->label();
    Camera *cam = input->camera();
    CameraDetectorMap *detectorMap = cam->DetectorMap();
    CameraFocalPlaneMap *focalMap = cam->FocalPlaneMap();
    CameraDistortionMap *distortionMap = cam->DistortionMap();
    CameraGroundMap *groundMap = cam->GroundMap();

    // Make sure the image contains the InstrumentPointing (aka CK) blob/table
    PvlGroup test = cube.label()->findGroup("Kernels", Pvl::Traverse);
    QString InstrumentPointing = (QString) test["InstrumentPointing"];
    if (InstrumentPointing != "Table") {
        QString msg = "Input image does not contain needed SPICE blobs...run spiceinit with attach=yes.";
        throw IException(IException::User, msg, _FILEINFO_);
    }

    // Open output line scanner keyword file
    ofstream toStrm;
    toStrm.open(to.toAscii().data(), ios::trunc);
    if (toStrm.bad()) {
        QString msg = "Unable to open output TO file";
        throw IException(IException::User, msg, _FILEINFO_);
    }

    // Get required keywords from instrument and band groups
    PvlGroup inst = cube.label()->findGroup("Instrument", Pvl::Traverse);
    QString instrumentId = (QString) inst["InstrumentId"];

    bool     isMocNA = false;
//TO DO: UNCOMMENT THIS LINES ONCE MOC IS WORKING IN SS
//  bool     isMocWARed = false;
    bool     isHiRise = false;
    bool     isCTX = false;
    bool     isLroNACL = false;
    bool     isLroNACR = false;
    bool     isHRSC = false;
//TO DO: UNCOMMENT THESE LINE ONCE MOC IS WORKING IN SS
//  if (instrumentId == "MOC") {
//    PvlGroup band = cube.label()->findGroup("BandBin", Pvl::Traverse);
//    QString filter = (QString) band["FilterName"];
//
//    if (strcmp(filter.toAscii().data(), "BROAD_BAND") == 0)
//      isMocNA = true;
//    else if (strcmp(filter.toAscii().data(), "RED") == 0)
//      isMocWARed = true;
//    else if (strcmp(filter.toAscii().data(), "BLUE") == 0) {
//      QString msg = "MOC WA Blue filter images not supported for Socet Set mapping";
//      throw IException(IException::User, msg, _FILEINFO_);
//    }
//  }
//  else if (instrumentId == "IdealCamera") {
//TO DO: DELETE THIS LINE ONCE MOC IS WORKING IN SS
    if (instrumentId == "IdealCamera") {
        PvlGroup orig = cube.label()->findGroup("OriginalInstrument",  Pvl::Traverse);
        QString origInstrumentId = (QString) orig["InstrumentId"];
        if (origInstrumentId == "HIRISE") {
            isHiRise = true;
        }
        else {
            QString msg = "Unsupported instrument: " + origInstrumentId;
            throw IException(IException::User, msg, _FILEINFO_);
        }
    }
    else if (instrumentId == "HIRISE") {
        isHiRise = true;
    }
    else if (instrumentId == "CTX") {
        isCTX = true;
    }
    else if (instrumentId == "NACL") {
        isLroNACL = true;
    }
    else if (instrumentId == "NACR") {
        isLroNACR = true;
    }
//TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS
//  else if (instrumentId == "HRSC") isHRSC = true;
    else {
        QString msg = "Unsupported instrument: " + instrumentId;
        throw IException(IException::User, msg, _FILEINFO_);
    }

    int ikCode = cam->naifIkCode();

    // Get Focal Length.
    // NOTE:
    //   For MOC Wide Angle, cam->focal_length returns the focal length
    //      in pixels, so we must convert from pixels to mm using the PIXEL_SIZE
    //      of 0.007 mm gotten from $ISIS3DATA/mgs/kernels/ik/moc20.ti.  (The
    //      PIXEL_PITCH value gotten from cam->PixelPitch is 1.0 since the
    //      focal length used by ISIS in this case is in pixels)
    //      For reference: the MOC WA blue filter pixel size needs an adjustment
    //      of 1.000452 (see p_scale in MocWideAngleDistortionMap.cpp), so that
    //      the final blue filter pixel size = (0.007 / 1.000452)
    //
    //   For all other cameras, cam->focal_length returns the focal
    //      length in mm, as needed by Socet Set

    double focal = cam->FocalLength();  // focal length returned in mm

//TO DO: UNCOMMENT THESE LINES ONCE HRSC and MOC IS WORKING IN SS
//  if (isMocWARed)
//    focal = focal * 0.007;  // pixel to mm conversion
//  else if (isHRSC)
//  {
//    switch (ikCode) {
//      case -41219:                   //S1: fwd stereo
//        focal = 184.88;
//        break;
//      case -41218:                   //IR: infra-red
//        focal = 181.57;
//        break;
//      case -41217:                   //P1: fwd photo
//        focal = 179.16;
//        break;
//      case -41216:                   // GREEN
//        focal = 175.31;
//        break;
//      case -41215:                   // NADIR
//        focal = 175.01;
//        break;
//      case -41214:                   // BLUE
//        focal = 175.53;
//        break;
//      case -41213:                   // P2: aft photo
//        focal = 179.19;
//        break;
//      case -41212:                   // RED
//        focal = 181.77;
//        break;
//      case -41211:                   // S2: aft stereo
//        focal = 184.88;
//        break;
//      default:
//        break;
//    }
//  }

    // Get instrument summing modes
    int csum = (int) detectorMap->SampleScaleFactor();
    int dsum = (int) detectorMap->LineScaleFactor();

    if (isLroNACL || isLroNACR || isHRSC)
        dsum = csum;

    // Calculate location of boresight in image space, these are zero-based values
    //
    // Note: For MOC NA, the boresight is at the image center
    //       For MOC WA, MRO HiRISE, MRO CTX, LRO_NACL, LRO_NACR and HRSC the
    //       boresight is not at the detector center, but the boresight is at the
    //       center of a NOPROJ'ED MRO HIRISE image

    // Get line/samp of boresight pixel in detector space (summing == 1)
    focalMap->SetFocalPlane(0.0, 0.0);
    double detectorBoresightSample = focalMap->DetectorSample();
    double detectorBoresightLine = focalMap->DetectorLine();

    // Convert sample of boresight pixel in detector into image space
    // (summing, etc., is accounted for.)
    detectorMap->SetDetector(detectorBoresightSample, detectorBoresightLine);
    double boresightSample = detectorMap->ParentSample();

    // Set Atmospheric correction coefficients to 0
    double atmco[4] = {0.0, 0.0, 0.0, 0.0};

    // Get totalLines, totalSamples and account for summed images
    int totalLines = cube.lineCount();
    int totalSamples = cube.sampleCount();

    // Get the Interval Time in seconds and calculate
    // scan duration in seconds
    double scanDuration = 0.0;
    double intTime = 0.0;

//TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS
//  int numIntTimes = 0.0;
//  vector<LineRateChange> lineRates;
//  if (isHRSC) {
//    numIntTimes = GetHRSCLineRates(&cube, lineRates, totalLines, HRSCNadirCenterTime);
//    if (numIntTimes == 1) {
//      LineRateChange lrc = lineRates.at(0);
//      intTime = lrc.GetLineScanRate();
//    }
//    if (numIntTimes <= 0) {
//      QString msg = "HRSC: Invalid number of scan times";
//      throw IException(IException::Programmer, msg, _FILEINFO_);
//    }
//    else
//      scanDuration = GetHRSCScanDuration(lineRates, totalLines);
//  }
//  else {
//
//  TO DO: indent the following two lines when HRSC is working in SS
    intTime = detectorMap->LineRate();  //LineRate is in seconds
    scanDuration = intTime * totalLines;
//TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS
//  }

    // For reference, this is the code if calculating interval time
    // via LineExposureDuration keyword off image labels:
    //
    // if (isMocNA || isMocWARed)
    //   intTime = exposureDuration * (double) dsum / 1000.0;
    // else if (isHiRise)
    //   intTime = exposureDuration * (double) dsum / 1000000.0;

    // Get along and cross scan pixel size for NA and WA sensors.
    // NOTE:
    //     1) The MOC WA pixel size is gotten from moc20.ti and is 7 microns
    //         HRSC pixel size is from the Instrument Addendum file
    //     2) For others, cam->PixelPitch() returns the pixel pitch (size) in mm.
    double alongScanPxSize = 0.0;
    double crossScanPxSize = 0.0;
//TO DO: UNCOMMENT THESE LINES ONCE MOC IS WORKING IN SS
//  if (isMocWARed || isHRSC) {
//    alongScanPxSize = csum * 0.007;
//    crossScanPxSize = dsum * 0.007;
//  }
//  else {
//
//  TO DO: indent the following 24 lines when HRSC is working in SS
    crossScanPxSize = dsum * cam->PixelPitch();

    // Get the ephemeris time, ground position and undistorted focal plane X
    // coordinate at the center line/samp of image
    cam->SetImage(cube.sampleCount() / 2.0, cube.lineCount() / 2.0);

    double tMid = cam->time().Et();

    const double latCenter = cam->UniversalLatitude();
    const double lonCenter = cam->UniversalLongitude();
    const double radiusCenter = cam->LocalRadius().meters();

    double uXCenter = distortionMap->UndistortedFocalPlaneX();

    // from the ground position at the image center, increment the ephemeris
    // time by the line rate and map the ground position into the sensor in
    // undistorted focal plane coordinates

    cam->setTime(iTime(tMid + intTime));
    double uX, uY;
    groundMap->GetXY(latCenter, lonCenter, radiusCenter, &uX, &uY);

    // the along scan pixel size is the difference in focal plane X coordinates
    alongScanPxSize = abs(uXCenter - uX);

//TO DO: UNCOMMENT THIS LINE ONCE MOC and HRSC IS WORKING IN SS
//  }

    // Now that we have totalLines, totalSamples, alongScanPxSize and
    // crossScanPxSize, fill the Interior Orientation Coefficient arrays
    double ioCoefLine[10];
    double ioCoefSample[10];
    for (int i = 0; i <= 9; i++) {
        ioCoefLine[i] = 0.0;
        ioCoefSample[i] = 0.0;
    }

    ioCoefLine[0] = totalLines / 2.0;
    ioCoefLine[1] = 1.0 / alongScanPxSize;

    ioCoefSample[0] = totalSamples / 2.0;
    ioCoefSample[2] = 1.0 / crossScanPxSize;

    // Update the Rectification Terms found in the base sensor class
    double rectificationTerms[6];
    rectificationTerms[0] = totalLines / 2.0;
    rectificationTerms[1] = 0.0;
    rectificationTerms[2] = 1.0;
    rectificationTerms[3] = totalSamples / 2.0;
    rectificationTerms[4] = 1.0;
    rectificationTerms[5] = 0.0;

    // Fill the triangulation parameters array
    double triParams[18];
    for (int i = 0; i <= 17; i++)
        triParams[i] = 0.0;

    triParams[15] = focal;

    // Set the Center Ground Point at the SOCET Set image, in radians
    double centerGp[3];
    double radii[3] = {0.0, 0.0, 0.0};
    Distance Dradii[3];

    cam->radii(Dradii);
    radii[0] = Dradii[0].kilometers();
    radii[1] = Dradii[1].kilometers();
    radii[2] = Dradii[2].kilometers();

    cam->SetImage(boresightSample, totalLines / 2.0);

    centerGp[0] = DEG2RAD *
                  TProjection::ToPlanetographic(cam->UniversalLatitude(), radii[0], radii[2]);
    centerGp[1] = DEG2RAD * TProjection::To180Domain(cam->UniversalLongitude());
    centerGp[2] = 0.0;
    //**** NOTE: in the import_pushbroom SOCET SET program, centerGp[2] will be set to the SS
    //**** project's gp_origin_z

    // Now get keyword values that depend on ephemeris data.

    // First get the ephemeris time and camera Lat Lon at image center line, boresight sample.
    double centerLine = double(totalLines) / 2.0;

    cam->SetImage(boresightSample, centerLine); //set to boresight of image
    double etCenter = cam->time().Et();

    // Get the sensor position at the image center in ographic lat,
    // +E lon domain 180 coordinates, radians, height in meters
    double sensorPosition[3] = {0.0, 0.0, 0.0};
    double ocentricLat, e360Lon;
    cam->subSpacecraftPoint(ocentricLat, e360Lon);
    sensorPosition[0] = DEG2RAD * TProjection::ToPlanetographic(ocentricLat, radii[0], radii[2]);
    sensorPosition[1] = DEG2RAD * TProjection::To180Domain(e360Lon);
    sensorPosition[2] = cam->SpacecraftAltitude() * 1000.0;

    // Build the ephem data.  If the image label contains the InstrumentPosition
    // table, use it as a guide for number and spacing of Ephem points.
    // Otherwise (i.e, for dejittered HiRISE images), the number and spacing of
    // ephem points based on hardcoded dtEphem value

    // Using the InstrumentPosition table as a guide build the ephem data
    QList< QList<double> > ephemPts;
    QList< QList<double> > ephemRates;

    PvlGroup kernels = cube.label()->findGroup("Kernels", Pvl::Traverse);
    QString InstrumentPosition = (QString) kernels["InstrumentPosition"];

    int numEphem = 0;      // number of ephemeris points
    double dtEphem = 0.0;  // delta time of ephemeris points, seconds
    if (InstrumentPosition == "Table") {
        // Labels contain SPK blob
        // set up Ephem pts/rates number and spacing
        Table tablePosition("InstrumentPosition", cubeHeader->fileName());
        numEphem = tablePosition.Records();

        // increase the number of ephem nodes by 20%.  This is somewhat random but
        // generally intended to compensate for having equally time spaced nodes
        // instead of of the potentially more efficient placement used by spiceinit
        numEphem = int(double(numEphem) * 1.2);

        // if numEphem calcutated from SPICE blobs is too sparse for SOCET Set,
        // mulitiply it by a factor of 30
        // (30X was settled upon emperically.  In the future, make this an input parameter)
        if (numEphem <= 10) numEphem = tablePosition.Records() * 30;

        // make the number of nodes odd
        numEphem  = (numEphem % 2) == 1 ? numEphem : numEphem + 1;

        // SOCET has a max number of ephem pts of 10000, and we're going to add twenty...
        if (numEphem > 10000 - 20) numEphem = 9979;

        dtEphem = scanDuration / double(numEphem);

        //build the tables of values
        double et = etCenter - (((numEphem - 1) / 2) * dtEphem);
        for (int i = 0; i < numEphem; i++) {
            cam->setTime(iTime(et));
            SpiceRotation *bodyRot = cam->bodyRotation();
            vector<double> pos = bodyRot->ReferenceVector(cam->instrumentPosition()->Coordinate());
//TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
            //vector<double> vel = bodyRot->ReferenceVector(cam->instrumentPosition()->Velocity());

            //Add the ephemeris position and velocity to their respective lists, in meters and meters/sec
            QList<double> ephemPt;
            QList<double> ephemRate;
            ephemPts.append(ephemPt << pos[0] * 1000 << pos[1] * 1000 << pos[2] * 1000);
//TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
            //ephemRates.append(ephemRate << vel[0] * 1000 << vel[1] * 1000 << vel[2] * 1000);

            et += dtEphem;
        }

//TO DO: WHEN VELOCITY BLOBS ARE CORRECT IN ISIS, linearlly interpolate 10 nodes rather than 11
//       (need 11 now for computation of velocity at first and last ephemeris point)
        // linearlly interpolate 11 additional nodes before line 1 (SOCET requires this)
        for (int i = 0; i < 11; i++) {
            double vec[3] = {0.0, 0.0, 0.0};
            vec[0] = ephemPts[0][0] + (ephemPts[0][0] - ephemPts[1][0]);
            vec[1] = ephemPts[0][1] + (ephemPts[0][1] - ephemPts[1][1]);
            vec[2] = ephemPts[0][2] + (ephemPts[0][2] - ephemPts[1][2]);
            QList<double> ephemPt;
            ephemPts.prepend (ephemPt << vec[0] << vec[1] << vec[2]);

//TO DO: UNCOMMENT THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
            //vec[0] = ephemRates[0][0] + (ephemRates[0][0] - ephemRates[1][0]);
            //vec[1] = ephemRates[0][1] + (ephemRates[0][1] - ephemRates[1][1]);
            //vec[2] = ephemRates[0][2] + (ephemRates[0][2] - ephemRates[1][2]);
            //QList<double> ephemRate;
            //ephemRates.prepend (ephemRate << vec[0] << vec[1] << vec[2]);
        }

//TO DO: WHEN VELOCITY BLOBS ARE CORRECT IN ISIS, linearlly interpolate 10 nodes rather than 11
//       (need 11 now for computation of velocity at first and last ephemeris point)
        // linearlly interpolate 11 additional nodes after the last line (SOCET requires this)
        for (int i = 0; i < 11; i++) {
            double vec[3] = {0.0, 0.0, 0.0};
            int index = ephemPts.size() - 1;
            vec[0] = ephemPts[index][0] + (ephemPts[index][0] - ephemPts[index - 1][0]);
            vec[1] = ephemPts[index][1] + (ephemPts[index][1] - ephemPts[index - 1][1]);
            vec[2] = ephemPts[index][2] + (ephemPts[index][2] - ephemPts[index - 1][2]);
            QList<double> ephemPt;
            ephemPts.append(ephemPt << vec[0] << vec[1] << vec[2]);

//TO DO: UNCOMMENT THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
            //vec[0] = ephemRates[index][0] + (ephemRates[index][0] - ephemRates[index - 1][0]);
            //vec[1] = ephemRates[index][1] + (ephemRates[index][1] - ephemRates[index - 1][1]);
            //vec[2] = ephemRates[index][2] + (ephemRates[index][2] - ephemRates[index - 1][2]);
            //QList<double> ephemRate;
            //ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]);
        }

        numEphem += 20;

//TO DO: DELETE THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
        // Compute the spacecraft velocity at each ephemeris point
        double deltaTime = 2.0 * dtEphem;
        for (int i = 0; i < numEphem; i++) {
            double vec[3] = {0.0, 0.0, 0.0};
            vec[0] = (ephemPts[i+2][0] - ephemPts[i][0]) / deltaTime;
            vec[1] = (ephemPts[i+2][1] - ephemPts[i][1]) / deltaTime;
            vec[2] = (ephemPts[i+2][2] - ephemPts[i][2]) / deltaTime;
            QList<double> ephemRate;
            ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]);
        }

    }
    else {
        // Calculate the number of ephemeris points that are needed, based on the
        // value of dtEphem (Delta-Time-Ephemeris).  SOCET SET needs the ephemeris
        // points to exceed the image range for interpolation.  For now, attempt a
        // padding of 10 ephemeris points on either side of the image.

        if (isMocNA || isHiRise || isCTX || isLroNACL || isLroNACR || isHRSC)
            // Try increment of every 300 image lines
            dtEphem = 300 * intTime;  // Make this a user definable increment?
        else // Set increment for WA images to one second
            dtEphem = 1.0;

        // Pad by 10 ephem pts on each side of the image
        numEphem = (int)(scanDuration / dtEphem) + 20;

        // if numEphem is even, make it odd so that the number of ephemeris points
        // is equal on either side of T_CENTER
        if ((numEphem % 2) == 0)
            numEphem++;

//TO DO: DELETE THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
        numEphem = numEphem + 2; // Add two for calcuation of velocity vectors...

        // Find the ephemeris time for the first ephemeris point, and from that, get
        // to_ephem needed by SOCET (to_ephem is relative to etCenter)
        double et = etCenter - (((numEphem - 1) / 2) * dtEphem);
        for (int i = 0; i < numEphem; i++) {
            cam->setTime(iTime(et));
            SpiceRotation *bodyRot = cam->bodyRotation();
            vector<double> pos = bodyRot->ReferenceVector(cam->instrumentPosition()->Coordinate());
//TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
            //vector<double> vel = bodyRot->ReferenceVector(cam->instrumentPosition()->Velocity());

            //Add the ephemeris position and velocity to their respective lists, in meters and meters/sec
            QList<double> ephemPt;
            QList<double> ephemRate;
            ephemPts.append(ephemPt << pos[0] * 1000 << pos[1] * 1000 << pos[2] * 1000);
//TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
            //ephemRates.append(ephemRate << vel[0] * 1000 << vel[1] * 1000 << vel[2] * 1000);

            et += dtEphem;
        }
//TO DO: DELETE THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
        // Compute the spacecraft velocity at each ephemeris point
        // (We must do this when blobs are not attached because the Spice Class
        // stores in memory the same data that would be in a blob...even when reading NAIF kernels)
        double deltaTime = 2.0 * dtEphem;
        numEphem = numEphem - 2; // set numEphem back to the number we need output
        for (int i = 0; i < numEphem; i++) {
            double vec[3] = {0.0, 0.0, 0.0};
            vec[0] = (ephemPts[i+2][0] - ephemPts[i][0]) / deltaTime;
            vec[1] = (ephemPts[i+2][1] - ephemPts[i][1]) / deltaTime;
            vec[2] = (ephemPts[i+2][2] - ephemPts[i][2]) / deltaTime;
            QList<double> ephemRate;
            ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]);
        }
    }

    //update ephem stats
    double etFirstEphem = etCenter - (((numEphem - 1) / 2) * dtEphem);
    double t0Ephem = etFirstEphem - etCenter;

    // Using the intrumentPointing table as a guide build the quarternions
    // for simplicity sake we'll leave the mountingAngles as identity
    // and store the complete rotation from body fixed to camera in the
    // quarternions

    //set up quaternions number and spacing
    Table tablePointing("InstrumentPointing", cubeHeader->fileName());

    //number of quaternions
    int numQuaternions = tablePointing.Records();

    // increase the number of quaternions nodes by 20%. This is somewhat random but
    // generally intended to compensate for having equally time spaced nodes
    // instead of of the potentially more efficient placement used by spiceinit
    numQuaternions = (int)(numQuaternions * 1.2);

    // if numQuaternions calcutated from SPICE blobs is too sparse for SOCET Set,
    // mulitiply it by a factor of 30
    // (30X was settled upon emperically.  In the future, make this an input parameter)
    if (numQuaternions <= 10) numQuaternions = tablePointing.Records() * 30;

    //make the number of nodes odd
    numQuaternions = (numQuaternions % 2) == 1 ? numQuaternions : numQuaternions + 1;

    // SOCET has a max number of quaternions of 20000, and we're going to add twenty...
    if (numQuaternions > 20000 - 20) numQuaternions = 19179;

    double dtQuat = scanDuration / double(numQuaternions);

    // build the tables of values
    QList< QList<double> > quaternions;
    double et = etCenter - (((numQuaternions - 1) / 2) * dtQuat);

    for (int i = 0; i < numQuaternions; i++) {
        cam->setTime(iTime(et));
        vector<double> j2000ToBodyFixedMatrixVector = cam->bodyRotation()->Matrix();
        vector<double> j2000ToCameraMatrixVector = cam->instrumentRotation()->Matrix();
        double quaternion[4] = {0.0, 0.0, 0.0, 0.0};

        double j2000ToBodyFixedRotationMatrix[3][3], //rotation from J2000 to target (aka body, planet)
               j2000ToCameraRotationMatrix[3][3], //rotation from J2000 to spacecraft
               cameraToBodyFixedRotationMatrix[3][3]; //rotation from camera to target

        // reformat vectors to 3x3 rotation matricies
        for (int j = 0; j < 3; j++) {
            for (int k = 0; k < 3; k++) {
                j2000ToBodyFixedRotationMatrix[j][k] = j2000ToBodyFixedMatrixVector[3 * j + k];
                j2000ToCameraRotationMatrix[j][k] = j2000ToCameraMatrixVector[3 * j + k];
            }
        }

        // get the quaternion
        mxmt_c(j2000ToBodyFixedRotationMatrix, j2000ToCameraRotationMatrix,
               cameraToBodyFixedRotationMatrix);
        m2q_c(cameraToBodyFixedRotationMatrix, quaternion);

        // add the quaternion to the list of quaternions
        QList<double> quat;
        quaternions.append(quat << quaternion[1] << quaternion[2] << quaternion[3] <<
                           quaternion[0]);
        //note also that the order is changed to match socet

        et += dtQuat;
    }

    // linearlly interpolate 10 additional nodes before the first quaternion (SOCET requires this)
    for (int i = 0; i < 10; i++) {
        double vec[4] = {0.0, 0.0, 0.0, 0.0};
        vec[0] = quaternions[0][0] + (quaternions[0][0] - quaternions[1][0]);
        vec[1] = quaternions[0][1] + (quaternions[0][1] - quaternions[1][1]);
        vec[2] = quaternions[0][2] + (quaternions[0][2] - quaternions[1][2]);
        vec[3] = quaternions[0][3] + (quaternions[0][3] - quaternions[1][3]);
        QList<double> quat;
        quaternions.prepend (quat << vec[0] << vec[1] << vec[2] << vec[3]);
    }

    // linearlly interpolate 10 additional nodes after the last quaternion (SOCET requires this)
    for (int i = 0; i < 10; i++) {
        double vec[4] = {0.0, 0.0, 0.0, 0.0};
        int index = quaternions.size() - 1;
        vec[0] = quaternions[index][0] + (quaternions[index][0] - quaternions[index - 1][0]);
        vec[1] = quaternions[index][1] + (quaternions[index][1] - quaternions[index - 1][1]);
        vec[2] = quaternions[index][2] + (quaternions[index][2] - quaternions[index - 1][2]);
        vec[3] = quaternions[index][3] + (quaternions[index][3] - quaternions[index - 1][3]);
        QList<double> quat;
        quaternions.append(quat << vec[0] << vec[1] << vec[2] << vec[3]);
    }

    //update quaternions stats
    numQuaternions += 20;

    //ephemeris time of the first quarternion
    double et0Quat = etCenter - (((numQuaternions - 1) / 2) * dtQuat);

    //quadrtic time of the first quarternion
    double qt0Quat = et0Quat - etCenter;

    //query remaing transformation parameters from Camera Classes
    //transformation to distortionless focal plane
    double zDirection = distortionMap->ZDirection();

    //transformation from DistortionlessFocalPlane to FocalPlane
    vector<double> opticalDistCoefs = distortionMap->OpticalDistortionCoefficients();

    // For instruments with less than 3 distortion coefficients, set the
    // unused ones to 0.0
    opticalDistCoefs.resize(3, 0);

    //transformation from focal plane to detector
    const double *iTransS = focalMap->TransS();
    const double *iTransL = focalMap->TransL();
    double detectorSampleOrigin = focalMap->DetectorSampleOrigin();
    double detectorLineOrigin = focalMap->DetectorLineOrigin();

    //transformation from dectector to cube
    double startingSample = detectorMap->AdjustedStartingSample();
    double startingLine = detectorMap->AdjustedStartingLine();
    double sampleSumming = detectorMap->SampleScaleFactor();
    double etStart = ((LineScanCameraDetectorMap *)detectorMap)->StartTime();
    double lineOffset = focalMap->DetectorLineOffset();

    // We are done with computing keyword values, so output the Line Scanner
    // Keyword file.

    // This is the SOCET SET base sensor class keywords portion of support file:
    toStrm.setf(ios::scientific);
    toStrm << "RECTIFICATION_TERMS" << endl;
    toStrm << "        " << setprecision(14) << rectificationTerms[0] << " " <<
           rectificationTerms[1] << " " << rectificationTerms[2] << endl;
    toStrm << "        " << rectificationTerms[3] << " " << rectificationTerms[4] <<
           " " << rectificationTerms[5] << endl;

    toStrm << "GROUND_ZERO ";
    toStrm << centerGp[0] << " " << centerGp[1] << " " << centerGp[2] << endl;

    toStrm << "LOAD_PT ";
    toStrm << centerGp[0] << " " << centerGp[1] << " " << centerGp[2] << endl;

    toStrm << "COORD_SYSTEM 1" << endl;

    toStrm << "IMAGE_MOTION 0" << endl;

    // This is the line scanner sensor model portion of support file:
    toStrm << "SENSOR_TYPE USGSAstroLineScanner" << endl;
    toStrm << "SENSOR_MODE UNKNOWN" << endl;

    toStrm << "FOCAL " << focal << endl;

    toStrm << "ATMCO";
    for (int i = 0; i < 4; i++) toStrm << " " << atmco[i];
    toStrm << endl;

    toStrm << "IOCOEF_LINE";
    for (int i = 0; i < 10; i++) toStrm << " " << ioCoefLine[i];
    toStrm << endl;

    toStrm << "IOCOEF_SAMPLE";
    for (int i = 0; i < 10; i++) toStrm << " " << ioCoefSample[i];
    toStrm << endl;

    toStrm << "ABERR    0" << endl;
    toStrm << "ATMREF   0" << endl;
    toStrm << "PLATFORM   1" << endl;
    toStrm << "SOURCE_FLAG  1" << endl;
    toStrm << "SINGLE_EPHEMERIDE  0" << endl;

    //Note, for TRI_PARAMETERS, we print the first element separate from the rest so that the array
    //starts in the first column.  Otherwise, SOCET Set will treat the array as a comment
    toStrm << "TRI_PARAMETERS" << endl;
    toStrm << triParams[0];
    for (int i = 1; i < 18; i++) toStrm << " " << triParams[i];
    toStrm << endl;

    toStrm << setprecision(25) << "T_CENTER  ";
    double tCenter = 0.0;
//TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS
//  if (isHRSC) {
//    tCenter = etCenter - HRSCNadirCenterTime;
//    toStrm << tCenter << endl;
//  }
//  else
    toStrm << tCenter << endl;

    toStrm << "DT_EPHEM  " << dtEphem << endl;

    toStrm << "T0_EPHEM  ";
//TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS
//  if (isHRSC) {
//    double t = tCenter + t0Ephem;
//    toStrm << t << endl;
//  }
//  else
    toStrm << t0Ephem << endl;

    toStrm << "NUMBER_OF_EPHEM   " << numEphem << endl;

    toStrm << "EPHEM_PTS" << endl;
//TO DO: DELETE THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
    for (int i = 1; i <= numEphem; i++) {
//TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS
        //for (int i = 0; i < numEphem; i++) {
        toStrm << " " << ephemPts[i][0];
        toStrm << " " << ephemPts[i][1];
        toStrm << " " << ephemPts[i][2] << endl;
    }

    toStrm  << "\n\nEPHEM_RATES" << endl;
    for (int i = 0; i < numEphem; i++) {
        toStrm << " " << ephemRates[i][0];
        toStrm << " " << ephemRates[i][1];
        toStrm << " " << ephemRates[i][2] << endl;
    }

    toStrm << "\n\nDT_QUAT " << dtQuat << endl;
    toStrm << "T0_QUAT " << qt0Quat << endl;
    toStrm << "NUMBER_OF_QUATERNIONS  " << numQuaternions << endl;
    toStrm << "QUATERNIONS" << endl;
    for (int i = 0; i < numQuaternions; i++) {
        toStrm << " " << quaternions[i][0];
        toStrm << " " << quaternions[i][1];
        toStrm << " " << quaternions[i][2];
        toStrm << " " << quaternions[i][3] << endl;
    }

    toStrm << "\n\nSCAN_DURATION " << scanDuration << endl;

    //  UNCOMMENT toStrm << "\nNUMBER_OF_INT_TIMES " << numIntTimes << endl;
    //
    //  if (isHRSC) {
    //    toStrm  << "INT_TIMES" << endl;
    //    for (int i = 0; i < numIntTimes; i++) {
    //      LineRateChange lr = lineRates.at(i);
    //      toStrm << " " << lr.GetStartEt();
    //      toStrm << " " << lr.GetLineScanRate();
    //      toStrm << " " << lr.GetStartLine() << endl;
    //    }
    //  }
    //  else
    toStrm << "INT_TIME " << intTime << endl;

    toStrm << "\nALONG_SCAN_PIXEL_SIZE  " << alongScanPxSize << endl;
    toStrm << "CROSS_SCAN_PIXEL_SIZE  " << crossScanPxSize << endl;

    toStrm << "\nCENTER_GP";
    for (int i = 0; i < 3; i++) toStrm << " " << centerGp[i];
    toStrm << endl;

    toStrm << "SENSOR_POSITION";
    for (int i = 0; i < 3; i++) toStrm << " " << sensorPosition[i];
    toStrm << endl;

    toStrm << "MOUNTING_ANGLES";
    double mountingAngles[3] = {0.0, 0.0, 0.0};
    for (int i = 0; i < 3; i++) toStrm << " " << mountingAngles[i];
    toStrm << endl;

    toStrm << "\nTOTAL_LINES " << totalLines << endl;
    toStrm << "TOTAL_SAMPLES " << totalSamples << endl;
    toStrm << "\n\n\n" << endl;

    toStrm << "IKCODE  " << ikCode << endl;
    toStrm << "ISIS_Z_DIRECTION  " << zDirection << endl;

    toStrm << "OPTICAL_DIST_COEF";
    for (int i = 0; i < 3; i++) toStrm << " " << opticalDistCoefs[i];
    toStrm << endl;

    toStrm << "ITRANSS";
    for (int i = 0; i < 3; i++) toStrm << " " << iTransS[i];
    toStrm << endl;

    toStrm << "ITRANSL";
    for (int i = 0; i < 3; i++) toStrm << " " << iTransL[i];
    toStrm << endl;

    toStrm << "DETECTOR_SAMPLE_ORIGIN " << detectorSampleOrigin << endl;
    toStrm << "DETECTOR_LINE_ORIGIN " << detectorLineOrigin << endl;
    toStrm << "DETECTOR_LINE_OFFSET  " << lineOffset << endl;
    toStrm << "DETECTOR_SAMPLE_SUMMING  " << sampleSumming << endl;

    toStrm << "STARTING_SAMPLE " << startingSample << endl;
    toStrm << "STARTING_LINE " << startingLine << endl;
    toStrm << "STARTING_EPHEMERIS_TIME " << setprecision(25) << etStart << endl;
    toStrm << "CENTER_EPHEMERIS_TIME " << etCenter << endl;

} // end main
Ejemplo n.º 17
0
void IsisMain() {

    // Use a regular Process
    Process p;

    UserInterface &ui = Application::GetUserInterface();
    QString from = ui.GetFileName("FROM");
    QString to = FileName(ui.GetFileName("TO")).expanded();
    QString socetProject = ui.GetString("SS_PROJECT");
    QString socetImageLocation = ui.GetString("SS_IMG_LOC");
    QString socetInputDataPath = ui.GetString("SS_INPUT_PATH");
    QString socetCameraCalibrationPath = ui.GetString("SS_CAM_CALIB_PATH");

    // Open input cube and make sure this is a lev1 image (ie, not map projected)
    Cube cube;
    cube.open(from);

    if (cube.isProjected()) {
        QString msg = QString("You can only create a SOCET Set Framing Camera or FrameOffAxis settings "
                              "file for level 1 images. The input image [%1] is a map projected, level "
                              "2, cube.").arg(from);
        throw IException(IException::User, msg, _FILEINFO_);
    }

    // Initialize the camera
    Cube *input = p.SetInputCube("FROM");
    Camera *cam = input->camera();
    CameraDetectorMap *detectorMap = cam->DetectorMap();
    CameraFocalPlaneMap *focalMap = cam->FocalPlaneMap();

    // Make sure the image contains the SPICE blobs/tables
    PvlGroup test = cube.label()->findGroup("Kernels", Pvl::Traverse);
    QString instrumentPointing = (QString) test["InstrumentPointing"];
    if (instrumentPointing != "Table") {
        QString msg = QString("Input image [%1] does not contain needed SPICE blobs.  Please run "
                              "spiceinit on the image with attach=yes.").arg(from);
        throw IException(IException::User, msg, _FILEINFO_);
    }

    // Set the image at the boresight pixel to get the ephemeris time and SPICE data at that image
    // location
    double detectorSampleOrigin = focalMap->DetectorSampleOrigin();
    double detectorLineOrigin = focalMap->DetectorSampleOrigin();
    cam->SetImage(detectorSampleOrigin, detectorLineOrigin);
    double et = cam->time().Et();

    Spice spice(*input);
    spice.setTime(et);

    // Get required keywords from instrument and band groups
    PvlGroup inst = cube.label()->findGroup("Instrument", Pvl::Traverse);
    QString instrumentId = (QString) inst["InstrumentId"];
    QString spacecraftName = (QString) inst["SpacecraftName"];

    // Compensate for noproj altering cube labels
    if (instrumentId == "IdealCamera") {
        PvlGroup orig = cube.label()->findGroup("OriginalInstrument", Pvl::Traverse);
        instrumentId = (QString) orig["InstrumentId"];
        spacecraftName = (QString) orig["SpacecraftName"];
    }

    // Get sensor position and orientation (opk) angles
    double ographicCamPos[3] = {0.0, 0.0, 0.0};
    double omegaPhiKappa[3] = {0.0, 0.0, 0.0};
    double isisFocalPlane2SocetPlateTranspose[3][3] =
    {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
    getCamPosOPK(spice, spacecraftName, et, cam, ographicCamPos,
                 omegaPhiKappa,isisFocalPlane2SocetPlateTranspose);

    // Determine the SOCET Set camera calibration file
    QString socetCamFile = socetCameraCalibrationPath;

    if (spacecraftName == "VIKING_ORBITER_1") {
        if (instrumentId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") {
            socetCamFile += "VIK1A.cam";
        }
        else {
            socetCamFile += "VIK1B.cam";
        }
    }
    else if (spacecraftName == "VIKING_ORBITER_2") {
        if (instrumentId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") {
            socetCamFile += "VIK2A.cam";
        }
        else {
            socetCamFile += "VIK2B.cam";
        }
    }

    //----------------------------------------.-------------
    //TO DO: Uncomment these lines when MEX SRC is supported
    //----------------------------------------.-------------
    //  // Mars Express
    //  else if (spacecraftName == "MARS_EXPRESS") {
    //    socetCamFile += "SRC.cam";
    //  }
    //-----------------------------------------------------
    //TO DO: Uncomment these lines when Themis is supported
    //-----------------------------------------------------
    //  // THEMIS VIS images (MARS Odyssey)
    //  else if (spacecraftName == "MARS_ODYSSEY") {
    //    socetCamFile += "THEMIS_VIS_F3.cam";
    //  }
    //-----------------------------------------------------
    //TO DO: Uncomment these lines when Apollo is supported
    //-----------------------------------------------------
    //  else if (spacecraftName == "APOLLO 15") {
    //    socetCamFile += "Apollo15_M_ASU.cam";
    //  }
    //  else if (spacecraftName == "APOLLO 16") {
    //    socetCamFile += "Apollo16_M_ASU.cam";
    //  }
    //  else if (spacecraftName == "APOLLO 17") {
    //    socetCamFile += "Apollo17_M_ASU.cam";
    //  }
    else if (spacecraftName == "Galileo Orbiter") {
        //Check if this image was aquired with the cover on or off
        iTime removeCoverDate("1994/04/01 00:00:00");
        iTime imageDate((QString) inst["StartTime"]);

        if (imageDate < removeCoverDate) {
            socetCamFile += "Galileo_SSI_Cover.cam";
        }
        else {
            socetCamFile += "Galileo_SSI.cam";
        }
    }
    else if (spacecraftName == "Cassini-Huygens") {
        // Get the image filter and replace "/" with "_"
        PvlGroup bandBin = cube.label()->findGroup("BandBin", Pvl::Traverse);
        QString filter = (QString) bandBin["FilterName"];
        filter.replace("/", "_");

        socetCamFile += "Cassini_ISSNA_";
        socetCamFile += filter;
        socetCamFile += ".cam";
    }
    else if (spacecraftName == "Messenger") {
        if (instrumentId == "MDIS-NAC") {
            socetCamFile += "MDIS_NAC.cam";
        }
        else {
            socetCamFile += "MDIS_WAC.cam";
        }
    }
    else if (spacecraftName == "CLEMENTINE 1") {
        if (instrumentId == "UVVIS") {
            socetCamFile += "ClemUVVIS.cam";
        }
    }

    // Throw exception for unsupported camera
    else {
        QString msg = QString("The ISIS to SOCET Set translation of input image [%1] is currently "
                              "not supported for instrument [%2].").arg(from).arg(instrumentId);
        throw IException(IException::User, msg, _FILEINFO_);
    }

    // For THEMIS VIS, Galileo SSI, Cassini ISS get the image summation mode
    int summation = 1;
    //-----------------------------------------------------
    //TO DO: Uncomment these lines when Themis is supported
    //-----------------------------------------------------
    //  if (spacecraftName == "MARS_ODYSSEY") {
    //    try {
    //      summation = (int) detectorMap->SampleScaleFactor();
    //    }
    //    catch (IException &e) {
    //      QString msg = "Error reading SpatialSumming from Instrument label";
    //      throw IException(IException::User, msg, _FILEINFO_);
    //    }
    //  }

    if (spacecraftName == "Galileo Orbiter") {
        try {
            summation = (int) detectorMap->SampleScaleFactor();
        }
        catch (IException &e) {
            QString msg = "Error reading Summing from Instrument label";
            throw IException(IException::User, msg, _FILEINFO_);
        }
    }

    if (spacecraftName == "Cassini-Huygens") {
        try {
            summation = (int) detectorMap->SampleScaleFactor();
        }
        catch (IException &e) {
            QString msg = "Error reading Summing from Instrument label";
            throw IException(IException::User, msg, _FILEINFO_);
        }
    }

    // Get NL/NS of image and calculate the size in x/y dimensions, in mm
    // Note: for THEMIS VIS, Galileo SSI and Cassini ISS summed images, calculate the size of the full
    // resolution image because our "isis2socet" scripts will enlarge the summed image for import into
    // Socet Set
    double pixelSize = 1.0 / cam->PixelPitch();
    int numLines = cube.lineCount();
    int numSamples = cube.sampleCount();
    if (summation > 1) {
        // For Themis VIS, Galileo SSI, Cassini ISS:
        numLines *= summation;
        numSamples *= summation;
    }
    double sizeX = numSamples / pixelSize;
    double sizeY = numLines / pixelSize;

    // Make sure the Socet Set project name has the .prj extension
    if (socetProject.endsWith(".prj", Qt::CaseInsensitive) == FALSE)  socetProject += ".prj";

    // Find cube base name w/o extensions & establish the Socet Set support file name
    // Note: I'm using the QFileInfo class because the baseName method in the ISIS
    // FileName class only strips the last extension, and we need the core name
    // of the file without any extensions, or path
    QString baseName = QFileInfo(from).baseName();
    QString socetSupFile = baseName + ".sup";

    //  Open and write to the SOCET Set Framing Camera settings file keywords and values
    //  If this is a Messenger image, add the temperature-dependent focal length so as to overrride
    //  the nominal focal lenghth stored in the SOCET Set camera calibration files
    ofstream toStrm;

    toStrm.open (to.toAscii().data(), ios::trunc);
    if (toStrm.bad()) {
        QString msg = "Unable to open output settings file";
        throw IException(IException::User, msg, _FILEINFO_);
    }

    toStrm << "setting_file                        1.1\n";
    toStrm << "multi_frame.project                 " << socetProject << endl;
    toStrm << "multi_frame.cam_calib_filename      " << socetCamFile << endl;
    toStrm << "multi_frame.create_files            IMAGE_AND_SUPPORT\n";
    toStrm << "multi_frame.atmos_ref               0\n";
    toStrm << "multi_frame.auto_min                YES\n";
    toStrm << "multi_frame.digital_cam             NO\n";
    toStrm << "multi_frame.input_image_filename    " << socetInputDataPath + baseName +
           ".raw" << endl;
    toStrm << "multi_frame.output_format           img_type_vitec\n";
    toStrm << "multi_frame.output_name             " << socetSupFile << endl;
    toStrm << "multi_frame.output_location         " << socetImageLocation << endl;
    toStrm << "multi_frame.cam_loc_ang_sys         OPK\n";
    toStrm << "multi_frame.cam_loc_ang_units       UNIT_DEGREES\n";
    toStrm << "multi_frame.cam_loc_xy_units        UNIT_DEGREES\n";

    if (spacecraftName == "Messenger") {
        // Overide the nominal focal length in the SOCET SET camera calibration file with the
        // Temperature Dependent Focal Length used in ISIS
        double focalLength = cam->FocalLength();
        toStrm << "multi_frame.cam_loc_focal           " << setprecision(17) << focalLength
               << endl;
    }
    toStrm << "multi_frame.cam_loc_y_or_lat        " << setprecision(17) <<
           ographicCamPos[0] << endl;
    toStrm << "multi_frame.cam_loc_x_or_lon        " << ographicCamPos[1] << endl;
    toStrm << "multi_frame.cam_loc_elev            " << ographicCamPos[2] << endl;
    toStrm << "multi_frame.cam_loc_omega           " << omegaPhiKappa[0] << endl;
    toStrm << "multi_frame.cam_loc_phi             " << omegaPhiKappa[1] << endl;
    toStrm << "multi_frame.cam_loc_kappa           " << omegaPhiKappa[2] << endl;
    toStrm << "multi_frame.img_size_lines          " << numLines << endl;
    toStrm << "multi_frame.img_size_samps          " << numSamples << endl;
    toStrm << "multi_frame.sizex                   " << setprecision(6) << sizeX << endl;
    toStrm << "multi_frame.sizey                   " << sizeY << endl;
    toStrm << "multi_frame.orientation             1\n";

    // Furthermore, if this is a Messenger image, get the needed keywords values needed for the
    // USGSAstro FrameOffAxis *support* file, and add them to the output settings file.
    // During frame import in SOCET Set, these values will be ignored, but then later accessed by
    // the USGSAstro import_frame SOCET Set program.
    //
    // Note: Summed Messenger images are handled in the FrameOffAxis sensor model, so no need to
    // account for enlarging Messenger images in the "socet2isis" scripts

    if (spacecraftName == "Messenger") {
        double originalHalfLines = numLines / 2.0;
        double originalHalfSamples = numSamples / 2.0;

        // Set the lens distortion coefficients
        // Note: These values were calculated for SOCET Set by Orrin Thomas in an MSExcel spreadsheet,
        // and are hardcoded here
        QString lenscoX;
        QString lenscoY;
        if (instrumentId == "MDIS-WAC") {
            lenscoX = QString("1.0913499678359500E-06 1.0000181809155400E+00 5.2705094712778700E-06 "
                              "7.3086112844249500E-05 -2.1503011755973800E-06 -3.5311655893430800E-08 "
                              "-5.3312743384716000E-06 -1.4642661005550900E-07 -5.4770856997706100E-06 "
                              "-1.2364567692453900E-07 0.0000000000000000E+00 0.0000000000000000E+00 "
                              "0.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00");

            lenscoY = QString("-4.8524316760252900E-08 -5.2704844291112000E-06 1.0000181808487100E+00 "
                              "2.4702140905559800E-09 7.3084305868732200E-05 -2.1478354889239300E-06 "
                              "1.2364567791040000E-07 -5.4663905009059100E-06 1.4516772126792600E-07 "
                              "-5.3419626374895400E-06 0.0000000000000000E+00 0.0000000000000000E+00 "
                              "0.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00");
        }
        else {
            //MDIS-NAC lens distortion coefficients:
            lenscoX = QString("-0.000000000000005 0.997948053760188 0.000000000000000 0.000000000000000 "
                              "0.000542184519158 0.000000000000000 -0.000007008182254 0.000000000000000 "
                              "-0.000006526474815 0.000000000000000 0.000000000000000 0.000000000000000 "
                              "0.000000000000000 0.000000000000000 0.000000000000000");

            lenscoY = QString("-0.000003746900328 0.000000000000000 0.999999575428613 -0.000880501428960 "
                              "0.000000000000000 -0.000332760373453 0.000000000000000 -0.000008067196812 "
                              "0.000000000000000 -0.000007553955548  0.000000000000000  0.000000000000000 "
                              "0.000000000000000  0.000000000000000  0.000000000000000");
        }

        // Get the image summation
        double sampleSumming = (int) detectorMap->SampleScaleFactor();
        double lineSumming = (int) detectorMap->LineScaleFactor();

        // Get the Starting Detector Line/Sample
        double startingSample = detectorMap->AdjustedStartingSample();
        double startingLine = detectorMap->AdjustedStartingLine();

        // Get the image plane corrdinates to pixel coordinates transformation matrices
        const double *iTransS = focalMap->TransS();
        const double *iTransL = focalMap->TransL();

        // Because of the options for applying light-time correction, capture the pertinent
        // ISIS keywords as a record to be stored in the settingsfile
        // Note: these values will not go into the Socet Set support file)
        QString ikCode;
        QString swapObserverTarget;
        QString lightTimeCorrection;
        QString ltSurfaceCorrect;
        PvlObject naifKeywordsObject = cube.label()->findObject("NaifKeywords");
        if (instrumentId == "MDIS-NAC") {
            ikCode = "236820";
            swapObserverTarget = (QString) naifKeywordsObject["INS-236820_SWAP_OBSERVER_TARGET"];
            lightTimeCorrection = (QString) naifKeywordsObject["INS-236820_LIGHTTIME_CORRECTION"];
            ltSurfaceCorrect = (QString) naifKeywordsObject["INS-236820_LT_SURFACE_CORRECT"];
        }
        else {
            ikCode = "236800";
            swapObserverTarget = (QString) naifKeywordsObject["INS-236800_SWAP_OBSERVER_TARGET"];
            lightTimeCorrection = (QString) naifKeywordsObject["INS-236800_LIGHTTIME_CORRECTION"];
            ltSurfaceCorrect = (QString) naifKeywordsObject["INS-236800_LT_SURFACE_CORRECT"];
        }

        toStrm << "\nSENSOR_TYPE FrameOffAxis" << endl;
        toStrm << "USE_LENS_DISTORTION 1" << endl;
        toStrm << "ORIGINAL_HALF_LINES " <<  originalHalfLines << endl;
        toStrm << "ORIGINAL_HALF_SAMPLES " << originalHalfSamples << endl;
        toStrm << "LENSCOX " << lenscoX << endl;
        toStrm << "LENSCOY " << lenscoY << endl;
        toStrm << "SAMPLE_SUMMING  " << sampleSumming << endl;
        toStrm << "LINE_SUMMING  " << lineSumming << endl;
        toStrm << "STARTING_DETECTOR_SAMPLE " << setprecision(17) << startingSample << endl;
        toStrm << "STARTING_DETECTOR_LINE " << startingLine << endl;
        toStrm << "SAMPLE_BORESIGHT " << detectorSampleOrigin << endl;
        toStrm << "LINE_BORESIGHT " << detectorLineOrigin << endl;
        toStrm << "INS_ITRANSS";
        for (int i = 0; i < 3; i++)
            toStrm << " " << setprecision(14) << iTransS[i];
        toStrm << endl;
        toStrm << "INS_ITRANSL";
        for (int i = 0; i < 3; i++)
            toStrm << " " << iTransL[i];
        toStrm << endl;
        toStrm << "M_SOCET2ISIS_FOCALPLANE " << setprecision(2) <<
               isisFocalPlane2SocetPlateTranspose[0][0] << " " <<
               isisFocalPlane2SocetPlateTranspose[0][1] << " " <<
               isisFocalPlane2SocetPlateTranspose[0][2] << endl;
        toStrm << "                         " <<
               isisFocalPlane2SocetPlateTranspose[1][0] << " " <<
               isisFocalPlane2SocetPlateTranspose[1][1] << " " <<
               isisFocalPlane2SocetPlateTranspose[1][2] << endl;
        toStrm << "                         " <<
               isisFocalPlane2SocetPlateTranspose[2][0] << " " <<
               isisFocalPlane2SocetPlateTranspose[2][1] << " " <<
               isisFocalPlane2SocetPlateTranspose[2][2] << endl;
        toStrm << "INS-" << ikCode << "_SWAP_OBSERVER_TARGET = '" << swapObserverTarget << "'\n";
        toStrm << "INS-" << ikCode << "_LIGHTTIME_CORRECTION = '" << lightTimeCorrection << "'\n";
        toStrm << "INS-" << ikCode << "_LT_SURFACE_CORRECT = '" << ltSurfaceCorrect <<"'\n";
    }

} //End IsisMain
Ejemplo n.º 18
0
void IsisMain() {
  const QString caminfo_program  = "caminfo";
  UserInterface &ui = Application::GetUserInterface();

  QList< QPair<QString, QString> > *general = NULL, *camstats = NULL, *statistics = NULL;
  BandGeometry *bandGeom = NULL;

  // Get input filename
  FileName in = ui.GetFileName("FROM");

  // Get the format
  QString sFormat = ui.GetAsString("FORMAT");

  // if true then run spiceinit, xml default is FALSE
  // spiceinit will use system kernels
  if(ui.GetBoolean("SPICE")) {
    QString parameters = "FROM=" + in.expanded();
    ProgramLauncher::RunIsisProgram("spiceinit", parameters);
  }

  Process p;
  Cube *incube = p.SetInputCube("FROM");

  // General data gathering
  general = new QList< QPair<QString, QString> >;
  general->append(MakePair("Program",     caminfo_program));
  general->append(MakePair("IsisVersion", Application::Version()));
  general->append(MakePair("RunDate",     iTime::CurrentGMT()));
  general->append(MakePair("IsisId",      SerialNumber::Compose(*incube)));
  general->append(MakePair("From",        in.baseName() + ".cub"));
  general->append(MakePair("Lines",       toString(incube->lineCount())));
  general->append(MakePair("Samples",     toString(incube->sampleCount())));
  general->append(MakePair("Bands",       toString(incube->bandCount())));

  // Run camstats on the entire image (all bands)
  // another camstats will be run for each band and output
  // for each band.
  if(ui.GetBoolean("CAMSTATS")) {
    camstats = new QList< QPair<QString, QString> >;

    QString filename = ui.GetAsString("FROM");
    int sinc = ui.GetInteger("SINC");
    int linc = ui.GetInteger("LINC");
    CameraStatistics stats(filename, sinc, linc);
    Pvl camPvl = stats.toPvl();

    PvlGroup cg = camPvl.findGroup("Latitude", Pvl::Traverse);
    camstats->append(MakePair("MinimumLatitude", cg["latitudeminimum"][0]));
    camstats->append(MakePair("MaximumLatitude", cg["latitudemaximum"][0]));

    cg = camPvl.findGroup("Longitude", Pvl::Traverse);
    camstats->append(MakePair("MinimumLongitude", cg["longitudeminimum"][0]));
    camstats->append(MakePair("MaximumLongitude", cg["longitudemaximum"][0]));

    cg = camPvl.findGroup("Resolution", Pvl::Traverse);
    camstats->append(MakePair("MinimumResolution", cg["resolutionminimum"][0]));
    camstats->append(MakePair("MaximumResolution", cg["resolutionmaximum"][0]));

    cg = camPvl.findGroup("PhaseAngle", Pvl::Traverse);
    camstats->append(MakePair("MinimumPhase", cg["phaseminimum"][0]));
    camstats->append(MakePair("MaximumPhase", cg["phasemaximum"][0]));

    cg = camPvl.findGroup("EmissionAngle", Pvl::Traverse);
    camstats->append(MakePair("MinimumEmission", cg["emissionminimum"][0]));
    camstats->append(MakePair("MaximumEmission", cg["emissionmaximum"][0]));

    cg = camPvl.findGroup("IncidenceAngle", Pvl::Traverse);
    camstats->append(MakePair("MinimumIncidence", cg["incidenceminimum"][0]));
    camstats->append(MakePair("MaximumIncidence", cg["incidencemaximum"][0]));

    cg = camPvl.findGroup("LocalSolarTime", Pvl::Traverse);
    camstats->append(MakePair("LocalTimeMinimum", cg["localsolartimeMinimum"][0]));
    camstats->append(MakePair("LocalTimeMaximum", cg["localsolartimeMaximum"][0]));
  }

  // Compute statistics for entire cube
  if(ui.GetBoolean("STATISTICS")) {
    statistics = new QList< QPair<QString, QString> >;

    LineManager iline(*incube);
    Statistics stats;
    Progress progress;
    progress.SetText("Statistics...");
    progress.SetMaximumSteps(incube->lineCount()*incube->bandCount());
    progress.CheckStatus();
    iline.SetLine(1);
    for(; !iline.end() ; iline.next()) {
      incube->read(iline);
      stats.AddData(iline.DoubleBuffer(), iline.size());
      progress.CheckStatus();
    }

    //  Compute stats of entire cube
    double nPixels     = stats.TotalPixels();
    double nullpercent = (stats.NullPixels() / (nPixels)) * 100;
    double hispercent  = (stats.HisPixels() / (nPixels)) * 100;
    double hrspercent  = (stats.HrsPixels() / (nPixels)) * 100;
    double lispercent  = (stats.LisPixels() / (nPixels)) * 100;
    double lrspercent  = (stats.LrsPixels() / (nPixels)) * 100;

    // Statitics output for band
    statistics->append(MakePair("MeanValue", toString(stats.Average())));
    statistics->append(MakePair("StandardDeviation", toString(stats.StandardDeviation())));
    statistics->append(MakePair("MinimumValue", toString(stats.Minimum())));
    statistics->append(MakePair("MaximumValue", toString(stats.Maximum())));
    statistics->append(MakePair("PercentHIS", toString(hispercent)));
    statistics->append(MakePair("PercentHRS", toString(hrspercent)));
    statistics->append(MakePair("PercentLIS", toString(lispercent)));
    statistics->append(MakePair("PercentLRS", toString(lrspercent)));
    statistics->append(MakePair("PercentNull", toString(nullpercent)));
    statistics->append(MakePair("TotalPixels", toString(stats.TotalPixels())));
  }

  bool getFootBlob = ui.GetBoolean("USELABEL");
  bool doGeometry = ui.GetBoolean("GEOMETRY");
  bool doPolygon = ui.GetBoolean("POLYGON");
  if(doGeometry || doPolygon || getFootBlob) {
    Camera *cam = incube->camera();

    QString incType = ui.GetString("INCTYPE");
    int polySinc, polyLinc;
    if(doPolygon && incType.toUpper() == "VERTICES") {
      ImagePolygon poly;
      poly.initCube(*incube);
      polySinc = polyLinc = (int)(0.5 + (((poly.validSampleDim() * 2) +
                                 (poly.validLineDim() * 2) - 3.0) /
                                 ui.GetInteger("NUMVERTICES")));
    }
    else if (incType.toUpper() == "LINCSINC"){
      if(ui.WasEntered("POLYSINC")) {
        polySinc = ui.GetInteger("POLYSINC");
      }
      else {
        polySinc = (int)(0.5 + 0.10 * incube->sampleCount());
        if(polySinc == 0) polySinc = 1;
      }
      if(ui.WasEntered("POLYLINC")) {
        polyLinc = ui.GetInteger("POLYLINC");
      }
      else {
        polyLinc = (int)(0.5 + 0.10 * incube->lineCount());
        if(polyLinc == 0) polyLinc = 1;
      }
    }
    else {
      QString msg = "Invalid INCTYPE option[" + incType + "]";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    bandGeom = new BandGeometry();
    bandGeom->setSampleInc(polySinc);
    bandGeom->setLineInc(polyLinc);
    bandGeom->setMaxIncidence(ui.GetDouble("MAXINCIDENCE"));
    bandGeom->setMaxEmission(ui.GetDouble("MAXEMISSION"));
    bool precision = ui.GetBoolean("INCREASEPRECISION");

    if (getFootBlob) {
      // Need to read history to obtain parameters that were used to
      // create the footprint
      History hist("IsisCube", in.expanded());
      Pvl pvl = hist.ReturnHist();
      PvlObject::PvlObjectIterator objIter;
      bool found = false;
      PvlGroup fpgrp;
      for (objIter=pvl.endObject()-1; objIter>=pvl.beginObject(); objIter--) {
        if (objIter->name().toUpper() == "FOOTPRINTINIT") {
          found = true;
          fpgrp = objIter->findGroup("UserParameters");
          break;
        }
      }
      if (!found) {
        QString msg = "Footprint blob was not found in input image history";
        throw IException(IException::User, msg, _FILEINFO_);
      }
      QString prec = (QString)fpgrp.findKeyword("INCREASEPRECISION");
      prec = prec.toUpper();
      if (prec == "TRUE") {
        precision = true;
      }
      else {
        precision = false;
      }
      QString inctype = (QString)fpgrp.findKeyword("INCTYPE");
      inctype = inctype.toUpper();
      if (inctype == "LINCSINC") {
        int linc = fpgrp.findKeyword("LINC");
        int sinc = fpgrp.findKeyword("SINC");
        bandGeom->setSampleInc(sinc);
        bandGeom->setLineInc(linc);
      }
      else {
        int vertices = fpgrp.findKeyword("NUMVERTICES");
        int lincsinc = (int)(0.5 + (((incube->sampleCount() * 2) +
                       (incube->lineCount() * 2) - 3.0) /
                       vertices));
        bandGeom->setSampleInc(lincsinc);
        bandGeom->setLineInc(lincsinc);
      }
      if (fpgrp.hasKeyword("MAXINCIDENCE")) {
        double maxinc = fpgrp.findKeyword("MAXINCIDENCE");
        bandGeom->setMaxIncidence(maxinc);
      }
      if (fpgrp.hasKeyword("MAXEMISSION")) {
        double maxema = fpgrp.findKeyword("MAXEMISSION");
        bandGeom->setMaxEmission(maxema);
      }
    }
    
    bandGeom->collect(*cam, *incube, doGeometry, doPolygon, getFootBlob, precision);

    // Check if the user requires valid image center geometry
    if(ui.GetBoolean("VCAMERA") && (!bandGeom->hasCenterGeometry())) {
      QString msg = "Image center does not project in camera model";
      throw IException(IException::Unknown, msg, _FILEINFO_);
    }
  }

  if(sFormat.toUpper() == "PVL")
    GeneratePVLOutput(incube, general, camstats, statistics, bandGeom);
  else
    GenerateCSVOutput(incube, general, camstats, statistics, bandGeom);

  // Clean the data
  delete general;
  general = NULL;
  if(camstats) {
    delete camstats;
    camstats = NULL;
  }
  if(statistics) {
    delete statistics;
    statistics = NULL;
  }
  if(bandGeom) {
    delete bandGeom;
    bandGeom = NULL;
  }

}
Ejemplo n.º 19
0
 /**
  * @brief Construct from PVL and Cube file
  *
  * @author Kris Becker - 2/21/2010
  *
  * @param pvl Photometric parameter files
  * @param cube Input cube file
  */
 Hillier::Hillier(PvlObject &pvl, Cube &cube) {
   _camera = cube.camera();
   init(pvl, cube);
 }
Ejemplo n.º 20
0
void IsisMain() {
  // We will be processing by line
  ProcessByLine p;

  // Setup the input and make sure it is a mariner10 file
  UserInterface & ui = Application::GetUserInterface();

  Isis::Pvl lab(ui.GetFileName("FROM"));
  Isis::PvlGroup & inst = lab.findGroup("Instrument", Pvl::Traverse);

  QString mission = inst["SpacecraftName"];
  if (mission != "Mariner_10") {
    string msg = "This is not a Mariner 10 image.  Mar10cal requires a Mariner 10 image.";
    throw IException(IException::User, msg, _FILEINFO_);
  }

  Cube * icube = p.SetInputCube("FROM", OneBand);

  // If it is already calibrated then complain
  if (icube->hasGroup("Radiometry")) {
    QString msg = "This Mariner 10 image [" + icube->fileName() + "] has "
                  "already been radiometrically calibrated";
    throw IException(IException::User, msg, _FILEINFO_);
  }

  // Get label parameters we will need for calibration equation
  QString instId = inst["InstrumentId"];
  QString camera = instId.mid(instId.size()-1);

  QString filter = (QString)(icube->group("BandBin"))["FilterName"];
  filter = filter.toUpper().mid(0,3);

  QString target = inst["TargetName"];

  iTime startTime((QString) inst["StartTime"]);

  double exposure = inst["ExposureDuration"];
  double exposureOffset = 0.0;
  if (ui.WasEntered("EXPOFF")) {
    exposureOffset = ui.GetDouble("EXPOFF");
  }
  else {
    if (camera == "A") {
      exposureOffset = 0.316;
    }
    else if (camera == "B") {
      exposureOffset = 3.060;
    }
    else {
      QString msg = "Camera [" + camera + "] is not supported.";
      throw IException(IException::User, msg, _FILEINFO_);
    }
  }
  correctedExp = exposure + exposureOffset;

  Cube * dcCube;
  if (ui.WasEntered ("DCCUBE") ) {
    dcCube = p.SetInputCube("DCCUBE");
  }
  else {
    //  Mercury Dark current
    //   ??? NOTE:  Need to find Mark's dc for venus and moon ????
    QString dcFile("$mariner10/calibration/mariner_10_" + camera +
                  "_dc.cub");
    CubeAttributeInput cubeAtt;
    dcCube = p.SetInputCube(dcFile, cubeAtt);
  }


  //  Open blemish removal file
  Cube * blemCube = 0;
  useBlem = (ui.GetBoolean("BLEMMASK")) ? true : false;
  if (useBlem) {
    QString blemFile("$mariner10/calibration/mariner_10_blem_" + camera + ".cub");
    CubeAttributeInput cubeAtt;
    blemCube = p.SetInputCube(blemFile, cubeAtt);
  }

  if (filter == "FAB" || filter == "WAF") {
    QString msg = "Filter type [" + filter + "] is not supported at this time.";
    throw IException(IException::User, msg, _FILEINFO_);
  }

  if (ui.WasEntered ("COEFCUBE")) {
    coCube.open(ui.GetFileName("COEFCUBE"));
  }
  else {
    FileName coFile("$mariner10/calibration/mariner_10_" + filter + "_" +
        camera + "_coef.cub");
    coCube.open(coFile.expanded());
  }
  coef = new Brick(icube->sampleCount(), 1, 6, coCube.pixelType());

  if (ui.WasEntered("ABSCOEF")) {
    absCoef = ui.GetDouble("ABSCOEF");
  }
  else {
    if (camera == "A") {
      absCoef = 16.0;
    }
    else if (camera == "B") {
      absCoef = 750.0;
    }
    else {
      QString msg = "Camera [" + camera + "] is not supported.";
      throw IException(IException::User, msg, _FILEINFO_);
    }
  }

  mask = ui.GetBoolean("MASK");
  xparm = ui.GetDouble("XPARM");

  // Get the distance between Mars and the Sun at the given time in
  // Astronomical Units (AU)
  Camera * cam = icube->camera();
  bool camSuccess = cam->SetImage(icube->sampleCount()/2,icube->lineCount()/2);
  if (!camSuccess) {
    throw IException(IException::Unknown,
        "Unable to calculate the Solar Distance on [" +
        icube->fileName() + "]", _FILEINFO_);
  }
  sunDist = cam->SolarDistance();

  // Setup the output cube
  Cube  *ocube = p.SetOutputCube("TO");

  // Add the radiometry group
  PvlGroup calgrp("Radiometry");

  calgrp += PvlKeyword("DarkCurrentCube", dcCube->fileName());
  if (useBlem) {
    calgrp += PvlKeyword("BlemishRemovalCube", blemCube->fileName());
  }
  calgrp += PvlKeyword("CoefficientCube", coCube.fileName());
  calgrp += PvlKeyword("AbsoluteCoefficient", toString(absCoef));

  ocube->putGroup(calgrp);

  // Start the line-by-line calibration sequence
  p.StartProcess(Mar10Cal);
  p.EndProcess();
}
Ejemplo n.º 21
0
void IsisMain() {
  UserInterface &ui = Application::GetUserInterface();

  // Get the camera information if this is not a mosaic. Otherwise, get the
  // projection information
  Process p1;
  Cube *icube = p1.SetInputCube("FROM", OneBand);
  if (ui.GetString("SOURCE") == "CAMERA") {
    noCamera = false;
  }
  else {
    noCamera = true;
  }

  if(noCamera) {
    try {
      proj = (TProjection *) icube->projection();
    }
    catch(IException &e) {
      QString msg = "Mosaic files must contain mapping labels";
      throw IException(e, IException::User, msg, _FILEINFO_);
    }
  } 
  else {
    try {
      cam = icube->camera();
    }
    catch(IException &e) {
      QString msg = "If " + FileName(ui.GetFileName("FROM")).name() + " is a mosaic, make sure the SOURCE "
      "option is set to PROJECTION";
      throw IException(e, IException::User, msg, _FILEINFO_);
    }
  }

  // We will be processing by brick.
  ProcessByBrick p;

  // Find out which bands are to be created
  nbands = 0;
  phase = false;
  emission = false;
  incidence = false;
  localEmission = false;
  localIncidence = false;
  lineResolution = false;
  sampleResolution = false;
  detectorResolution = false;
  sunAzimuth = false;
  spacecraftAzimuth = false;
  offnadirAngle = false;
  subSpacecraftGroundAzimuth = false;
  subSolarGroundAzimuth = false;
  morphology = false;
  albedo = false;
  northAzimuth = false;
  if (!noCamera) {
    if((phase = ui.GetBoolean("PHASE"))) nbands++;
    if((emission = ui.GetBoolean("EMISSION"))) nbands++;
    if((incidence = ui.GetBoolean("INCIDENCE"))) nbands++;
    if((localEmission = ui.GetBoolean("LOCALEMISSION"))) nbands++;
    if((localIncidence = ui.GetBoolean("LOCALINCIDENCE"))) nbands++;
    if((lineResolution = ui.GetBoolean("LINERESOLUTION"))) nbands++;
    if((sampleResolution = ui.GetBoolean("SAMPLERESOLUTION"))) nbands++;
    if((detectorResolution = ui.GetBoolean("DETECTORRESOLUTION"))) nbands++;
    if((sunAzimuth = ui.GetBoolean("SUNAZIMUTH"))) nbands++;
    if((spacecraftAzimuth = ui.GetBoolean("SPACECRAFTAZIMUTH"))) nbands++;
    if((offnadirAngle = ui.GetBoolean("OFFNADIRANGLE"))) nbands++;
    if((subSpacecraftGroundAzimuth = ui.GetBoolean("SUBSPACECRAFTGROUNDAZIMUTH"))) nbands++;
    if((subSolarGroundAzimuth = ui.GetBoolean("SUBSOLARGROUNDAZIMUTH"))) nbands++;
    if ((morphology = ui.GetBoolean("MORPHOLOGY"))) nbands++; 
    if ((albedo = ui.GetBoolean("ALBEDO"))) nbands++; 
    if ((northAzimuth = ui.GetBoolean("NORTHAZIMUTH"))) nbands++; 
  }
  if((dn = ui.GetBoolean("DN"))) nbands++;
  if((latitude = ui.GetBoolean("LATITUDE"))) nbands++;
  if((longitude = ui.GetBoolean("LONGITUDE"))) nbands++;
  if((pixelResolution = ui.GetBoolean("PIXELRESOLUTION"))) nbands++;

  if(nbands < 1) {
    QString message = "At least one photometry parameter must be entered"
                     "[PHASE, EMISSION, INCIDENCE, LATITUDE, LONGITUDE...]";
    throw IException(IException::User, message, _FILEINFO_);
  }

  // If outputting a a dn band, retrieve the orignal values for the filter name from the input cube,
  // if it exists.  Otherwise, the default will be "DN"
  QString bname = "DN";
  if ( dn && icube->hasGroup("BandBin") ) {
    PvlGroup &mybb = icube->group("BandBin");
    if ( mybb.hasKeyword("Name") ) {
      bname = mybb["Name"][0];
    }
    else if ( mybb.hasKeyword("FilterName") ) {
      bname = mybb["FilterName"][0];
    }
  }

  // Create a bandbin group for the output label
  PvlKeyword name("Name");
  if (dn) name += bname;
  if(phase) name += "Phase Angle";
  if(emission) name += "Emission Angle";
  if(incidence) name += "Incidence Angle";
  if(localEmission) name += "Local Emission Angle";
  if(localIncidence) name += "Local Incidence Angle";
  if(latitude) name += "Latitude";
  if(longitude) name += "Longitude";
  if(pixelResolution) name += "Pixel Resolution";
  if(lineResolution) name += "Line Resolution";
  if(sampleResolution) name += "Sample Resolution";
  if(detectorResolution) name += "Detector Resolution";
  if(northAzimuth) name += "North Azimuth";
  if(sunAzimuth) name += "Sun Azimuth";
  if(spacecraftAzimuth) name += "Spacecraft Azimuth";
  if(offnadirAngle) name += "OffNadir Angle";
  if(subSpacecraftGroundAzimuth) name += "Sub Spacecraft Ground Azimuth";
  if(subSolarGroundAzimuth) name += "Sub Solar Ground Azimuth";
  if (morphology) name += "Morphology";
  if (albedo) name += "Albedo";


  // Create the output cube.  Note we add the input cube to expedite propagation
  // of input cube elements (label, blobs, etc...).  It will be cleared
  // prior to systematic processing only if the DN option is not selected.
  // If DN is chosen by the user, then we propagate the input buffer with a 
  // different function - one that accepts both input and output buffers.
  (void) p.SetInputCube("FROM", OneBand);
  Cube *ocube = p.SetOutputCube("TO", icube->sampleCount(), 
                                icube->lineCount(), nbands);
  p.SetBrickSize(64, 64, nbands);

  if (dn) {
    // Process with input and output buffers
    p.StartProcess(phocubeDN);
  }
  else {
    // Toss the input file as stated above
    p.ClearInputCubes();

    // Start the processing
    p.StartProcess(phocube);
  }

  // Add the bandbin group to the output label.  If a BandBin group already
  // exists, remove all existing keywords and add the keywords for this app.
  // Otherwise, just put the group in.
  PvlObject &cobj = ocube->label()->findObject("IsisCube");
  if(!cobj.hasGroup("BandBin")) {
    cobj.addGroup(PvlGroup("BandBin"));
  }

  PvlGroup &bb = cobj.findGroup("BandBin");
  bb.addKeyword(name, PvlContainer::Replace);
  int nvals = name.size();
  UpdateBandKey("Center", bb, nvals, "1.0");

  if ( bb.hasKeyword("OriginalBand") ) {
    UpdateBandKey("OriginalBand", bb, nvals, "1.0");
  }

  if ( bb.hasKeyword("Number") ) {
    UpdateBandKey("Number", bb, nvals, "1.0");
  }

  UpdateBandKey("Width", bb, nvals, "1.0");



  p.EndProcess();
}
Ejemplo n.º 22
0
void IsisMain() {
  UserInterface &ui = Application::GetUserInterface();
  Cube cube;
  cube.open(ui.GetFileName("FROM"), "rw");

  // Make sure cube has been run through spiceinit
  try {
    cube.camera();
  }
  catch(IException &e) {
    string msg = "Spiceinit must be run before initializing the polygon";
    throw IException(e, IException::User, msg, _FILEINFO_);
  }

  Progress prog;
  prog.SetMaximumSteps(1);
  prog.CheckStatus();

  QString sn = SerialNumber::Compose(cube);

  ImagePolygon poly;
  if(ui.WasEntered("MAXEMISSION")) {
    poly.Emission(ui.GetDouble("MAXEMISSION"));
  }
  if(ui.WasEntered("MAXINCIDENCE")) {
    poly.Incidence(ui.GetDouble("MAXINCIDENCE"));
  }
  if(ui.GetString("LIMBTEST") == "ELLIPSOID") {
    poly.EllipsoidLimb(true);
  }

  int sinc = 1;
  int linc = 1;
  IString incType = ui.GetString("INCTYPE");
  if(incType.UpCase() == "VERTICES") {
    poly.initCube(cube);
    sinc = linc = (int)(0.5 + (((poly.validSampleDim() * 2) +
                       (poly.validLineDim() * 2) - 3.0) /
                       ui.GetInteger("NUMVERTICES")));
    if (sinc < 1.0 || linc < 1.0)
      sinc = linc = 1.0;
  }
  else if (incType.UpCase() == "LINCSINC"){
    sinc = ui.GetInteger("SINC");
    linc = ui.GetInteger("LINC");
  }
  else {
    string msg = "Invalid INCTYPE option[" + incType + "]";
    throw IException(IException::Programmer, msg, _FILEINFO_);
  }

  bool precision = ui.GetBoolean("INCREASEPRECISION");
  try {
    poly.Create(cube, sinc, linc, 1, 1, 0, 0, 1, precision);
  }
  catch (IException &e) {
    QString msg = "Cannot generate polygon for [" + ui.GetFileName("FROM") + "]";
    throw IException(e, IException::User, msg, _FILEINFO_);
  }

  if(ui.GetBoolean("TESTXY")) {
    Pvl cubeLab(ui.GetFileName("FROM"));
    PvlGroup inst = cubeLab.findGroup("Instrument", Pvl::Traverse);
    QString target = inst["TargetName"];
    PvlGroup radii = Projection::TargetRadii(target);

    Pvl map(ui.GetFileName("MAP"));
    PvlGroup &mapping = map.findGroup("MAPPING");

    if(!mapping.hasKeyword("TargetName"))
      mapping += Isis::PvlKeyword("TargetName", target);
    if(!mapping.hasKeyword("EquatorialRadius"))
      mapping += Isis::PvlKeyword("EquatorialRadius", (QString)radii["EquatorialRadius"]);
    if(!mapping.hasKeyword("PolarRadius"))
      mapping += Isis::PvlKeyword("PolarRadius", (QString)radii["PolarRadius"]);
    if(!mapping.hasKeyword("LatitudeType"))
      mapping += Isis::PvlKeyword("LatitudeType", "Planetocentric");
    if(!mapping.hasKeyword("LongitudeDirection"))
      mapping += Isis::PvlKeyword("LongitudeDirection", "PositiveEast");
    if(!mapping.hasKeyword("LongitudeDomain"))
      mapping += Isis::PvlKeyword("LongitudeDomain", "360");
    if(!mapping.hasKeyword("CenterLatitude"))
      mapping += Isis::PvlKeyword("CenterLatitude", "0");
    if(!mapping.hasKeyword("CenterLongitude"))
      mapping += Isis::PvlKeyword("CenterLongitude", "0");

    sinc = poly.getSinc();
    linc = poly.getLinc();
    bool polygonGenerated = false;
    while (!polygonGenerated) {
      Projection *proj = NULL;
      geos::geom::MultiPolygon *xyPoly = NULL;

      try {
        proj = ProjectionFactory::Create(map, true);
        xyPoly = PolygonTools::LatLonToXY(*poly.Polys(), proj);

        polygonGenerated = true;
      }
      catch (IException &e) {
        if (precision && sinc > 1 && linc > 1) {
          sinc = sinc * 2 / 3;
          linc = linc * 2 / 3;
          poly.Create(cube, sinc, linc);
        }
        else {
          delete proj;
          delete xyPoly;
          e.print(); // This should be a NAIF error
          QString msg = "Cannot calculate XY for [";
          msg += ui.GetFileName("FROM") + "]";
          throw IException(e, IException::User, msg, _FILEINFO_);
        }
      }

      delete proj;
      delete xyPoly;
    }
  }

  cube.deleteBlob("Polygon", sn);
  cube.write(poly);

  if(precision) {
    PvlGroup results("Results");
    results.addKeyword(PvlKeyword("SINC", toString(sinc)));
    results.addKeyword(PvlKeyword("LINC", toString(linc)));
    Application::Log(results);
  }

  Process p;
  p.SetInputCube("FROM");
  p.WriteHistory(cube);

  cube.close();
  prog.CheckStatus();
}
Ejemplo n.º 23
0
void IsisMain() {

  UserInterface &ui = Application::GetUserInterface();

  FileList addList(ui.GetFileName("ADDLIST"));

  bool log = false;
  FileName logFile;
  if (ui.WasEntered("LOG")) {
    log = true;
    logFile = ui.GetFileName("LOG");
  }
  Pvl results;
  results.setName("cnetadd_Results");
  PvlKeyword added("FilesAdded");
  PvlKeyword omitted("FilesOmitted");
  PvlKeyword pointsModified("PointsModified");

  bool checkMeasureValidity = ui.WasEntered("DEFFILE");
  ControlNetValidMeasure validator;
  if (checkMeasureValidity) {
    Pvl deffile(ui.GetFileName("DEFFILE"));
    validator = ControlNetValidMeasure(deffile);
  }

  SerialNumberList *fromSerials = ui.WasEntered("FROMLIST") ?
    new SerialNumberList(ui.GetFileName("FROMLIST")) : new SerialNumberList();

  ControlNet inNet = ControlNet(ui.GetFileName("CNET"));
  inNet.SetUserName(Application::UserName());
  inNet.SetModifiedDate(iTime::CurrentLocalTime()); //This should be done in ControlNet's Write fn

  QString retrievalOpt = ui.GetString("RETRIEVAL");
  PvlKeyword duplicates("DupSerialNumbers");
  if (retrievalOpt == "REFERENCE") {
    FileList list1(ui.GetFileName("FROMLIST"));
    SerialNumberList addSerials(ui.GetFileName("ADDLIST"));

    //Check for duplicate files in the lists by serial number
    for (int i = 0; i < addSerials.Size(); i++) {

      // Check for duplicate SNs accross the lists
      if (fromSerials->HasSerialNumber(addSerials.SerialNumber(i))) {
        duplicates.addValue(addSerials.FileName(i));
      }

      // Check for duplicate SNs within the addlist
      for (int j = i + 1; j < addSerials.Size(); j++) {
        if (addSerials.SerialNumber(i) == addSerials.SerialNumber(j)) {
          QString msg = "Add list files [" + addSerials.FileName(i) + "] and [";
          msg += addSerials.FileName(j) + "] share the same serial number.";
          throw IException(IException::User, msg, _FILEINFO_);
        }
      }
    }

    // Get the lat/long coords from the existing reference measure
    setControlPointLatLon(*fromSerials, inNet);
  }
  else {
    for (int cp = 0; cp < inNet.GetNumPoints(); cp++) {
      // Get the surface point from the current control point
      ControlPoint *point = inNet.GetPoint(cp);
      SurfacePoint surfacePoint = point->GetBestSurfacePoint();

      if (!surfacePoint.Valid()) {
        QString msg = "Unable to retreive lat/lon from Control Point [";
        msg += point->GetId() + "]. RETREIVAL=POINT cannot be used unless ";
        msg += "all Control Points have Latitude/Longitude keywords.";
        throw IException(IException::User, msg, _FILEINFO_);
      }

      g_surfacePoints[point->GetId()] = surfacePoint;
    }
  }

  FileName outNetFile(ui.GetFileName("ONET"));

  Progress progress;
  progress.SetText("Adding Images");
  progress.SetMaximumSteps(addList.size());
  progress.CheckStatus();

  STRtree coordTree;
  QList<ControlPoint *> pointList;
  bool usePolygon = ui.GetBoolean("POLYGON");
  if (usePolygon) {
    for (int cp = 0; cp < inNet.GetNumPoints(); cp++) {
      ControlPoint *point = inNet.GetPoint(cp);
      SurfacePoint surfacePoint = g_surfacePoints[point->GetId()];

      Longitude lon = surfacePoint.GetLongitude();
      Latitude lat = surfacePoint.GetLatitude();

      Coordinate *coord = new Coordinate(lon.degrees(), lat.degrees());
      Envelope *envelope = new Envelope(*coord);
      coordTree.insert(envelope, point);
    }
  }
  else {
    for (int cp = 0; cp < inNet.GetNumPoints(); cp++) {
      pointList.append(inNet.GetPoint(cp));
    }
  }

  // Loop through all the images
  for (int img = 0; img < addList.size(); img++) {
    Cube cube;
    cube.open(addList[img].toString());
    Pvl *cubepvl = cube.label();
    QString sn = SerialNumber::Compose(*cubepvl);
    Camera *cam = cube.camera();

    // Loop through all the control points
    QList<ControlPoint *> validPoints = usePolygon ?
        getValidPoints(cube, coordTree) : pointList;

    bool imageAdded = false;
    for (int cp = 0; cp < validPoints.size(); cp++) {
      ControlPoint *point = validPoints[cp];

      // If the point is locked and Apriori source is "AverageOfMeasures"
      // then do not add the measures.
      if (point->IsEditLocked() &&
          point->GetAprioriSurfacePointSource() ==
              ControlPoint::SurfacePointSource::AverageOfMeasures) {
        continue;
      }

      if (point->HasSerialNumber(sn)) continue;

      // Only use the surface point's latitude and longitude, rely on the DEM
      // for computing the radius.  We do this because otherwise we will receive
      // inconsistent results from successive runs of this program if the
      // different DEMs are used, or the point X, Y, Z was generated from the
      // ellipsoid.
      SurfacePoint surfacePoint = g_surfacePoints[point->GetId()];
      if (cam->SetGround(
              surfacePoint.GetLatitude(), surfacePoint.GetLongitude())) {

        // Make sure the samp & line are inside the image
        if (cam->InCube()) {
          ControlMeasure *newCm = new ControlMeasure();
          newCm->SetCoordinate(cam->Sample(), cam->Line(), ControlMeasure::Candidate);
          newCm->SetAprioriSample(cam->Sample());
          newCm->SetAprioriLine(cam->Line());
          newCm->SetCubeSerialNumber(sn);
          newCm->SetDateTime();
          newCm->SetChooserName("Application cnetadd");

          // Check the measure for DEFFILE validity
          if (checkMeasureValidity) {
            if (!validator.ValidEmissionAngle(cam->EmissionAngle())) {
              //TODO: log that it was Emission Angle that failed the check
              newCm->SetIgnored(true);
            }
            else if (!validator.ValidIncidenceAngle(cam->IncidenceAngle())) {
              //TODO: log that it was Incidence Angle that failed the check
              newCm->SetIgnored(true);
            }
            else if (!validator.ValidResolution(cam->resolution())) {
              //TODO: log that it was Resolution that failed the check
              newCm->SetIgnored(true);
            }
            else if (!validator.PixelsFromEdge((int)cam->Sample(), (int)cam->Line(), &cube)) {
              //TODO: log that it was Pixels from Edge that failed the check
              newCm->SetIgnored(true);
            }
            else {
              Portal portal(1, 1, cube.pixelType());
              portal.SetPosition(cam->Sample(), cam->Line(), 1);
              cube.read(portal);
              if (!validator.ValidDnValue(portal[0])) {
                //TODO: log that it was DN that failed the check
                newCm->SetIgnored(true);
              }
            }
          }

          point->Add(newCm); // Point takes ownership

          // Record the modified Point and Measure
          g_modifications[point->GetId()].insert(newCm->GetCubeSerialNumber());
          newCm = NULL; // Do not delete because the point has ownership

          if (retrievalOpt == "POINT" && point->GetNumMeasures() == 1)
            point->SetIgnored(false);

          imageAdded = true;
        }
      }
    }

    cubepvl = NULL;
    cam = NULL;

    if (log) {
      PvlKeyword &logKeyword = (imageAdded) ? added : omitted;
      logKeyword.addValue(addList[img].baseName());
    }

    progress.CheckStatus();
  }

  if (log) {
    // Add the list of modified points to the output log file
    QList<QString> modifiedPointsList = g_modifications.keys();
    for (int i = 0; i < modifiedPointsList.size(); i++)
      pointsModified += modifiedPointsList[i];

    results.addKeyword(added);
    results.addKeyword(omitted);
    results.addKeyword(pointsModified);
    if (duplicates.size() > 0) {
      results.addKeyword(duplicates);
    }

    results.write(logFile.expanded());
  }

  // List the modified points
  if (ui.WasEntered("MODIFIEDPOINTS")) {
    FileName pointList(ui.GetFileName("MODIFIEDPOINTS"));

    // Set up the output file for writing
    std::ofstream out_stream;
    out_stream.open(pointList.expanded().toAscii().data(), std::ios::out);
    out_stream.seekp(0, std::ios::beg);   //Start writing from beginning of file

    QList<QString> modifiedPointsList = g_modifications.keys();
    for (int i = 0; i < modifiedPointsList.size(); i++)
      out_stream << modifiedPointsList[i].toStdString() << std::endl;

    out_stream.close();
  }

  // Modify the inNet to only have modified points/measures
  if (ui.GetString("EXTRACT") == "MODIFIED") {
    for (int cp = inNet.GetNumPoints() - 1; cp >= 0; cp--) {
      ControlPoint *point = inNet.GetPoint(cp);

      // If the point was not modified, delete
      // Even get rid of edit locked points in this case
      if (!g_modifications.contains(point->GetId())) {
        point->SetEditLock(false);
        inNet.DeletePoint(cp);
      }
      // Else, remove the unwanted measures from the modified point
      else {
        for (int cm = point->GetNumMeasures() - 1; cm >= 0; cm--) {
          ControlMeasure *measure = point->GetMeasure(cm);

          // Even get rid of edit locked measures in this case
          if (point->GetRefMeasure() != measure &&
              !g_modifications[point->GetId()].contains(
                  measure->GetCubeSerialNumber())) {
            measure->SetEditLock(false);
            point->Delete(cm);
          }
        }
      }
    }
  }

  // Generate the TOLIST if wanted
  if (ui.WasEntered("TOLIST")) {
    SerialNumberList toList;

    SerialNumberList addSerials(ui.GetFileName("ADDLIST"));

    const QList<QString> snList = inNet.GetCubeSerials();
    for (int i = 0; i < snList.size(); i++) {
      QString sn = snList[i];

      if (addSerials.HasSerialNumber(sn))
        toList.Add(addSerials.FileName(sn));
      else if (fromSerials->HasSerialNumber(sn))
        toList.Add(fromSerials->FileName(sn));
    }

    IString name(ui.GetFileName("TOLIST"));
    std::fstream out_stream;
    out_stream.open(name.c_str(), std::ios::out);
    out_stream.seekp(0, std::ios::beg); //Start writing from beginning of file

    for (int f = 0; f < (int) toList.Size(); f++)
      out_stream << toList.FileName(f) << std::endl;

    out_stream.close();
  }

  inNet.Write(outNetFile.expanded());

  delete fromSerials;
}
Ejemplo n.º 24
0
int main() {
  Preference::Preferences(true);
  QString inputFile = "$mgs/testData/ab102401.cub";
  Cube cube;
  cube.open(inputFile);
  Camera *c = cube.camera();
  std::vector<Distance> radii = c->target()->radii();
  Pvl &pvl = *cube.label();
  Spice spi(cube);
  Target targ(&spi, pvl);
  targ.setRadii(radii);

  cout << "Begin testing Ellipsoid Shape Model class...." << endl;

  cout << endl << "  Testing constructors..."  << endl;
  EllipsoidShape shape(&targ, pvl);
  EllipsoidShape shape2(&targ);
  EllipsoidShape shape3;

  cout << "    Shape1  name is " << shape.name() << endl;
  cout << "    Shape2  name is " << shape2.name() << endl;
  cout << "    Shape3  name is " << shape3.name() << endl;

  std::vector<double> sB(3);
  sB[0] = -2399.54;
  sB[1] = -2374.03;
  sB[2] = 1277.68;
  std::vector<double> lookB(3, 1.);
  lookB[0] = -1.;
  cout << endl << "  Testing method intersectSurface with failure..." << endl; 
  cout << "    Do we have an intersection? " << shape.hasIntersection() << endl;
  shape.intersectSurface(sB, lookB);
  if (!shape.hasIntersection()) cout << "    Intersection failed " << endl;

  cout << endl << "Testing method intersectSurface..." << endl; 
  cout << "    Do we have an intersection? " << shape.hasIntersection() << endl;
  cout << "   Set a pixel in the image and check again." << endl;
  double line = 453.0;
  double sample = 534.0;
  c->SetImage(sample, line);
  c->instrumentPosition((double *) &sB[0]);
  std::vector<double> uB(3);
  c->sunPosition((double *) &uB[0]);
  c->SpacecraftSurfaceVector((double *) &lookB[0]);
  /*
Sample/Line = 534/453
surface normal = -0.623384, -0.698838, 0.350738
Local normal = -0.581842, -0.703663, 0.407823
  Phase                      = 40.787328112158
  Incidence                  = 85.341094499768
  Emission                   = 46.966269013795
  */
  if (!shape.intersectSurface(sB, lookB)) { 
      cout << "    ...  intersectSurface method failed" << endl;
      return -1;
  }
  cout << "    Do we have an intersection? " << shape.hasIntersection() << endl;
  SurfacePoint *sp = shape.surfaceIntersection();
  cout << "     surface point = (" << sp->GetX().kilometers() << ", " << 
    sp->GetY().kilometers() << ", " << sp->GetZ().kilometers() << endl;

  cout << endl << "  Testing class method calculateLocalNormal..." << endl;
  QVector<double *>  notUsed(4);

  for (int i = 0; i < notUsed.size(); i ++)
      notUsed[i] = new double[3];

  shape.calculateLocalNormal(notUsed);
  vector<double> myNormal(3);
  myNormal = shape.normal();
  cout << "    local normal = (" << myNormal[0] << ", " << myNormal[1] << ", " << myNormal[2] << endl;

  cout << endl << "  Testing class method calculateSurfaceNormal..." << endl;
  shape.calculateSurfaceNormal(); 
  myNormal = shape.normal();
  cout << "    surface normal = (" << myNormal[0] << ", " << myNormal[1] << ", " << myNormal[2] << endl;

  cout << endl << "  Testing class method calculateDefaultNormal..." << endl;
  shape.calculateDefaultNormal();
  myNormal = shape.normal();
  cout << "    default normal = (" << myNormal[0] << ", " << myNormal[1] << ", " << myNormal[2] << endl;

  cout << endl << "  Testing localRadius method ..." << endl;
  cout  << "    Local radius = " << shape.localRadius(Latitude(20.532461495381, Angle::Degrees),
                                                  Longitude(228.26609149754, Angle::Degrees)).kilometers() << endl;
  // Mars radii = 3397.      3397.         3375.

  cout << endl << "  Testing setHasIntersection method" << endl;
  shape.setHasIntersection(false);
  cout << "    Do we have an intersection? " << shape.hasIntersection() << endl;

  cout << endl << "  Testing setSurfacePoint method ..." << endl;
  shape.setSurfacePoint(*sp);
  cout << "     Do we have an intersection? " << shape.hasIntersection() << endl;
  cout << "     surface point = (" << sp->GetX().kilometers() << ", " << 
    sp->GetY().kilometers() << ", " << sp->GetZ().kilometers() << endl;

  cube.close();
}