120 IString msg =
"Projection failed. No target radii are available "
121 "through keywords [EquatorialRadius and PolarRadius] "
128 IString msg =
"Projection failed. Invalid value for keyword "
129 "[EquatorialRadius]. It must be greater than zero";
133 IString msg =
"Projection failed. Invalid value for keyword "
134 "[PolarRadius]. It must be greater than zero";
139 if ((QString)
m_mappingGrp[
"LatitudeType"] ==
"Planetographic") {
142 else if ((QString)
m_mappingGrp[
"LatitudeType"] ==
"Planetocentric") {
146 IString msg =
"Projection failed. Invalid value for keyword "
147 "[LatitudeType] must be "
148 "[Planetographic or Planetocentric]";
153 if ((QString)
m_mappingGrp[
"LongitudeDirection"] ==
"PositiveWest") {
156 else if ((QString)
m_mappingGrp[
"LongitudeDirection"] ==
"PositiveEast") {
160 IString msg =
"Projection failed. Invalid value for keyword "
161 "[LongitudeDirection] must be "
162 "[PositiveWest or PositiveEast]";
167 if ((QString)
m_mappingGrp[
"LongitudeDomain"] ==
"360") {
170 else if ((QString)
m_mappingGrp[
"LongitudeDomain"] ==
"180") {
174 IString msg =
"Projection failed. Invalid value for keyword "
175 "[LongitudeDomain] must be [180 or 360]";
191 IString msg =
"Projection failed. "
193 +
"] is outside the range of [-90:90]";
198 IString msg =
"Projection failed. "
200 +
"] is outside the range of [-90:90]";
205 IString msg =
"Projection failed. "
206 "[MinimumLatitude,MaximumLatitude] of ["
209 +
"properly ordered";
214 IString msg =
"Projection failed. "
215 "[MinimumLongitude,MaximumLongitude] of ["
218 +
"properly ordered";
234 IString msg =
"Projection failed. Invalid keyword value(s). "
236 +
" must be greater than or equal to [PolarRadius] = "
255 IString msg =
"Projection failed. Invalid label group [Mapping]";
275 if (!Projection::operator==(proj))
return false;
341 if (latitude ==
Null) {
343 "Unable to calculate local radius. The given latitude value ["
344 +
IString(latitude) +
"] is invalid.",
350 if (a - c < DBL_EPSILON) {
354 double lat = latitude *
PI / 180.0;
355 return a * c / sqrt(pow(c * cos(lat), 2) + pow(a * sin(lat), 2));
389 if (!cachedResults.contains(target)) {
393 bodn2c_c(target.toAscii().data(), &code, &found);
395 QString msg =
"Could not convert target name [" + target +
"] to NAIF code";
400 FileName kern(
"$Base/kernels/pck/pck?????.tpc");
401 kern = kern.highestVersion();
402 QString kernName(kern.expanded());
403 furnsh_c(kernName.toAscii().data());
408 SpiceDouble radii[3];
409 bodvar_c(code,
"RADII", &n, radii);
410 unload_c(kernName.toAscii().data());
413 NaifStatus::CheckErrors();
418 QObject::tr(
"The target name [%1] does not correspond to a target body "
419 "with known radii").arg(target),
426 cachedResults[target] = mapping;
429 mapping = cachedResults[target];
467 QString target = inst[
"TargetName"];
471 radii.
findKeyword(
"EquatorialRadius")[0],
"meters");
555 double eRadius,
double pRadius) {
556 if (lat ==
Null || abs(lat) > 90.0) {
558 "Unable to convert to Planetocentric. The given latitude value ["
559 +
IString(lat) +
"] is invalid.",
563 if (abs(mylat) < 90.0) {
565 mylat = atan(tan(mylat) * (pRadius / eRadius) *
566 (pRadius / eRadius));
601 double eRadius,
double pRadius) {
603 if (qFuzzyCompare(fabs(lat), 90.0)) {
606 if (lat ==
Null || fabs(lat) > 90.0) {
608 "Unable to convert to Planetographic. The given latitude value ["
609 +
IString(lat) +
"] is invalid.",
613 if (fabs(mylat) < 90.0) {
615 mylat = atan(tan(mylat) * (eRadius / pRadius) *
616 (eRadius / pRadius));
630 return "Planetocentric";
671 "Unable to convert to PositiveEast. The given longitude value ["
672 +
IString(lon) +
"] is invalid.",
682 else if (domain == 180) {
686 IString msg =
"Unable to convert longitude. Domain [" +
IString(domain)
687 +
"] is not 180 or 360.";
710 "Unable to convert to PositiveWest. The given longitude value ["
711 +
IString(lon) +
"] is invalid.",
721 else if (domain == 180) {
725 IString msg =
"Unable to convert longitude. Domain [" +
IString(domain)
726 +
"] is not 180 or 360.";
742 return "PositiveWest";
780 "Unable to convert to 180 degree domain. The given longitude value ["
781 +
IString(lon) +
"] is invalid.",
798 "Unable to convert to 360 degree domain. The given longitude value ["
799 +
IString(lon) +
"] is invalid.",
804 if ( (lon < 0.0 || lon > 360.0) &&
805 !qFuzzyCompare(lon, 0.0) && !qFuzzyCompare(lon, 360.0)) {
1032 sqrt(a * a + b * b);
1080 double &minY,
double &maxY) {
1132 if (latitude ==
Null || longitude ==
Null) {
1169 double &minY,
double &maxY) {
1181 double minFoundX1, minFoundX2;
1182 double minFoundY1, minFoundY2;
1198 double minFoundX3, minFoundX4;
1199 double minFoundY3, minFoundY4;
1215 double minFoundX5 = min(minFoundX1, minFoundX2);
1216 double minFoundX6 = min(minFoundX3, minFoundX4);
1219 double minFoundY5 = min(minFoundY1, minFoundY2);
1220 double minFoundY6 = min(minFoundY3, minFoundY4);
1224 double maxFoundX1, maxFoundX2;
1225 double maxFoundY1, maxFoundY2;
1241 double maxFoundX3, maxFoundX4;
1242 double maxFoundY3, maxFoundY4;
1258 double maxFoundX5 = max(maxFoundX1, maxFoundX2);
1259 double maxFoundX6 = max(maxFoundX3, maxFoundX4);
1262 double maxFoundY5 = max(maxFoundY1, maxFoundY2);
1263 double maxFoundY6 = max(maxFoundY3, maxFoundY4);
1268 for (
unsigned int specialLatCase = 0;
1269 specialLatCase < specialLatCases.size();
1270 specialLatCase ++) {
1271 double minX, maxX, minY, maxY;
1275 minX, specialLatCases[specialLatCase],
true,
false,
true);
1278 minY, specialLatCases[specialLatCase],
false,
false,
true);
1281 maxX, specialLatCases[specialLatCase],
true,
false,
false);
1284 maxY, specialLatCases[specialLatCase],
false,
false,
false);
1293 for (
unsigned int specialLonCase = 0;
1294 specialLonCase < specialLonCases.size();
1295 specialLonCase ++) {
1296 double minX, maxX, minY, maxY;
1300 minX, specialLonCases[specialLonCase],
true,
true,
true);
1303 minY, specialLonCases[specialLonCase],
false,
true,
true);
1306 maxX, specialLonCases[specialLonCase],
true,
true,
false);
1309 maxY, specialLonCases[specialLonCase],
false,
true,
false);
1371 double &extremeVal,
const double constBorder,
1372 bool searchX,
bool searchLongitude,
bool findMin) {
1373 if (minBorder ==
Null || maxBorder ==
Null || constBorder ==
Null) {
1377 const int NUM_ATTEMPTS = (
unsigned int)DBL_DIG;
1380 double minBorderX, minBorderY, maxBorderX, maxBorderY;
1384 findExtreme(minBorder, maxBorder, minBorderX, minBorderY, maxBorderX,
1385 maxBorderY, constBorder, searchX, searchLongitude, findMin);
1386 if (minBorderX ==
Null && maxBorderX ==
Null
1387 && minBorderY ==
Null && maxBorderY ==
Null ) {
1388 attempts = NUM_ATTEMPTS;
1393 while ((fabs(minBorderX - maxBorderX) > TOLERANCE
1394 || fabs(minBorderY - maxBorderY) > TOLERANCE)
1395 && (attempts < NUM_ATTEMPTS));
1400 if (attempts >= NUM_ATTEMPTS) {
1405 if (searchLongitude) {
1415 if (searchX) extremeVal = min(minBorderX, maxBorderX);
1416 else extremeVal = min(minBorderY, maxBorderY);
1419 if (searchX) extremeVal = max(minBorderX, maxBorderX);
1420 else extremeVal = max(minBorderY, maxBorderY);
1485 double &minBorderX,
double &minBorderY,
1486 double &maxBorderX,
double &maxBorderY,
1487 const double constBorder,
bool searchX,
1488 bool searchLongitude,
bool findMin) {
1489 if (minBorder ==
Null || maxBorder ==
Null || constBorder ==
Null) {
1491 minBorderY = minBorderX;
1492 minBorderX = minBorderX;
1493 minBorderY = minBorderX;
1496 if (!searchLongitude && (fabs(fabs(constBorder) - 90.0) < DBL_EPSILON)) {
1501 maxBorderX = minBorderX;
1502 maxBorderY = minBorderY;
1506 const double STEP_SIZE = (maxBorder - minBorder) / 10.0;
1507 const double LOOP_END = maxBorder + (STEP_SIZE / 2.0);
1510 double currBorderVal = minBorder;
1518 while (!
m_good && currBorderVal <= LOOP_END) {
1519 currBorderVal+=STEP_SIZE;
1520 if (searchLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1521 currBorderVal = 90.0;
1527 minBorderY = minBorderX;
1528 minBorderX = minBorderX;
1529 minBorderY = minBorderX;
1537 double border1 = currBorderVal;
1538 double border2 = currBorderVal;
1539 double border3 = currBorderVal;
1545 double value2 = value1;
1549 double extremeVal2 = value2;
1553 double extremeBorder1 = minBorder;
1554 double extremeBorder3 = minBorder;
1556 while (currBorderVal <= LOOP_END) {
1563 if (searchLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1564 currBorderVal = 90.0;
1568 currBorderVal += STEP_SIZE;
1577 border1 = currBorderVal;
1581 if ((findMin && value2 < extremeVal2)
1582 || (!findMin && value2 > extremeVal2)) {
1587 extremeVal2 = value2;
1589 extremeBorder3 = border3;
1590 extremeBorder1 = border1;
1597 minBorder = extremeBorder3;
1602 if (extremeBorder1 <= maxBorder ) {
1603 maxBorder = extremeBorder1;
1651 const double constBorder,
1652 bool variableIsLat) {
1653 if (variableBorder ==
Null || constBorder ==
Null) {
1657 if (variableIsLat) {
1658 lat = variableBorder;
1663 lon = variableBorder;
1679 keyNames <<
"TargetName" <<
"ProjectionName" <<
"EquatorialRadius" <<
"PolarRadius"
1680 <<
"LatitudeType" <<
"LongitudeDirection" <<
"LongitudeDomain"
1681 <<
"PixelResolution" <<
"Scale" <<
"UpperLeftCornerX" <<
"UpperLeftCornerY"
1682 <<
"MinimumLatitude" <<
"MaximumLatitude" <<
"MinimumLongitude" <<
"MaximumLongitude"
1685 foreach (QString keyName, keyNames) {
1749 IString msg =
"Snyder's q variable should only be computed for "
1750 "ellipsoidal projections.";
1755 * (sinPhi / (1 - eSinPhi * eSinPhi)
1756 - 1 / (2 * m_eccentricity) * log( (1 - eSinPhi) / (1 + eSinPhi) ));
1781 double localPhi =
HALFPI - 2.0 * atan(t);
1783 double difference = DBL_MAX;
1790 const int MAX_ITERATIONS = 45;
1792 while ((iteration < MAX_ITERATIONS) && (difference > 0.0000000001)) {
1793 double eccTimesSinphi =
Eccentricity() * sin(localPhi);
1795 2.0 * atan(t * pow((1.0 - eccTimesSinphi) /
1796 (1.0 + eccTimesSinphi), halfEcc));
1797 difference = fabs(newPhi - localPhi);
1802 if (iteration >= MAX_ITERATIONS) {
1803 IString msg =
"Failed to converge in TProjection::phi2Compute()";
1826 double denominator = sqrt(1.0 - eccTimesSinphi * eccTimesSinphi);
1827 return cosphi / denominator;
1848 if ((
HALFPI) - fabs(phi) < DBL_EPSILON)
return 0.0;
1851 double denominator = pow((1.0 - eccTimesSinphi) /
1852 (1.0 + eccTimesSinphi),
1854 return tan(0.5 * (
HALFPI - phi)) / denominator;
1872 return sqrt(pow(onePlusEcc, onePlusEcc) *
1873 pow(oneMinusEcc, oneMinusEcc));