/** * Checks if this latitude value is within the given range. Defines the * range as the change from the minimum latitude to the maximum latitude (an * angle), and returns whether the change from the minimum latitude to this * latitude is less than or equal to the maximum change allowed (the range). * * @param min The beginning of the valid latitude range * @param max The end of the valid latitude range * * @return Whether the latitude is in the given range */ bool Latitude::inRange(Latitude min, Latitude max) const { // Validity check on the range if (min > max) { IString msg = "Minimum latitude [" + IString(min.degrees()) + "] degrees is greater than maximum latitude [" + IString(max.degrees()) + "] degrees"; throw IException(IException::User, msg, _FILEINFO_); } // Provide a little wriggle room for precision problems Angle epsilon(DBL_EPSILON, Angle::Degrees); Latitude adjustedMin = min - epsilon; Latitude adjustedMax = max + epsilon; // Is this latitude between the min and the max return *this >= adjustedMin && *this <= adjustedMax; }
// Compute the radius at the lat/lon Distance GetRadius(QString filename, Latitude lat, Longitude lon) { Cube cube(filename, "r"); Sensor sensor(cube); sensor.SetGround(SurfacePoint(lat, lon, sensor.LocalRadius(lat, lon))); Distance radius = sensor.LocalRadius(); if(!radius.isValid()) { QString msg = "Could not determine radius from DEM at lat/lon ["; msg += toString(lat.degrees()) + "," + toString(lon.degrees()) + "]"; throw IException(IException::Unknown, msg, _FILEINFO_); } return radius; }
/** * Returns whether the lat/lon position was set successfully in the camera * model or projection. * * @param lat The universal latitude or ring radius for ring planes * @param lon The universal longitude or ring longitude (azimuth) for ring planes * * @return Returns true if the lat/lon position was set successfully, and * false if it was not */ bool UniversalGroundMap::SetGround(Latitude lat, Longitude lon) { if(p_camera != NULL) { if(p_camera->SetGround(lat, lon)) { // This should work for rings (radius,azimuth) return p_camera->InCube(); } else { return false; } } else { double universalLat = lat.degrees(); double universalLon = lon.degrees(); return p_projection->SetUniversalGround(universalLat, universalLon); // This should work for rings (radius,azimuth) } }
/** Compute undistorted focal plane coordinate from ground position * * @param lat Planetocentric latitude in degrees * @param lon Planetocentric longitude in degrees * * @return @b bool Indicates whether the conversion was successful * * @internal * @history 2007-04-18 Tracie Sucharski - Added check for reasonable * match when attempting to find closest * lat/lon in map arrays. * @history 2007-09-14 Tracie Sucharski - Added check for longitude * outside min/max bounds. Don't know why * this wasn't put in before (lat check was * in), was it oversight, or did I take it out * for some reason??? * @history 2007-12-14 Tracie Sucharski - Remove resolution test, too * image dependent and the resolution for vims is * incorrect due to the instrument having * rectangular pixels. * @history 2008-01-02 Tracie Sucharski - Check validity of resulting * sample and line against edge of starting * ending pixels (0.5/Parent+0.5) instead of * center of pixels. * @history 2012-12-03 Tracie Sucharski - Check for valid minLat/maxLat, minLon/maxLon. If * none are valid, this means the latMap and lonMap have no valid * data, therefore we cannot back project, so return false. * */ bool VimsGroundMap::SetGround(const Latitude &lat, const Longitude &lon) { QVector3D xyz; if (p_camera->target()->shape()->name() == "Plane") { double radius = lat.degrees(); if(radius <= 0.0) return false; double xCheck = radius * 0.001 * cos(lon.radians()); double yCheck = radius * 0.001 * sin(lon.radians()); xyz.setX(xCheck); xyz.setY(yCheck); xyz.setZ(0.); } else { // Convert lat/lon to x/y/z Distance radius = p_camera->LocalRadius(lat, lon); SpiceDouble pB[3]; latrec_c(radius.kilometers(), lon.radians(), lat.radians(), pB); xyz.setX(pB[0]); xyz.setY(pB[1]); xyz.setZ(pB[2]); } double minDist = DBL_MAX; int minSamp = -1; int minLine = -1; // Find closest points ??? what tolerance ??? for (int line = 0; line < p_camera->ParentLines(); line++) { for (int samp = 0; samp < p_camera->ParentSamples(); samp++) { if (p_xyzMap[line][samp].isNull()) continue; // Subtract map from coordinate then get length QVector3D deltaXyz = xyz - p_xyzMap[line][samp]; if (deltaXyz.length() < minDist) { minDist = deltaXyz.length(); minSamp = samp; minLine = line; } } } //----------------------------------------------------------------- // If dist is less than some ??? tolerance ??? this is the // closest point. Use this point and surrounding 8 pts as // control pts. //---------------------------------------------------------------- if (minDist >= DBL_MAX) return false; //------------------------------------------------------------- // Set-up for LU decomposition (least2 fit). // Assume we will have 9 control points, this may not be true // and will need to be adjusted before the final solution. //------------------------------------------------------------- BasisFunction sampXyzBasis("Sample", 4, 4); BasisFunction lineXyzBasis("Line", 4, 4); LeastSquares sampXyzLsq(sampXyzBasis); LeastSquares lineXyzLsq(lineXyzBasis); vector<double> knownXyz(4); // Solve using x/y/z for (int line = minLine - 1; line < minLine + 2; line++) { if (line < 0 || line > p_camera->ParentLines() - 1) continue; for (int samp = minSamp - 1; samp < minSamp + 2; samp++) { // Check for edges if (samp < 0 || samp > p_camera->ParentSamples() - 1) continue; if (p_xyzMap[line][samp].isNull()) continue; knownXyz[0] = p_xyzMap[line][samp].x(); knownXyz[1] = p_xyzMap[line][samp].y(); knownXyz[2] = p_xyzMap[line][samp].z(); knownXyz[3] = 1; sampXyzLsq.AddKnown(knownXyz, samp + 1); lineXyzLsq.AddKnown(knownXyz, line + 1); } } if (sampXyzLsq.Knowns() < 4) return false; sampXyzLsq.Solve(); lineXyzLsq.Solve(); // Solve for sample, line position corresponding to input lat, lon knownXyz[0] = xyz.x(); knownXyz[1] = xyz.y(); knownXyz[2] = xyz.z(); knownXyz[3] = 1; double inSamp = sampXyzLsq.Evaluate(knownXyz); double inLine = lineXyzLsq.Evaluate(knownXyz); if (inSamp < 0.5 || inSamp > p_camera->ParentSamples() + 0.5 || inLine < 0.5 || inLine > p_camera->ParentLines() + 0.5) { return false; } p_camera->IgnoreProjection(true); p_camera->SetImage(inSamp, inLine); p_camera->IgnoreProjection(false); if (!p_camera->HasSurfaceIntersection()) return false; p_focalPlaneX = inSamp; p_focalPlaneY = inLine; return true; }
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; }