USGS

Isis 3.0 Object Programmers' Reference

Home

ProjectionFactory.cpp
Go to the documentation of this file.
1 
23 #include "ProjectionFactory.h"
24 
25 #include <cmath>
26 #include <cfloat>
27 
28 #include "Camera.h"
29 #include "Cube.h"
30 #include "Displacement.h"
31 #include "Distance.h"
32 #include "FileName.h"
33 #include "IException.h"
34 #include "Plugin.h"
35 #include "Projection.h"
36 #include "RingPlaneProjection.h"
37 #include "TProjection.h"
38 
39 using namespace std;
40 
41 namespace Isis {
42  Plugin ProjectionFactory::m_projPlugin;
43 
65  Isis::Projection *ProjectionFactory::Create(Isis::Pvl &label,
66  bool allowDefaults) {
67  // Try to load a plugin file in the current working directory and then
68  // load the system file
69  Plugin p;
70 
71  if (m_projPlugin.fileName() == "") {
72  FileName localFile("Projection.plugin");
73  if (localFile.fileExists())
74  m_projPlugin.read(localFile.expanded());
75 
76  FileName systemFile("$ISISROOT/lib/Projection.plugin");
77  if (systemFile.fileExists())
78  m_projPlugin.read(systemFile.expanded());
79  }
80 
81  try {
82  // Look for info in the mapping group
83  Isis::PvlGroup &mapGroup = label.findGroup("Mapping", Isis::Pvl::Traverse);
84  QString proj = mapGroup["ProjectionName"];
85 
86  // Now get the plugin for the projection
87  void *ptr;
88  try {
89  ptr = m_projPlugin.GetPlugin(proj);
90  }
91  catch(IException &e) {
92  QString msg = "Unsupported projection, unable to find plugin for [" +
93  proj + "]";
94  throw IException(e, IException::Unknown, msg, _FILEINFO_);
95  }
96 
97  // Now cast that pointer in the proper way
98  Isis::TProjection * (*plugin)(Isis::Pvl & label, bool flag);
99  // plugin = (Isis::TProjection * ( *)(Isis::Pvl & label, bool flag)) ptr;
100  plugin = (Isis::TProjection * ( *)(Isis::Pvl & label, bool flag)) ptr;
101  // Create the projection as requested
102  return (Isis::Projection *) (*plugin)(label, allowDefaults);
103  }
104  catch(IException &e) {
105  QString message = "Unable to initialize Projection information ";
106  message += "from group [Mapping]";
107  throw IException(e, IException::Io, message, _FILEINFO_);
108  }
109  }
110 
111 
112 
113 
114 
136  Isis::Projection *ProjectionFactory::RingsCreate(Isis::Pvl &label,
137  bool allowDefaults) {
138  // Try to load a plugin file in the current working directory and then
139  // load the system file
140  Plugin p;
141 
142  if (m_projPlugin.fileName() == "") {
143  FileName localFile("Projection.plugin");
144  if (localFile.fileExists())
145  m_projPlugin.read(localFile.expanded());
146 
147  FileName systemFile("$ISISROOT/lib/Projection.plugin");
148  if (systemFile.fileExists())
149  m_projPlugin.read(systemFile.expanded());
150  }
151 
152  try {
153  // Look for info in the mapping group
154  Isis::PvlGroup &mapGroup = label.findGroup("Mapping", Isis::Pvl::Traverse);
155  QString proj = mapGroup["ProjectionName"];
156 
157  // Now get the plugin for the projection
158  void *ptr;
159  try {
160  ptr = m_projPlugin.GetPlugin(proj);
161  }
162  catch(IException &e) {
163  QString msg = "Unsupported projection, unable to find plugin for [" +
164  proj + "]";
165  throw IException(e, IException::Unknown, msg, _FILEINFO_);
166  }
167 
168  // Now cast that pointer in the proper way
169  Isis::RingPlaneProjection * (*plugin)(Isis::Pvl & label, bool flag);
170  plugin = (Isis::RingPlaneProjection * ( *)(Isis::Pvl & label, bool flag)) ptr;
171  // Create the projection as requested
172  return (Projection *) (*plugin)(label, allowDefaults);
173  }
174  catch(IException &e) {
175  QString message = "Unable to initialize Projection information ";
176  message += "from group [Mapping]";
177  throw IException(e, IException::Io, message, _FILEINFO_);
178  }
179  }
180 
204  Isis::Projection *ProjectionFactory::CreateForCube(Isis::Pvl &label,
205  int &samples, int &lines,
206  bool sizeMatch) {
207  // Create a temporary projection and get the radius at the special latitude
208  Isis::TProjection *proj = (Isis::TProjection *) Create(label, true);
209  double trueScaleLat = proj->TrueScaleLatitude();
210  double localRadius = proj->LocalRadius(trueScaleLat);
211  delete proj;
212 
213  IException errors;
214  try {
215  // Try to get the pixel resolution and then compute the scale
216  double scale, pixelResolution;
217  Isis::PvlGroup &mapGroup = label.findGroup("Mapping", Isis::Pvl::Traverse);
218  try {
219  pixelResolution = mapGroup["PixelResolution"];
220  scale = (2.0 * Isis::PI * localRadius) / (360.0 * pixelResolution);
221  }
222 
223  // If not get the scale and then compute the pixel resolution
224  catch(IException &e) {
225  errors.append(e);
226 
227  scale = mapGroup["Scale"];
228  pixelResolution = (2.0 * Isis::PI * localRadius) / (360.0 * scale);
229  }
230  // Write out the scale and resolution with units and truescale latitude
231  mapGroup.addKeyword(Isis::PvlKeyword("PixelResolution", toString(pixelResolution), "meters/pixel"),
232  Isis::Pvl::Replace);
233  mapGroup.addKeyword(Isis::PvlKeyword("Scale", toString(scale), "pixels/degree"), Isis::Pvl::Replace);
234  //mapGroup.addKeyword(Isis::PvlKeyword ("TrueScaleLatitude", trueScaleLat),
235  // Isis::Pvl::Replace);
236 
237  // Get the upper left corner from the labels if possible
238  // This forces an exact match of projection parameters for
239  // output cubes
240  bool sizeFound = false;
241  double upperLeftX = Null, upperLeftY = Null;
242  if (label.hasObject("IsisCube")) {
243  Isis::PvlGroup &dims = label.findGroup("Dimensions", Isis::Pvl::Traverse);
244  samples = dims["Samples"];
245  lines = dims["Lines"];
246 
247  upperLeftX = mapGroup["UpperLeftCornerX"];
248  upperLeftY = mapGroup["UpperLeftCornerY"];
249  sizeFound = true;
250  }
251  if (!sizeMatch) sizeFound = false;
252 
253  // Initialize the rest of the projection
254  proj = (Isis::TProjection *) Create(label, true);
255 
256  // Couldn't find the cube size from the labels so compute it
257  if (!sizeFound) {
258  if (!proj->HasGroundRange()) {
259  QString msg = "Invalid ground range [MinimumLatitude,MaximumLatitude,";
260  msg += "MinimumLongitude,MaximumLongitude] missing or invalid";
261  throw IException(IException::Unknown, msg, _FILEINFO_);
262  }
263 
264  double minX, maxX, minY, maxY;
265  if (!proj->XYRange(minX, maxX, minY, maxY)) {
266  QString msg = "Invalid ground range [MinimumLatitude,MaximumLatitude,";
267  msg += "MinimumLongitude,MaximumLongitude] cause invalid computation ";
268  msg += "of image size";
269  throw IException(IException::Unknown, msg, _FILEINFO_);
270  }
271 
272  // Convert upperleft coordinate to units of pixel
273  // Truncate it to the nearest whole pixel (floor/ceil)
274  // Convert it back to meters. But don't do this if
275  // the X/Y position is already close to a whole pixel because
276  // the floor/ceil function could cause an extra pixel to be added
277  // just due to machine precision issues
278  if (fabs(fmod(minX, pixelResolution)) > 1.0e-6) {
279  if (pixelResolution - fabs(fmod(minX, pixelResolution)) > 1.0e-6) {
280  double sampleOffset = floor(minX / pixelResolution);
281  minX = sampleOffset * pixelResolution;
282  }
283  }
284  // make sure that the distance from minX to maxX is at least one pixel wide
285  // so we have at least one sample in the created cube
286  if (maxX < minX + pixelResolution) {
287  maxX = minX + pixelResolution;
288  }
289 
290  if (fabs(fmod(maxY, pixelResolution)) > 1.0e-6) {
291  if (pixelResolution - fabs(fmod(maxY, pixelResolution)) > 1.0e-6) {
292  double lineOffset = -1.0 * ceil(maxY / pixelResolution);
293  maxY = -1.0 * lineOffset * pixelResolution;
294  }
295  }
296  // make sure that the distance from minY to maxY is at least one pixel wide
297  // so we have at least one line in the created cube
298  if (minY > maxY - pixelResolution) {
299  minY = maxY - pixelResolution;
300  }
301 
302  // Determine the number of samples and lines
303  samples = (int)((maxX - minX) / pixelResolution + 0.5);
304  lines = (int)((maxY - minY) / pixelResolution + 0.5);
305 
306  // Set the upper left corner and add to the labels
307  upperLeftX = minX;
308  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerX", toString(upperLeftX)),
309  Isis::Pvl::Replace);
310 
311  upperLeftY = maxY;
312  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerY", toString(upperLeftY)),
313  Isis::Pvl::Replace);
314 
315  // Write it in pixel units as well
316 #if 0
317  lineOffset += 0.5; // This matches the PDS definition
318  sampleOffset += 0.5; // of the offsets (center of pixel). This statement is questionable!
319  mapGroup.addKeyword(Isis::PvlKeyword("LineProjectionOffset", lineOffset),
320  Isis::Pvl::Replace);
321  mapGroup.addKeyword(Isis::PvlKeyword("SampleProjectionOffset", sampleOffset),
322  Isis::Pvl::Replace);
323 #endif
324  }
325 
326 
327  // Make sure labels have good units
328  mapGroup.addKeyword(Isis::PvlKeyword("PixelResolution",
329  (QString) mapGroup["PixelResolution"],
330  "meters/pixel"), Isis::Pvl::Replace);
331 
332  mapGroup.addKeyword(Isis::PvlKeyword("Scale",
333  (QString) mapGroup["Scale"],
334  "pixels/degree"), Isis::Pvl::Replace);
335 
336  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerX",
337  (QString) mapGroup["UpperLeftCornerX"],
338  "meters"), Isis::Pvl::Replace);
339 
340  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerY",
341  (QString) mapGroup["UpperLeftCornerY"],
342  "meters"), Isis::Pvl::Replace);
343 
344  mapGroup.addKeyword(Isis::PvlKeyword("EquatorialRadius",
345  (QString) mapGroup["EquatorialRadius"],
346  "meters"), Isis::Pvl::Replace);
347 
348  mapGroup.addKeyword(Isis::PvlKeyword("PolarRadius",
349  (QString) mapGroup["PolarRadius"],
350  "meters"), Isis::Pvl::Replace);
351 
352  // Add the mapper from pixel coordinates to projection coordinates
353  PFPixelMapper *pixelMapper = new PFPixelMapper(pixelResolution, upperLeftX, upperLeftY);
354  proj->SetWorldMapper(pixelMapper);
355 
356  proj->SetUpperLeftCorner(Displacement(upperLeftX, Displacement::Meters),
357  Displacement(upperLeftY, Displacement::Meters));
358  }
359  catch(IException &e) {
360  QString msg = "Unable to create projection";
361  if (label.fileName() != "") msg += " from file [" + label.fileName() + "]";
362  IException finalError(IException::Unknown, msg, _FILEINFO_);
363  finalError.append(errors);
364  finalError.append(e);
365  throw finalError;
366  }
367  return (Isis::Projection *) proj;
368  }
369 
394  Isis::Projection *ProjectionFactory::RingsCreateForCube(Isis::Pvl &label,
395  int &samples, int &lines, bool sizeMatch) {
396 
397  // Create a temporary projection and get the radius at the special radius
398  // NOTE: by "special radius" we mean that radius where the projection is
399  // not distorted
400  Isis::RingPlaneProjection *proj = (Isis::RingPlaneProjection *) RingsCreate(label, true);
401  double localRadius = proj->TrueScaleRingRadius();
402  delete proj;
403 
404  IException errors;
405  try {
406  // Try to get the pixel resolution and then compute the scale
407  double scale, pixelResolution;
408  Isis::PvlGroup &mapGroup = label.findGroup("Mapping", Isis::Pvl::Traverse);
409  try {
410  pixelResolution = mapGroup["PixelResolution"];
411  scale = (2.0 * Isis::PI * localRadius) / (360.0 * pixelResolution);
412  }
413  catch(IException &e) {
414  // If this fails, use the scale to compute the pixel resolution
415  errors.append(e);
416 
417  scale = mapGroup["Scale"];
418  pixelResolution = (2.0 * Isis::PI * localRadius) / (360.0 * scale);
419  }
420 
421  // Write out the scale and resolution with units and truescale radius
422  mapGroup.addKeyword(Isis::PvlKeyword("PixelResolution", toString(pixelResolution),
423  "meters/pixel"),
424  Isis::Pvl::Replace);
425  mapGroup.addKeyword(Isis::PvlKeyword("Scale", toString(scale), "pixels/degree"),
426  Isis::Pvl::Replace);
427 
428  //mapGroup.AddKeyword(Isis::PvlKeyword ("TrueScaleRadius", trueScaleRadius),
429  // Isis::Pvl::Replace);
430 
431  // Get the upper left corner from the labels if possible
432  // This forces an exact match of projection parameters for
433  // output cubes
434  bool sizeFound = false;
435  double upperLeftX = Null, upperLeftY = Null;
436  if (label.hasObject("IsisCube")) {
437  Isis::PvlGroup &dims = label.findGroup("Dimensions", Isis::Pvl::Traverse);
438  samples = dims["Samples"];
439  lines = dims["Lines"];
440 
441  upperLeftX = mapGroup["UpperLeftCornerX"];
442  upperLeftY = mapGroup["UpperLeftCornerY"];
443  sizeFound = true;
444  }
445 
446  if (!sizeMatch) {
447  sizeFound = false;
448  }
449 
450  // Initialize the rest of the projection
451  proj = (Isis::RingPlaneProjection *) RingsCreate(label, true);
452 
453  // Couldn't find the cube size from the labels so compute it
454  if (!sizeFound) {
455  if (!proj->HasGroundRange()) {
456  QString msg = "Invalid ring range [MinimumRingRadius,MaximumRingRadius,";
457  msg += "MinimumRingLongitude,MaximumRingLongitude] missing or invalid";
458  throw IException(IException::Unknown, msg, _FILEINFO_);
459  }
460 
461  double minX, maxX, minY, maxY;
462  if (!proj->XYRange(minX, maxX, minY, maxY)) {
463  QString msg = "Invalid ring range [MinimumRingRadius,MaximumRingRadius,";
464  msg += "MinimumRingLongitude,MaximumRingLongitude] cause invalid computation ";
465  msg += "of image size";
466  throw IException(IException::Unknown, msg, _FILEINFO_);
467  }
468 
469  // Convert upperleft coordinate to pixel units
470  // Truncate it to the nearest whole pixel (floor/ceil)
471  // Convert it back to meters. But don't do this if
472  // the X/Y position is already close to a whole pixel because
473  // the floor/ceil function could cause an extra pixel to be added
474  // just due to machine precision issues
475  if (fabs(fmod(minX, pixelResolution)) > 1.0e-6) {
476  if (pixelResolution - fabs(fmod(minX, pixelResolution)) > 1.0e-6) {
477  double sampleOffset = floor(minX / pixelResolution);
478  minX = sampleOffset * pixelResolution;
479  }
480  }
481  // make sure that the distance from minX to maxX is at least one pixel wide
482  // so we have at least one sample in the created cube
483  if (maxX < minX + pixelResolution) {
484  maxX = minX + pixelResolution;
485  }
486  if (fabs(fmod(maxY, pixelResolution)) > 1.0e-6) {
487  if (pixelResolution - fabs(fmod(maxY, pixelResolution)) > 1.0e-6) {
488  double lineOffset = -1.0 * ceil(maxY / pixelResolution);
489  maxY = -1.0 * lineOffset * pixelResolution;
490  }
491  }
492  // make sure that the distance from minY to maxY is at least one pixel wide
493  // so we have at least one line in the created cube
494  if (minY > maxY - pixelResolution) {
495  minY = maxY - pixelResolution;
496  }
497 
498  // Determine the number of samples and lines
499  samples = (int)((maxX - minX) / pixelResolution + 0.5);
500  lines = (int)((maxY - minY) / pixelResolution + 0.5);
501 
502  // Set the upper left corner and add to the labels
503  upperLeftX = minX;
504  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerX", toString(upperLeftX)),
505  Isis::Pvl::Replace);
506 
507  upperLeftY = maxY;
508  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerY", toString(upperLeftY)),
509  Isis::Pvl::Replace);
510 
511  // Write it in pixel units as well
512 #if 0
513  lineOffset += 0.5; // This matches the PDS definition
514  sampleOffset += 0.5; // of the offsets (center of pixel). This statement is questionable!
515  mapGroup.AddKeyword(Isis::PvlKeyword("LineProjectionOffset", lineOffset),
516  Isis::Pvl::Replace);
517  mapGroup.AddKeyword(Isis::PvlKeyword("SampleProjectionOffset", sampleOffset),
518  Isis::Pvl::Replace);
519 #endif
520  }
521 
522 
523  // Make sure labels have good units
524  mapGroup.addKeyword(Isis::PvlKeyword("PixelResolution",
525  (QString) mapGroup["PixelResolution"],
526  "meters/pixel"), Isis::Pvl::Replace);
527 
528  mapGroup.addKeyword(Isis::PvlKeyword("Scale",
529  (QString) mapGroup["Scale"],
530  "pixels/degree"), Isis::Pvl::Replace);
531 
532  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerX",
533  (QString) mapGroup["UpperLeftCornerX"],
534  "meters"), Isis::Pvl::Replace);
535 
536  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerY",
537  (QString) mapGroup["UpperLeftCornerY"],
538  "meters"), Isis::Pvl::Replace);
539 
540  // Add the mapper from pixel coordinates to projection coordinates
541  PFPixelMapper *pixelMapper = new PFPixelMapper(pixelResolution, upperLeftX, upperLeftY);
542  proj->SetWorldMapper(pixelMapper);
543 
544  proj->SetUpperLeftCorner(Displacement(upperLeftX, Displacement::Meters),
545  Displacement(upperLeftY, Displacement::Meters));
546  }
547  catch(IException &e) {
548  QString msg = "Unable to create projection";
549  if (label.fileName() != "") msg += " from file [" + label.fileName() + "]";
550  IException finalError(IException::Unknown, msg, _FILEINFO_);
551  finalError.append(errors);
552  finalError.append(e);
553  throw finalError;
554  }
555  return (Isis::Projection *) proj;
556  }
557 
558 
583  Isis::Projection *ProjectionFactory::CreateForCube(Isis::Pvl &label,
584  int &samples, int &lines,
585  Camera &cam) {
586  // Create a temporary projection and get the radius at the special latitude
587  Isis::TProjection *proj = (Isis::TProjection *) Create(label, true);
588  double trueScaleLat = proj->TrueScaleLatitude();
589  double localRadius = proj->LocalRadius(trueScaleLat);
590  delete proj;
591 
592  try {
593  // Try to get the pixel resolution and then compute the scale
594  double scale, pixelResolution;
595  Isis::PvlGroup &mapGroup = label.findGroup("Mapping", Isis::Pvl::Traverse);
596  try {
597  pixelResolution = mapGroup["PixelResolution"];
598  scale = (2.0 * Isis::PI * localRadius) / (360.0 * pixelResolution);
599  }
600 
601  // If not get the scale and then compute the pixel resolution
602  catch(IException &) {
603  scale = mapGroup["Scale"];
604  pixelResolution = (2.0 * Isis::PI * localRadius) / (360.0 * scale);
605  }
606  // Write out the scale and resolution with units and truescale latitude
607  mapGroup.addKeyword(Isis::PvlKeyword("PixelResolution", toString(pixelResolution), "meters/pixel"),
608  Isis::Pvl::Replace);
609  mapGroup.addKeyword(Isis::PvlKeyword("Scale", toString(scale), "pixels/degree"), Isis::Pvl::Replace);
610  //mapGroup.AddKeyword(Isis::PvlKeyword ("TrueScaleLatitude", trueScaleLatitude),
611  // Isis::Pvl::Replace);
612 
613  // Initialize the rest of the projection
614  proj = (Isis::TProjection *) Create(label, true);
615  double minX = DBL_MAX;
616  double maxX = -DBL_MAX;
617  double minY = DBL_MAX;
618  double maxY = -DBL_MAX;
619 
620  // Walk the boundaries of the camera to determine the x/y range
621  int eband = cam.Bands();
622  if (cam.IsBandIndependent()) eband = 1;
623  for(int band = 1; band <= eband; band++) {
624  cam.SetBand(band);
625 
626  // Loop for each line testing the left and right sides of the image
627  for(int line = 0; line <= cam.Lines(); line++) {
628  // Look for the first good lat/lon on the left edge of the image
629  // If it is the first or last line then test the whole line
630  int samp;
631  for(samp = 0; samp <= cam.Samples(); samp++) {
632  if (cam.SetImage((double)samp + 0.5, (double)line + 0.5)) {
633  double lat = cam.UniversalLatitude();
634  double lon = cam.UniversalLongitude();
635  proj->SetUniversalGround(lat, lon);
636  if (proj->IsGood()) {
637  if (proj->XCoord() < minX) minX = proj->XCoord();
638  if (proj->XCoord() > maxX) maxX = proj->XCoord();
639  if (proj->YCoord() < minY) minY = proj->YCoord();
640  if (proj->YCoord() > maxY) maxY = proj->YCoord();
641  if ((line != 0) && (line != cam.Lines())) break;
642  }
643  }
644  }
645 
646  // Look for the first good lat/lon on the right edge of the image
647  if (samp < cam.Samples()) {
648  for(samp = cam.Samples(); samp >= 0; samp--) {
649  if (cam.SetImage((double)samp + 0.5, (double)line + 0.5)) {
650  double lat = cam.UniversalLatitude();
651  double lon = cam.UniversalLongitude();
652  proj->SetUniversalGround(lat, lon);
653  if (proj->IsGood()) {
654  if (proj->XCoord() < minX) minX = proj->XCoord();
655  if (proj->XCoord() > maxX) maxX = proj->XCoord();
656  if (proj->YCoord() < minY) minY = proj->YCoord();
657  if (proj->YCoord() > maxY) maxY = proj->YCoord();
658  break;
659  }
660  }
661  }
662  }
663  }
664 
665  // Special test for ground range to see if either pole is in the image
666  if (cam.SetUniversalGround(90.0, 0.0)) {
667  if (cam.Sample() >= 0.5 && cam.Line() >= 0.5 &&
668  cam.Sample() <= cam.Samples() + 0.5 && cam.Line() <= cam.Lines() + 0.5) {
669  double lat = cam.UniversalLatitude();
670  double lon = cam.UniversalLongitude();
671  proj->SetUniversalGround(lat, lon);
672  if (proj->IsGood()) {
673  if (proj->XCoord() < minX) minX = proj->XCoord();
674  if (proj->XCoord() > maxX) maxX = proj->XCoord();
675  if (proj->YCoord() < minY) minY = proj->YCoord();
676  if (proj->YCoord() > maxY) maxY = proj->YCoord();
677  }
678  }
679  }
680 
681  if (cam.SetUniversalGround(-90.0, 0.0)) {
682  if (cam.Sample() >= 0.5 && cam.Line() >= 0.5 &&
683  cam.Sample() <= cam.Samples() + 0.5 && cam.Line() <= cam.Lines() + 0.5) {
684  double lat = cam.UniversalLatitude();
685  double lon = cam.UniversalLongitude();
686  proj->SetUniversalGround(lat, lon);
687  if (proj->IsGood()) {
688  if (proj->XCoord() < minX) minX = proj->XCoord();
689  if (proj->XCoord() > maxX) maxX = proj->XCoord();
690  if (proj->YCoord() < minY) minY = proj->YCoord();
691  if (proj->YCoord() > maxY) maxY = proj->YCoord();
692  }
693  }
694  }
695 
696 #if 0
697  // Another special test for ground range as we could have the
698  // 0-360 seam running right through the image so
699  // test it as well (the increment may not be fine enough !!!)
700  for(double lat = p_minlat; lat <= p_maxlat; lat += (p_maxlat - p_minlat) / 10.0) {
701  if (SetUniversalGround(lat, 0.0)) {
702  if (Sample() >= 0.5 && Line() >= 0.5 &&
703  Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) {
704  p_minlon = 0.0;
705  p_maxlon = 360.0;
706  break;
707  }
708  }
709  }
710 
711  // Another special test for ground range as we could have the
712  // -180-180 seam running right through the image so
713  // test it as well (the increment may not be fine enough !!!)
714  for(double lat = p_minlat; lat <= p_maxlat; lat += (p_maxlat - p_minlat) / 10.0) {
715  if (SetUniversalGround(lat, 180.0)) {
716  if (Sample() >= 0.5 && Line() >= 0.5 &&
717  Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) {
718  p_minlon180 = -180.0;
719  p_maxlon180 = 180.0;
720  break;
721  }
722  }
723  }
724 #endif
725  }
726 
727  // Convert upperleft coordinate to units of pixel
728  // Truncate it to the nearest whole pixel (floor/ceil)
729  // Convert it back to meters. But don't do this if
730  // the X/Y position is already close to a whole pixel because
731  // the floor/ceil function could cause an extra pixel to be added
732  // just due to machine precision issues
733  if (fabs(fmod(minX, pixelResolution)) > 1.0e-6) {
734  if (pixelResolution - fabs(fmod(minX, pixelResolution)) > 1.0e-6) {
735  double sampleOffset = floor(minX / pixelResolution);
736  minX = sampleOffset * pixelResolution;
737  }
738  }
739  // make sure that the distance from minX to maxX is at least one pixel wide
740  // so we have at least one sample in the created cube
741  if (maxX < minX + pixelResolution) {
742  maxX = minX + pixelResolution;
743  }
744  if (fabs(fmod(maxY, pixelResolution)) > 1.0e-6) {
745  if (pixelResolution - fabs(fmod(maxY, pixelResolution)) > 1.0e-6) {
746  double lineOffset = -1.0 * ceil(maxY / pixelResolution);
747  maxY = -1.0 * lineOffset * pixelResolution;
748  }
749  }
750  // make sure that the distance from minY to maxY is at least one pixel wide
751  // so we have at least one line in the created cube
752  if (minY > maxY - pixelResolution) {
753  minY = maxY - pixelResolution;
754  }
755 
756  // Determine the number of samples and lines
757  samples = (int)((maxX - minX) / pixelResolution + 0.5);
758  lines = (int)((maxY - minY) / pixelResolution + 0.5);
759 
760  // Set the upper left corner and add to the labels
761  double upperLeftX = minX;
762  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerX", toString(upperLeftX)),
763  Isis::Pvl::Replace);
764 
765  double upperLeftY = maxY;
766  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerY", toString(upperLeftY)),
767  Isis::Pvl::Replace);
768 
769  // Make sure labels have good units
770  mapGroup.addKeyword(Isis::PvlKeyword("PixelResolution",
771  (QString) mapGroup["PixelResolution"],
772  "meters/pixel"), Isis::Pvl::Replace);
773 
774  mapGroup.addKeyword(Isis::PvlKeyword("Scale",
775  (QString) mapGroup["Scale"],
776  "pixels/degree"), Isis::Pvl::Replace);
777 
778  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerX",
779  (QString) mapGroup["UpperLeftCornerX"],
780  "meters"), Isis::Pvl::Replace);
781 
782  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerY",
783  (QString) mapGroup["UpperLeftCornerY"],
784  "meters"), Isis::Pvl::Replace);
785 
786  mapGroup.addKeyword(Isis::PvlKeyword("EquatorialRadius",
787  (QString) mapGroup["EquatorialRadius"],
788  "meters"), Isis::Pvl::Replace);
789 
790  mapGroup.addKeyword(Isis::PvlKeyword("PolarRadius",
791  (QString) mapGroup["PolarRadius"],
792  "meters"), Isis::Pvl::Replace);
793 
794  // Add the mapper from pixel coordinates to projection coordinates
795  PFPixelMapper *pixelMapper = new PFPixelMapper(pixelResolution, upperLeftX, upperLeftY);
796  proj->SetWorldMapper(pixelMapper);
797 
798  proj->SetUpperLeftCorner(Displacement(upperLeftX, Displacement::Meters),
799  Displacement(upperLeftY, Displacement::Meters));
800  }
801  catch(IException &e) {
802  QString msg = "Unable to create projection";
803  if (label.fileName() != "") msg += " from file [" + label.fileName() + "]";
804  throw IException(e, IException::Unknown, msg, _FILEINFO_);
805  }
806  return (Isis::Projection *) proj;
807  }
808 
809 
834  Isis::Projection *ProjectionFactory::RingsCreateForCube(Isis::Pvl &label,
835  int &samples, int &lines, Camera &cam) {
836 
837  // Create a temporary projection
838  Isis::RingPlaneProjection *proj = (Isis::RingPlaneProjection *) RingsCreate(label, true);
839  double localRadius = proj->TrueScaleRingRadius();
840  delete proj;
841 
842  IException errors;
843  try {
844  // Try to get the pixel resolution and then compute the scale
845  double scale, pixelResolution;
846  Isis::PvlGroup &mapGroup = label.findGroup("Mapping", Isis::Pvl::Traverse);
847  try {
848  pixelResolution = mapGroup["PixelResolution"];
849  scale = (2.0 * Isis::PI * localRadius) / (360.0 * pixelResolution);
850  // scale = proj->Scale();
851  }
852 
853  // If not get the scale and then compute the pixel resolution
854  catch(IException &e) {
855  errors.append(e);
856  scale = mapGroup["Scale"];
857  pixelResolution = (2.0 * Isis::PI * localRadius) / (360.0 * scale);
858  }
859  // Write out the scale and resolution with units and truescale radius
860  mapGroup.addKeyword(Isis::PvlKeyword("PixelResolution", toString(pixelResolution),
861  "meters/pixel"), Isis::Pvl::Replace);
862  mapGroup.addKeyword(Isis::PvlKeyword("Scale", toString(scale), "pixels/degree"),
863  Isis::Pvl::Replace);
864 
865  // Initialize the rest of the projection
866  proj = (Isis::RingPlaneProjection *) RingsCreate(label, true);
867  double minX = DBL_MAX;
868  double maxX = -DBL_MAX;
869  double minY = DBL_MAX;
870  double maxY = -DBL_MAX;
871 
872  // Walk the boundaries of the camera to determine the x/y range
873  int eband = cam.Bands();
874  if (cam.IsBandIndependent()) eband = 1;
875  for(int band = 1; band <= eband; band++) {
876  cam.SetBand(band);
877 
878  // Loop for each line testing the left and right sides of the image
879  for(int line = 0; line <= cam.Lines(); line++) {
880  // Look for the first good rad/az on the left edge of the image
881  // If it is the first or last line then test the whole line
882  int samp;
883  for(samp = 0; samp <= cam.Samples(); samp++) {
884  if (cam.SetImage((double)samp + 0.5, (double)line + 0.5)) {
885  double radius = cam.LocalRadius().meters();
886  double az = cam.UniversalLongitude();
887  proj->SetGround(radius, az);
888  if (proj->IsGood()) {
889  if (proj->XCoord() < minX) minX = proj->XCoord();
890  if (proj->XCoord() > maxX) maxX = proj->XCoord();
891  if (proj->YCoord() < minY) minY = proj->YCoord();
892  if (proj->YCoord() > maxY) maxY = proj->YCoord();
893  if ((line != 0) && (line != cam.Lines())) break;
894  }
895  }
896  }
897 
898  // Look for the first good rad/az on the right edge of the image
899  if (samp < cam.Samples()) {
900  for(samp = cam.Samples(); samp >= 0; samp--) {
901  if (cam.SetImage((double)samp + 0.5, (double)line + 0.5)) {
902  double radius = cam.LocalRadius().meters();
903  double az = cam.UniversalLongitude();
904  proj->SetGround(radius, az);
905  if (proj->IsGood()) {
906  if (proj->XCoord() < minX) minX = proj->XCoord();
907  if (proj->XCoord() > maxX) maxX = proj->XCoord();
908  if (proj->YCoord() < minY) minY = proj->YCoord();
909  if (proj->YCoord() > maxY) maxY = proj->YCoord();
910  break;
911  }
912  }
913  }
914  }
915  }
916 
917 #if 0
918  // Another special test for ground range as we could have the
919  // 0-360 seam running right through the image so
920  // test it as well (the increment may not be fine enough !!!)
921  for(double rad = p_minRadius; rad <= p_maxRadius; rad += (p_maxRadius - p_minRadius) / 10.0) {
922  if (SetUniversalGround(rad, 0.0)) {
923  if (Sample() >= 0.5 && Line() >= 0.5 &&
924  Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) {
925  p_minaz = 0.0;
926  p_maxaz = 360.0;
927  break;
928  }
929  }
930  }
931 
932  // Another special test for ground range as we could have the
933  // -180-180 seam running right through the image so
934  // test it as well (the increment may not be fine enough !!!)
935  for(double rad = p_minrad; rad <= p_maxrad; rad += (p_maxrad - p_minrad) / 10.0) {
936  if (SetUniversalGround(rad, 180.0)) {
937  if (Sample() >= 0.5 && Line() >= 0.5 &&
938  Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) {
939  p_minaz180 = -180.0;
940  p_maxaz180 = 180.0;
941  break;
942  }
943  }
944  }
945 #endif
946  }
947 
948  // Convert upperleft coordinate to units of pixel
949  // Truncate it to the nearest whole pixel (floor/ceil)
950  // Convert it back to meters. But don't do this if
951  // the X/Y position is already close to a whole pixel because
952  // the floor/ceil function could cause an extra pixel to be added
953  // just due to machine precision issues
954  if (fabs(fmod(minX, pixelResolution)) > 1.0e-6) {
955  if (pixelResolution - fabs(fmod(minX, pixelResolution)) > 1.0e-6) {
956  double sampleOffset = floor(minX / pixelResolution);
957  minX = sampleOffset * pixelResolution;
958  }
959  }
960  // make sure that the distance from minX to maxX is at least one pixel wide
961  // so we have at least one sample in the created cube
962  if (maxX < minX + pixelResolution) {
963  maxX = minX + pixelResolution;
964  }
965 
966  if (fabs(fmod(maxY, pixelResolution)) > 1.0e-6) {
967  if (pixelResolution - fabs(fmod(maxY, pixelResolution)) > 1.0e-6) {
968  double lineOffset = -1.0 * ceil(maxY / pixelResolution);
969  maxY = -1.0 * lineOffset * pixelResolution;
970  }
971  }
972  // make sure that the distance from minY to maxY is at least one pixel wide
973  // so we have at least one line in the created cube
974  if (minY > maxY - pixelResolution) {
975  minY = maxY - pixelResolution;
976  }
977 
978  // Determine the number of samples and lines
979  samples = (int)((maxX - minX) / pixelResolution + 0.5);
980  lines = (int)((maxY - minY) / pixelResolution + 0.5);
981 
982  // Set the upper left corner and add to the labels
983  double upperLeftX = minX;
984  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerX", toString(upperLeftX)),
985  Isis::Pvl::Replace);
986 
987  double upperLeftY = maxY;
988  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerY", toString(upperLeftY)),
989  Isis::Pvl::Replace);
990 
991  // Make sure labels have good units
992  mapGroup.addKeyword(Isis::PvlKeyword("PixelResolution",
993  (QString) mapGroup["PixelResolution"],
994  "meters/pixel"), Isis::Pvl::Replace);
995 
996  mapGroup.addKeyword(Isis::PvlKeyword("Scale",
997  (QString) mapGroup["Scale"],
998  "pixels/degree"), Isis::Pvl::Replace);
999 
1000  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerX",
1001  (QString) mapGroup["UpperLeftCornerX"],
1002  "meters"), Isis::Pvl::Replace);
1003 
1004  mapGroup.addKeyword(Isis::PvlKeyword("UpperLeftCornerY",
1005  (QString) mapGroup["UpperLeftCornerY"],
1006  "meters"), Isis::Pvl::Replace);
1007 
1008  // Add the mapper from pixel coordinates to projection coordinates
1009  PFPixelMapper *pixelMapper = new PFPixelMapper(pixelResolution, upperLeftX, upperLeftY);
1010  proj->SetWorldMapper(pixelMapper);
1011 
1012  proj->SetUpperLeftCorner(Displacement(upperLeftX, Displacement::Meters),
1013  Displacement(upperLeftY, Displacement::Meters));
1014  }
1015  catch(IException &e) {
1016  QString msg = "Unable to create projection";
1017  if (label.fileName() != "") msg += " from file [" + label.fileName() + "]";
1018  throw IException(e, IException::Unknown, msg, _FILEINFO_);
1019  }
1020  return (Isis::Projection *) proj;
1021  }
1022 
1023 
1031  Isis::Projection *ProjectionFactory::CreateFromCube(Isis::Cube &cube) {
1032  return CreateFromCube(*cube.label());
1033  }
1034 
1035 
1043  Isis::Projection *ProjectionFactory::RingsCreateFromCube(Isis::Cube &cube) {
1044  return RingsCreateFromCube(*cube.label());
1045  }
1046 
1047 
1057  Isis::Projection *ProjectionFactory::CreateFromCube(Isis::Pvl &label) {
1058  Isis::TProjection *proj;
1059  try {
1060  // Get the pixel resolution
1061  Isis::PvlGroup &mapGroup = label.findGroup("Mapping", Isis::Pvl::Traverse);
1062  double pixelResolution = mapGroup["PixelResolution"];
1063 
1064  // Get the upper left corner
1065  double upperLeftX = mapGroup["UpperLeftCornerX"];
1066  double upperLeftY = mapGroup["UpperLeftCornerY"];
1067 
1068  // Initialize the rest of the projection
1069  proj = (Isis::TProjection *) Create(label, true);
1070 
1071  // Create a mapper to transform pixels into projection x/y and vice versa
1072  PFPixelMapper *pixelMapper = new PFPixelMapper(pixelResolution, upperLeftX, upperLeftY);
1073  proj->SetWorldMapper(pixelMapper);
1074 
1075  proj->SetUpperLeftCorner(Displacement(upperLeftX, Displacement::Meters),
1076  Displacement(upperLeftY, Displacement::Meters));
1077  }
1078  catch (IException &e) {
1079  QString msg = "Unable to initialize cube projection";
1080  if (label.fileName() != "") msg += " from file [" + label.fileName() + "]";
1081  throw IException(e, IException::Unknown, msg, _FILEINFO_);
1082  }
1083  return (Isis::Projection *) proj;
1084  }
1085 
1086 
1096  Isis::Projection *ProjectionFactory::RingsCreateFromCube(Isis::Pvl &label) {
1098  try {
1099  // Get the pixel resolution
1100  Isis::PvlGroup &mapGroup = label.findGroup("Mapping", Isis::Pvl::Traverse);
1101  double pixelResolution = mapGroup["PixelResolution"];
1102 
1103  // Get the upper left corner
1104  double upperLeftX = mapGroup["UpperLeftCornerX"];
1105  double upperLeftY = mapGroup["UpperLeftCornerY"];
1106 
1107  // Initialize the rest of the projection
1108  proj = (Isis::RingPlaneProjection *) RingsCreate(label, true);
1109 
1110  // Create a mapper to transform pixels into projection x/y and vice versa
1111  PFPixelMapper *pixelMapper = new PFPixelMapper(pixelResolution, upperLeftX, upperLeftY);
1112  proj->SetWorldMapper(pixelMapper);
1113 
1114  proj->SetUpperLeftCorner(Displacement(upperLeftX, Displacement::Meters),
1115  Displacement(upperLeftY, Displacement::Meters));
1116  }
1117  catch (IException &e) {
1118  QString msg = "Unable to initialize cube projection";
1119  if (label.fileName() != "") msg += " from file [" + label.fileName() + "]";
1120  throw IException(e, IException::Unknown, msg, _FILEINFO_);
1121  }
1122  return (Isis::Projection *) proj;
1123  }
1124 } //end namespace isis