OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimOrthoIgen.cpp
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 //
3 // License: LGPL
4 //
5 // See LICENSE.txt file in the top level directory for more details.
6 //
7 //----------------------------------------------------------------------------
8 // $Id: ossimOrthoIgen.cpp 22813 2014-06-04 19:52:08Z okramer $
9 
10 
12 #include <ossim/base/ossimCommon.h>
14 #include <ossim/init/ossimInit.h>
16 #include <ossim/base/ossimGrect.h>
22 #include <ossim/base/ossimTrace.h>
56 
57 #include <sstream>
58 
59 // In Windows, standard output is ASCII by default.
60 // Let's include the following in case we have
61 // to change it over to binary mode.
62 #if defined(_WIN32)
63 # include <io.h>
64 # include <fcntl.h>
65 #endif
66 
67 
68 static ossimTrace traceDebug("ossimOrthoIgen:debug");
69 static ossimTrace traceLog("ossimOrthoIgen:log");
70 
71 static const char* AUTOGENERATE_HISTOGRAM_KW = "autogenerate_histogram";
72 
73 using namespace ossim;
74 
75 //*************************************************************************************************
76 // Parses the file info as specified in the command line or src file. The file info is a '|'-
77 // delimited string with filename and additional attributes such as entry and band numbers.
78 //*************************************************************************************************
79 bool ossimOrthoIgen::parseFilename(const ossimString& file_spec, bool decodeEntry)
80 {
81  ossimSrcRecord src_record;
82 
83  std::vector<ossimString> fileInfos = file_spec.split("|");
84  unsigned int num_fields = (unsigned int) fileInfos.size();
85  unsigned int field_idx = 0;
86 
87  if (num_fields == 0)
88  return false;
89 
90  // First field is the actual filename:
91  src_record.setFilename(fileInfos[field_idx]);
92  ++field_idx;
93 
94  // Next field depends on whether an entry is being decoded:
95  if ((field_idx < num_fields) && decodeEntry)
96  {
97  src_record.setEntryIndex(fileInfos[field_idx].trim().toInt32());
98  ++field_idx;
99  }
100 
101  // The rest of the fields can appear in any order:
102  while (field_idx < num_fields)
103  {
104  ossimString active_field (fileInfos[field_idx].trim());
105  ossimString downcased_field (active_field);
106  downcased_field.downcase();
107  ++field_idx;
108 
109  // Check for overview file spec:
110  ossimFilename filename (active_field);
111  if (filename.contains(".ovr") || filename.isDir())
112  {
113  src_record.setSupportDir(filename.path());
114  }
115  else if (filename.contains(".mask") || filename.isDir())
116  {
117  src_record.setSupportDir(filename.path());
118  }
119 
120  // else check for auto-minmax histogram stretch:
121  else if ((downcased_field == "auto-minmax") || downcased_field.contains("std-stretch"))
122  {
123  src_record.setHistogramOp(downcased_field);
124  }
125 
126  // Otherwise, this must be a band specification. Band numbers begin with 1:
127  else
128  {
129  // multiple bands delimited by comma:
130  std::vector<ossimString> bandsStr = active_field.split(",");
131  std::vector<ossim_uint32> bands;
132  for (unsigned int i = 0; i < bandsStr.size(); i++)
133  {
134  int band = bandsStr[i].toInt32() - 1;
135  if (band >= 0)
136  bands.push_back((ossim_uint32)band);
137  }
138  src_record.setBands(bands);
139  }
140 
141  } // end of while loop parsing fileInfos spec
142 
143  theSrcRecords.push_back(src_record);
144  return true;
145 }
146 
147 //*************************************************************************************************
148 // Constructor
149 //*************************************************************************************************
151  :
152  ossimIgen(),
153  theDeltaPerPixelUnit(OSSIM_UNIT_UNKNOWN),
154  theDeltaPerPixelOverride(ossim::nan(), ossim::nan()),
155  theProjectionType(OSSIM_UNKNOWN_PROJECTION),
156  theProjectionName(""),
157  theGeoScalingLatitude(ossim::nan()),
158  theCombinerType("ossimImageMosaic"),
159  theResamplerType("nearest neighbor"),
160  theWriterType(""),
161  theTemplateView(""),
162  theTilingTemplate(""),
163  theTilingFilename(""),
164  theChainTemplate(""),
165  theCombinerTemplate(""),
166  theAnnotationTemplate(""),
167  theWriterTemplate(""),
168  theSupplementaryDirectory(""),
169  theSlaveBuffers("2"),
170  theCutOriginType(ossimOrthoIgen::OSSIM_CENTER_ORIGIN),
171  theCutOrigin(ossim::nan(), ossim::nan()),
172  theCutDxDy(ossim::nan(), ossim::nan()),
173  theCutOriginUnit(OSSIM_UNIT_UNKNOWN),
174  theCutDxDyUnit(OSSIM_UNIT_UNKNOWN),
175  theLowPercentClip(ossim::nan()),
176  theHighPercentClip(ossim::nan()),
177  theStdDevClip(-1),
178  theUseAutoMinMaxFlag(false),
179  theClipToValidRectFlag(false),
180  theReaderProperties(),
181  theWriterProperties(),
182  theTargetHistoFileName(),
183  theProductFilename(),
184  theReferenceProj(0),
185  theMaskShpFile(""),
186  theCacheExcludedFlag(false),
187  theOutputRadiometry(""),
188  thePixelAlignment(OSSIM_PIXEL_IS_AREA) // will revert to "point" upon first occurrence in source list
189 {
190  // Determine default behavior of clip from preferences:
191  ossimString flag = ossimPreferences::instance()->findPreference("orthoigen.clip_to_valid_rect");
192  if (!flag.empty())
193  theClipToValidRectFlag = flag.toBool();
194 
195  thePixelReplacementMode = ossimPreferences::instance()->findPreference("orthoigen.flip_null_pixels");
196  return;
197 }
198 
199 //*************************************************************************************************
200 // Initializes the argument parser
201 //*************************************************************************************************
202 void ossimOrthoIgen::addArguments(ossimArgumentParser& argumentParser)
203 {
204  // These are in ALPHABETIC ORDER. Please keep it that way.
205 
206  argumentParser.getApplicationUsage()->addCommandLineOption(
207  "--annotate", "annotation keyword list");
208  argumentParser.getApplicationUsage()->addCommandLineOption(
209  "--chain-template","Specify an external file that contains chain information");
210  argumentParser.getApplicationUsage()->addCommandLineOption(
211  "--clamp-pixels <min> <max>","Specify the min and max allowed pixel values. All values "
212  "outside of this get mapped to their corresponding clamp value.");
213  argumentParser.getApplicationUsage()->addCommandLineOption(
214  "--clip-pixels <min> <max>","Causes all pixel values between min and max (inclusive)"
215  " to be mapped to the null pixel value. Min and max can be equal for mapping a single value."
216  " See also related option \"--replacement-mode\" for additional explanation.");
217  argumentParser.getApplicationUsage()->addCommandLineOption(
218  "--clip-to-valid-rect <true|false>","When true, any requested cut rect is clipped by the "
219  "valid image bounding rect to minimize null border pixels. If false, the output will "
220  "correspond to the cut rect as close as possible given the product projection. This option "
221  "overrides the ossim_preferences setting. If no cut options are supplied, this option is "
222  "ignored.");
223  argumentParser.getApplicationUsage()->addCommandLineOption(
224  "--combiner-template","Specify an external file that contains combiner information");
225  argumentParser.getApplicationUsage()->addCommandLineOption(
226  "--combiner-type","Specify what mosaic to use, ossimImageMosiac or ossimFeatherMosaic or "
227  "osimBlendMosaic ... etc");
228  argumentParser.getApplicationUsage()->addCommandLineOption(
229  "--cut-bbox-en","Specify the min easting, min northing, max easting, max northing");
230  argumentParser.getApplicationUsage()->addCommandLineOption(
231  "--cut-bbox-ll","Specify the min lat and min lon and max lat and maxlon <minLat> <minLon> "
232  "<maxLat> <maxLon>");
233  argumentParser.getApplicationUsage()->addCommandLineOption(
234  "--cut-center-ll","Specify the center cut in lat lon space. Takes two argument <lat> <lon>");
235  argumentParser.getApplicationUsage()->addCommandLineOption(
236  "--cut-pixel-width-height","Specify cut box's width and height in pixels");
237  argumentParser.getApplicationUsage()->addCommandLineOption(
238  "--cut-radius-meters","Specify the cut distance in meters. A bounding box for the cut will "
239  "be produced");
240  argumentParser.getApplicationUsage()->addCommandLineOption(
241  "--degrees","Specifies an override for degrees per pixel. Takes either a single value "
242  "applied equally to x and y directions, or two values applied correspondingly to x then y.");
243  argumentParser.getApplicationUsage()->addCommandLineOption(
244  "--geo","Defaults to a geographic image chain with GSD = to the input. Origin of latitude is"
245  "on the equator.");
246  argumentParser.getApplicationUsage()->addCommandLineOption(
247  "--geo-auto-scaled","Computes the mosaic center latitude for purpose of scaling in the "
248  "longitude direction so that the pixels will appear nearly square in ground space at "
249  "specified latitude. Implies a geographic projection.");
250  argumentParser.getApplicationUsage()->addCommandLineOption(
251  "--geo-scaled","Takes latitude as an argument for purpose of scaling in the "
252  "longitude direction so that the pixels will appear nearly square in ground space at "
253  "specified latitude. Implies a geographic projection.");
254  argumentParser.getApplicationUsage()->addCommandLineOption(
255  "--hist-auto-minmax","uses the automatic search for the best min and max clip values."
256  " Incompatible with other histogram options.");
257  argumentParser.getApplicationUsage()->addCommandLineOption(
258  "--hist-match","Takes one image filename argument for target histogram to match."
259  " Incompatible with other histogram options.");
260  argumentParser.getApplicationUsage()->addCommandLineOption(
261  "--hist-std-stretch","Specify histogram stretch as a standard deviation from the mean as"
262  " <int>, where <int> is 1, 2, or 3."
263  " Incompatible with other histogram options.");
264  argumentParser.getApplicationUsage()->addCommandLineOption(
265  "--hist-stretch","Specify in normalized percent the low clip and then the high clip value"
266  " as <low.dd> <hi.dd>."
267  " Incompatible with other histogram options.");
268  argumentParser.getApplicationUsage()->addCommandLineOption(
269  "--input-proj","Makes the view equal to the input. If more than one file then the first is "
270  "taken");
271  argumentParser.getApplicationUsage()->addCommandLineOption(
272  "--mask","Specify the ESRI shape file with polygons to clip the image");
273  argumentParser.getApplicationUsage()->addCommandLineOption(
274  "--meters","Specifies an override for the meters per pixel. Takes either a single value "
275  "applied equally to x and y directions, or two values applied correspondingly to x then y.");
276  argumentParser.getApplicationUsage()->addCommandLineOption(
277  "--no-cache","Excludes the cache from the input image chain(s). Necessary as a workaround "
278  " for inconsistent cache behavior for certain image types.");
279  argumentParser.getApplicationUsage()->addCommandLineOption(
280  "--output-radiometry","Specifies the desired product's pixel radiometry type. Possible "
281  "values are: U8, U11, U16, S16, F32. Note this overrides the deprecated option \"scale-to"
282  "-8-bit\".");
283  argumentParser.getApplicationUsage()->addCommandLineOption(
284  "--reader-prop","Passes a name=value pair to the reader(s) for setting it's property. Any "
285  "number of these can appear on the line.");
286  argumentParser.getApplicationUsage()->addCommandLineOption(
287  "--replacement-mode <mode>","Specify how to treat multi-band imagery when providing "
288  "clip-pixels and/or clamp-pixels settings. Possible values are: REPLACE_BAND_IF_TARGET | "
289  "REPLACE_BAND_IF_PARTIAL_TARGET | REPLACE_ALL_BANDS_IF_ANY_TARGET | "
290  "REPLACE_ONLY_FULL_TARGETS.");
291  argumentParser.getApplicationUsage()->addCommandLineOption(
292  "--resample-type","Specify what resampler to use, nearest neighbor, bilinear, cubic");
293  argumentParser.getApplicationUsage()->addCommandLineOption(
294  "--scale-to-8-bit","Scales the output to unsigned eight bits per band. This option has been"
295  " deprecated by the newer \"--output-radiometry\" option.");
296  argumentParser.getApplicationUsage()->addCommandLineOption(
297  "--slave-buffers","number of slave tile buffers for mpi processing (default = 2)");
298  argumentParser.getApplicationUsage()->addCommandLineOption(
299  "--srs","specify an output reference frame/projection. Example: --srs EPSG:4326");
300  argumentParser.getApplicationUsage()->addCommandLineOption(
301  "--stdout","Output the image to standard out. This will return an error if writer does not "
302  "support writing to standard out. Callers should combine this with the --ossim-logfile "
303  "option to ensure output image stream does not get corrupted. You must still pass an output "
304  "file so the writer type can be determined like \"dummy.png\".");
305  argumentParser.getApplicationUsage()->addCommandLineOption(
306  "--supplementary-directory or --support","Specify the supplementary directory path where "
307  "overviews, histograms and external geometries are located");
308  argumentParser.getApplicationUsage()->addCommandLineOption(
309  "-t or --thumbnail", "thumbnail size");
310  argumentParser.getApplicationUsage()->addCommandLineOption(
311  "--tiling-template","Specify an external file that contains tiling information");
312  argumentParser.getApplicationUsage()->addCommandLineOption(
313  "--threads [n]","Indicates multi-threaded process using optionally-specified number of threads");
314  argumentParser.getApplicationUsage()->addCommandLineOption(
315  "--utm","Defaults to a utm image chain with GSD = to the input");
316  argumentParser.getApplicationUsage()->addCommandLineOption(
317  "--view-template","Specify an external file that contains view information");
318  argumentParser.getApplicationUsage()->addCommandLineOption(
319  "-w or --writer","Specifies the output writer. Default uses output file extension to "
320  "determine writer.");
321  argumentParser.getApplicationUsage()->addCommandLineOption(
322  "--wkt","specify an output reference frame/projection that is in a wkt format. Must have the"
323  " ossimgdal_plugin compiled");
324  argumentParser.getApplicationUsage()->addCommandLineOption(
325  "--writer-prop","Passes a name=value pair to the writer for setting it's property. Any "
326  "number of these can appear on the line.");
327  argumentParser.getApplicationUsage()->addCommandLineOption(
328  "--writer-template","Specify an external file that contains tiling information");
329 }
330 
331 //*************************************************************************************************
332 // Initializes this objects data members given the command line args
333 //*************************************************************************************************
335 {
336  if(traceDebug())
337  {
339  << "ossimOrthoIgen::initialize DEBUG:"
340  << "Entered..... "
341  << std::endl;
342  }
343  double tempDouble;
344  double tempDouble2;
345  double tempDouble3;
346  double tempDouble4;
347  ossimString tempString;
348  unsigned int tempUint;
349  ossimArgumentParser::ossimParameter stringParam(tempString);
350  ossimArgumentParser::ossimParameter doubleParam(tempDouble);
351  ossimArgumentParser::ossimParameter doubleParam2(tempDouble2);
352  ossimArgumentParser::ossimParameter doubleParam3(tempDouble3);
353  ossimArgumentParser::ossimParameter doubleParam4(tempDouble4);
354  ossimArgumentParser::ossimParameter uintParam(tempUint);
355  theCutOriginType = ossimOrthoIgen::OSSIM_CENTER_ORIGIN;
356  theCutOrigin.makeNan();
357  theCutDxDy.makeNan();
358  theCutOriginUnit = OSSIM_UNIT_UNKNOWN;
359  theCutDxDyUnit = OSSIM_UNIT_UNKNOWN;
360  theLowPercentClip = ossim::nan();
361  theHighPercentClip = ossim::nan();
362  double minX=ossim::nan(), minY=ossim::nan(), maxX=ossim::nan(), maxY=ossim::nan();
363  theUseAutoMinMaxFlag = false;
364  theDeltaPerPixelOverride.makeNan();
365  theDeltaPerPixelUnit = OSSIM_UNIT_UNKNOWN;
366  theCacheExcludedFlag = false;
367  theClampPixelMin = ossim::nan();
368  theClampPixelMax = ossim::nan();
369  theClipPixelMin = ossim::nan();
370  theClipPixelMax = ossim::nan();
371 
372  if(argumentParser.read("--annotate", stringParam))
373  {
374  theAnnotationTemplate = ossimFilename(tempString);
375  }
376  if(argumentParser.read("-t", stringParam) ||
377  argumentParser.read("--thumbnail", stringParam))
378  {
379  ossimString comma (",");
380  if (tempString.contains(comma))
381  {
382  theThumbnailSize.x = tempString.before(comma).toInt();
383  theThumbnailSize.y = tempString.after(comma).toInt();
384  }
385  else
386  {
387  theThumbnailSize.x = tempString.toInt();
388  theThumbnailSize.y = 0;
389  }
390  theBuildThumbnailFlag = true;
391  }
392 
393  theReaderProperties.clear();
394  while(argumentParser.read("--reader-prop", stringParam))
395  {
396  std::vector<ossimString> splitArray;
397  tempString.split(splitArray, "=");
398  if(splitArray.size() == 2)
399  {
400  theReaderProperties.insert(std::make_pair(splitArray[0], splitArray[1]));
401  }
402  }
403 
404  if(argumentParser.read("-w", stringParam) ||
405  argumentParser.read("--writer", stringParam))
406  {
407  theWriterType = tempString;
408  }
409 
410  theWriterProperties.clear();
411 
412  while(argumentParser.read("--writer-prop", stringParam))
413  {
414  std::vector<ossimString> splitArray;
415  tempString.split(splitArray, "=");
416  if(splitArray.size() == 2)
417  {
418  theWriterProperties.insert(std::make_pair(splitArray[0], splitArray[1]));
419  }
420  }
421 
422  if(argumentParser.read("--slave-buffers", stringParam))
423  {
424  theSlaveBuffers = tempString;
425  }
426  if(argumentParser.read("--cut-center-ll", doubleParam, doubleParam2))
427  {
428  theCutOrigin.lat = tempDouble;
429  theCutOrigin.lon = tempDouble2;
430  theCutOriginUnit = OSSIM_DEGREES;
431  theCutOriginType = ossimOrthoIgen::OSSIM_CENTER_ORIGIN;
432  }
433  if(argumentParser.read("--cut-radius-meters", doubleParam))
434  {
435  theCutDxDy.x = tempDouble;
436  theCutDxDy.y = tempDouble;
437  theCutDxDyUnit = OSSIM_METERS;
438  }
439  if(argumentParser.read("--cut-bbox-ll", doubleParam, doubleParam2, doubleParam3, doubleParam4))
440  {
441  minY = tempDouble;
442  minX = tempDouble2;
443  maxY = tempDouble3;
444  maxX = tempDouble4;
445  theCutOriginUnit = OSSIM_DEGREES;
446  theCutOriginType = ossimOrthoIgen::OSSIM_UPPER_LEFT_ORIGIN;
447  theCutOrigin.lat = maxY;
448  theCutOrigin.lon = minX;
449  theCutDxDy.lat = (maxY-minY);
450  if ( (maxX < 0.0) && (minX >= 0.0) )
451  {
452  //---
453  // Min is eastern hemisphere, max is western. Crossed the international date line.
454  // Add 360 to make it positive.
455  //
456  // Note no check for just max < min here??? Perhaps throw exception.(drb)
457  //---
458  maxX += 360.0;
459  }
460  theCutDxDy.lon = (maxX-minX);
461  theCutDxDyUnit = OSSIM_DEGREES;
462  }
463  if(argumentParser.read("--cut-bbox-en", doubleParam, doubleParam2, doubleParam3, doubleParam4))
464  {
465  minX = tempDouble;
466  minY = tempDouble2;
467  maxX = tempDouble3;
468  maxY = tempDouble4;
469  theCutOriginUnit = OSSIM_METERS;
470  theCutOriginType = ossimOrthoIgen::OSSIM_UPPER_LEFT_ORIGIN;
471  theCutOrigin.x = minX;
472  theCutOrigin.y = maxY;
473  theCutDxDy.x = (maxX-minX);
474  theCutDxDy.y = (maxY-minY);
475  theCutDxDyUnit = OSSIM_METERS;
476  }
477  if(argumentParser.read("--cut-pixel-width-height", doubleParam, doubleParam2))
478  {
479  if((ossim::isnan(minX) == false)&&
480  (ossim::isnan(minY) == false)&&
481  (ossim::isnan(maxX) == false)&&
482  (ossim::isnan(maxY) == false))
483  {
484  theDeltaPerPixelOverride = ossimDpt(theCutDxDy.x/(tempDouble-1),
485  theCutDxDy.y/(tempDouble2-1));
486  theDeltaPerPixelUnit = theCutDxDyUnit;
487  }
488  else
489  {
490  theCutOrigin.makeNan();
491  ossimNotify(ossimNotifyLevel_WARN) << "Can't have option --cut-pixel-width-height without --cut-bbox-ll" << std::endl;
492  }
493  }
494 
495  int num_params = argumentParser.numberOfParams("--degrees", doubleParam);
496  if (num_params == 1)
497  {
498  argumentParser.read("--degrees", doubleParam);
499  theDeltaPerPixelUnit = OSSIM_DEGREES;
500  theDeltaPerPixelOverride.x = tempDouble;
501  theDeltaPerPixelOverride.y = tempDouble;
502  }
503  else if (num_params == 2)
504  {
505  argumentParser.read("--degrees", doubleParam, doubleParam2);
506  theDeltaPerPixelUnit = OSSIM_DEGREES;
507  theDeltaPerPixelOverride.x = tempDouble;
508  theDeltaPerPixelOverride.y = tempDouble2;
509  }
510 
511  // The three histogram options are mutually exclusive:
512  bool histo_op_selected = false;
513  if(argumentParser.read("--hist-match", stringParam))
514  {
515  ossimFilename target_image (tempString);
516  histo_op_selected = true;
517 
518  // Check for histogram matching request and initialize for that:
519  if (target_image.isReadable())
520  {
521  // Establish target histogram file:
522  theTargetHistoFileName = target_image;
523  theTargetHistoFileName.setExtension("his");
524  if (!theTargetHistoFileName.isReadable())
525  {
526  ossimNotify(ossimNotifyLevel_NOTICE)<<"Target histogram file <" << theTargetHistoFileName
527  << "> not found. Cannot perform histogram matching." << std::endl;
528  theTargetHistoFileName.clear();
529  }
530  }
531  }
532  if(argumentParser.read("--hist-stretch", doubleParam, doubleParam2))
533  {
534  if (histo_op_selected)
535  {
536  ossimNotify(ossimNotifyLevel_WARN) << "Cannot specify nore than one histogram operation. "
537  " Ignoring --hist-stretch option." << std::endl;
538  }
539  else
540  {
541  theLowPercentClip = tempDouble;
542  theHighPercentClip = tempDouble2;
543  histo_op_selected = true;
544  }
545  }
546  if(argumentParser.read("--hist-std-stretch", stringParam))
547  {
548  if (histo_op_selected)
549  {
550  ossimNotify(ossimNotifyLevel_WARN) << "Cannot specify nore than one histogram operation. "
551  " Ignoring --hist-stretch option." << std::endl;
552  }
553  else
554  {
555  theStdDevClip = tempString.toInt32();
556  histo_op_selected = true;
557  if ((theStdDevClip < 1) || (theStdDevClip > 3))
558  {
559  ossimNotify(ossimNotifyLevel_WARN) << "Invalid standard deviation value provided with"
560  " --hist-std-stretch option. Only 1,2, or 3 allowed. Ignoring option."<< std::endl;
561  }
562  }
563  }
564  if(argumentParser.read("--hist-auto-minmax"))
565  {
566  if (histo_op_selected)
567  {
568  ossimNotify(ossimNotifyLevel_WARN) << "Cannot specify nore than one histogram operation. "
569  " Ignoring --hist-auto-minmax option." << std::endl;
570  }
571  else
572  theUseAutoMinMaxFlag = true;
573  }
574 
575  num_params = argumentParser.numberOfParams("--meters", doubleParam);
576  if (num_params == 1)
577  {
578  argumentParser.read("--meters", doubleParam);
579  theDeltaPerPixelUnit = OSSIM_METERS;
580  theDeltaPerPixelOverride.x = tempDouble;
581  theDeltaPerPixelOverride.y = tempDouble;
582  }
583  else if (num_params == 2)
584  {
585  argumentParser.read("--meters", doubleParam, doubleParam2);
586  theDeltaPerPixelUnit = OSSIM_METERS;
587  theDeltaPerPixelOverride.x = tempDouble;
588  theDeltaPerPixelOverride.y = tempDouble2;
589  }
590 
591  if(argumentParser.read("--no-cache"))
592  {
593  theCacheExcludedFlag = true;
594  }
595 
596  if(argumentParser.read("--output-radiometry", stringParam))
597  {
598  theOutputRadiometry = tempString;
599  }
600 
601  if(argumentParser.read("--scale-to-8-bit"))
602  {
603  if (theOutputRadiometry.empty())
604  theOutputRadiometry = "U8";
605  }
606 
607  if (argumentParser.read("--stdout"))
608  {
609 #if defined(_WIN32)
610  // In Windows, cout is ASCII by default.
611  // Let's change it over to binary mode.
612  int result = _setmode( _fileno(stdout), _O_BINARY );
613  if( result == -1 )
614  {
616  << "ossimOrthoIgen::initialize WARNING:"
617  << "\nCannot set standard output mode to binary."
618  << std::endl;
619  return;
620  }
621 #endif
622 
623  theStdoutFlag = true;
624  }
625 
626  if(argumentParser.read("--writer-template", stringParam))
627  {
628  theWriterTemplate = tempString;
629  }
630  if(argumentParser.read("--tiling-template", stringParam))
631  {
632  theTilingTemplate = ossimFilename(tempString);
633  }
634  if(argumentParser.read("--chain-template", stringParam))
635  {
636  theChainTemplate = ossimFilename(tempString);
637  }
638  if(argumentParser.read("--combiner-template", stringParam))
639  {
640  theCombinerTemplate = ossimFilename(tempString);
641  }
642 
643  theGeoScalingLatitude = ossim::nan();
644 
645  if (argumentParser.read("--utm"))
646  {
647  theProjectionType = OSSIM_UTM_PROJECTION;
648  theProjectionName = "ossimUtmProjection";
649  }
650  else if(argumentParser.read("--geo"))
651  {
652  theProjectionType = OSSIM_GEO_PROJECTION;
653  theProjectionName = "ossimEquDistCylProjection";
654  theGeoScalingLatitude = 0.0;
655  }
656  else if(argumentParser.read("--input-proj"))
657  {
658  theProjectionType = OSSIM_INPUT_PROJECTION;
659  }
660  else if (argumentParser.read("--srs", stringParam))
661  {
662  theCrsString=tempString;
663  theProjectionType = OSSIM_SRS_PROJECTION;
664  }
665 
666  if(argumentParser.read("--view-template", stringParam))
667  {
668  theTemplateView = ossimFilename(tempString);
669  theProjectionType = OSSIM_EXTERNAL_PROJECTION;
670  }
671 
672  if(argumentParser.read("--geo-scaled", doubleParam))
673  {
674  theProjectionType = OSSIM_GEO_PROJECTION;
675  theProjectionName = "ossimEquDistCylProjection";
676  if ( (tempDouble < 90.0) && (tempDouble > -90.0) )
677  {
678  theGeoScalingLatitude = tempDouble;
679  }
680  else
681  {
683  << "ossimOrthoIgen::initialize WARNING:"
684  << "\nLatitude out of range! Must be between -90 and 90."
685  << std::endl;
686  }
687  if (traceDebug())
688  {
690  << "ossimOrthoIgen::initialize DEBUG:"
691  << "\ngeographicOriginOfLatitude: " << theGeoScalingLatitude
692  << std::endl;
693  }
694  }
695 
696  if(argumentParser.read("--geo-auto-scaled"))
697  {
698  theProjectionType = OSSIM_GEO_PROJECTION;
699  theProjectionName = "ossimEquDistCylProjection";
700  theGeoScalingLatitude = 999.0; // Flags computation of center lat for scaling
701  }
702 
703  if(argumentParser.read("--combiner-type", stringParam))
704  theCombinerType = tempString;
705 
706  if(argumentParser.read("--resample-type", stringParam))
707  {
708  theResamplerType = tempString;
709  }
710  if(argumentParser.read("--supplementary-directory", stringParam) ||
711  argumentParser.read("--support", stringParam))
712  {
713  theSupplementaryDirectory = ossimFilename(tempString);
714  }
715 
716  if (argumentParser.read("--clip-to-valid-rect", stringParam))
717  {
718  theClipToValidRectFlag = tempString.toBool();
719  }
720 
721  if(argumentParser.read("--mask", stringParam))
722  {
723  theMaskShpFile = tempString;
724  }
725 
726  // Pixel flipper control options:
727  if (argumentParser.read("--clip-pixels", doubleParam, doubleParam2))
728  {
729  theClipPixelMin = tempDouble;
730  theClipPixelMax = tempDouble2;
731  }
732  if (argumentParser.read("--clamp-pixels", doubleParam, doubleParam2))
733  {
734  theClampPixelMin = tempDouble;
735  theClampPixelMax = tempDouble2;
736  }
737  if (argumentParser.read("--replacement-mode", stringParam))
738  {
739  thePixelReplacementMode = tempString;
740  }
741 
742  // Threading:
743  num_params = argumentParser.numberOfParams("--threads", uintParam);
744  if (num_params == 0) // No param means system decides optimal thread count
745  {
746  argumentParser.read("--threads");
747  theThreadCount = 0; // Flags system-resolved
748  }
749  else if (num_params == 1)
750  {
751  argumentParser.read("--threads", uintParam);
752  theThreadCount = (ossim_uint32) tempUint;
753  }
754 
755  if(traceDebug())
756  {
758  << "ossimOrthoIgen::initialize DEBUG:"
759  << "Leaving..... "
760  << std::endl;
761  }
762 }
763 
764 //*************************************************************************************************
765 // Adds any file specifications to the files list
766 //*************************************************************************************************
767 void ossimOrthoIgen::addFiles(ossimArgumentParser& argumentParser,
768  bool withDecoding,
769  ossim_uint32 startIdx)
770 {
771  ossim_uint32 idx = startIdx;
772  ossim_uint32 last_idx = argumentParser.argc()-1;
773  while(argumentParser.argv()[idx] && (idx < last_idx))
774  {
775  ossimString file_spec = argumentParser.argv()[idx];
776  if (file_spec.contains(".src"))
777  {
778  // input file spec provided via src file. Need to parse it:
779  addSrcFile(ossimFilename(file_spec));
780  }
781  else
782  {
783  // Filename with optional switches explicitly provided on command line:
784  parseFilename(file_spec, withDecoding);
785  }
786  ++idx;
787  }
788 
789  // The last filename left on the command line should be the product filename:
790  theProductFilename = argumentParser.argv()[last_idx];
791 }
792 
793 //*************************************************************************************************
794 // Performs the top-level management of image generation
795 //*************************************************************************************************
796 bool ossimOrthoIgen::execute()
797 {
798  if (traceDebug())
799  {
801  << "ossimOrthoIgen::execute DEBUG: Entered ..."
802  << std::endl;
803  }
804 // double start=0, stop=0;
805 
806  if(theSrcRecords.size() < 1)
807  {
809  << "ossimOrthoIgen::execute WARNING: No filenames to process"
810  << std::endl;
811  return false;
812  }
813 
814  if (!theCrsString.empty() && !theProductFilename.empty())
815  {
816  if ((theProductFilename.ext().upcase() == "KMZ" || theProductFilename.ext().upcase() == "KML")
817  && theCrsString.upcase() != "EPSG:4326")
818  {
820  << "ossimOrthoIgen::execute ERROR: Unsupported projection for kmz or kml"
821  << std::endl;
822  return false;
823  }
824  }
825 
826  //if(ossimMpi::instance()->getRank() == 0)
827  //{
828  try
829  {
830  setupIgenChain();
831  }
832  catch (const ossimException& e)
833  {
834  if (traceDebug())
835  {
836  ossimNotify(ossimNotifyLevel_DEBUG) << e.what() << std::endl;
837  }
838  throw; // re-throw exception
839  }
840 
841  if (traceLog())
842  {
843  generateLog();
844  }
845  //}
846 
847  try
848  {
849  // theProductProjection->print(cout) << endl;
850  outputProduct();
851  }
852  catch(const ossimException& e)
853  {
854  if (traceDebug())
855  {
856  ossimNotify(ossimNotifyLevel_DEBUG) << e.what() << std::endl;
857  }
858  throw; // re-throw
859  }
860 
861  return true;
862 }
863 
864 //*************************************************************************************************
865 // METHOD
866 //*************************************************************************************************
867 void ossimOrthoIgen::clearFilenameList()
868 {
869  theSrcRecords.clear();
870 }
871 
872 //*************************************************************************************************
873 // Parses the .src file specified in the command line. These contain an alternate specification
874 // of input file and associated attributes as a KWL.
875 //*************************************************************************************************
876 void ossimOrthoIgen::addSrcFile(const ossimFilename& src_file)
877 {
878  if (!src_file.isReadable())
879  return;
880 
881  ossimKeywordlist src_kwl;
882  src_kwl.setExpandEnvVarsFlag(true);
883  if ( src_kwl.addFile(src_file) == false ) return;
884 
885  unsigned int image_idx = 0;
886  // int entry = -1;
887 
888  // Loop to read all image file entries:
889  double sum_weights = 0;
890  while (true)
891  {
892  ossimSrcRecord src_record(src_kwl, image_idx++);
893  if (!src_record.valid())
894  break;
895 
896  // Check for the presence of separate RGB file specs in this SRC record. This indicates
897  // special processing. (comment added OLK 01/11)
898  if (src_record.isRgbData())
899  {
900  for (ossim_uint32 rgb_index = 0; rgb_index < 3; rgb_index++)
901  {
902  // This call creates another band-specific ossimSrcRecord that is pushed onto
903  // theSrcRecords vector data member. (comment added OLK 01/11)
904  if (parseFilename(src_record.getRgbFilename(rgb_index), true))
905  {
906  // The parseFilename call pushes the R, G, or B band onto the back of theSrcRecords
907  // vector. Set some additional attributes on this last entry. (OLK 01/11)
908  theSrcRecords.back().setRgbDataBool(true);
909  theSrcRecords.back().setHistogramOp(src_record.getRgbHistogramOp(rgb_index));
910  theSrcRecords.back().setHistogram(src_record.getRgbHistogramPath(rgb_index));
911  theSrcRecords.back().setOverview(src_record.getRgbOverviewPath(rgb_index));
912  }
913  }
914  }
915  else
916  {
917  // Not RGB data, so treat as conventional image: (comment added OLK 01/11)
918  theSrcRecords.push_back(src_record);
919  sum_weights += src_record.getWeight();
920 
921  //if the vector file exists, set the mosaic combiner type to ossimBlendMosaic
922  if (src_record.isVectorData())
923  theCombinerType = "ossimBlendMosaic";
924  }
925  }
926 
927  double max_weight = (sum_weights > 100.0 ? sum_weights : 100.0);
928  double num_entries = (double)theSrcRecords.size();
929  double weight;
930  vector<ossimSrcRecord>::iterator iter = theSrcRecords.begin();
931  while (iter != theSrcRecords.end())
932  {
933  if (sum_weights > 0.0)
934  {
935  // Somebody declared opacity, so need to share the remaining contributions among
936  // other images:
937  theCombinerType = "ossimBlendMosaic";
938  if (iter->getWeight() == 0.0)
939  {
940  // No weight has been assigned for this image, so use default remaining partial
941  if (num_entries == 1.0)
942  weight = 1.0; // This is the only image, so full weight
943  else
944  {
945  // share remaining contributions:
946  weight = (1.0 - sum_weights/max_weight)/(num_entries - 1);
947  if (weight < 0.01)
948  weight = 0.01;
949  }
950  }
951  else
952  {
953  // An opacity value was specified for this
954  weight = iter->getWeight()/max_weight;
955  }
956  }
957  else
958  {
959  // No opacity values were specified, so simply use the default equal share. Note that the
960  // mosaic may not even be of type ossimBlendMosaic:
961  weight = 100.0/num_entries; // default if no opacity specified
962  }
963 
964  iter->setWeight(weight);
965  iter++;
966  }
967 }
968 
969 //*************************************************************************************************
970 // METHOD
971 //*************************************************************************************************
972 void ossimOrthoIgen::setDefaultValues()
973 {
974  theBuildThumbnailFlag = false;
975  theDeltaPerPixelUnit = OSSIM_UNIT_UNKNOWN;
976  theDeltaPerPixelOverride.makeNan();
977  theTemplateView = "";
978  theProjectionType = OSSIM_UNKNOWN_PROJECTION;
979  theGeoScalingLatitude = ossim::nan();
980  theCombinerType = "ossimImageMosaic";
981  theResamplerType = "nearest neighbor";
982  theTilingTemplate = "";
983  theTilingFilename = "";
984  theSupplementaryDirectory = "";
985  theSlaveBuffers = "2";
986  clearFilenameList();
987  theLowPercentClip = ossim::nan();
988  theHighPercentClip = ossim::nan();
989  theCutOrigin.makeNan();
990  theCutDxDy.makeNan();
991  theCutOriginUnit = OSSIM_UNIT_UNKNOWN;
992  theCutDxDyUnit = OSSIM_UNIT_UNKNOWN;
993 
994  // PIXEL_IS_AREA HACK -- Set the assumed pixel alignment type to "area". Upon the first occurrence
995  // of a pixel-is-point entry, this property will revert to point. THIS NEEDS TO BE
996  // REMOVED WHEN THE EW GUI PROVIDES FOR THE USER TO SET THIS PROPERTY (OLK 09/11):
997  thePixelAlignment = OSSIM_PIXEL_IS_AREA; // not a default, but necessary for later logic
998 }
999 
1000 //*************************************************************************************************
1001 // Initializes the processing chain from the information on the command line
1002 //*************************************************************************************************
1003 void ossimOrthoIgen::setupIgenChain()
1004 {
1005  if (traceDebug())
1006  ossimNotify(ossimNotifyLevel_DEBUG)<< "ossimOrthoIgen::setupIgenChain DEBUG: Entered ..."<< std::endl;
1007 
1008  setupTiling();
1009 
1010  if (theSlaveBuffers == "")
1012  else
1013  theNumberOfTilesToBuffer = theSlaveBuffers.toLong();
1014 
1015  if(theProductFilename.empty())
1016  throw(ossimException(std::string("Must supply an output file.")));
1017 
1018  // Create the output mosaic object, to be connected to its inputs later:
1019  ossimKeywordlist templateKwl;
1020  templateKwl.clear();
1021  ossimRefPtr<ossimImageCombiner> mosaicObject = 0;
1022  ossimRefPtr<ossimImageCombiner> bandMergeObject = 0;
1023  if(theCombinerTemplate.exists())
1024  {
1025  templateKwl.addFile(theCombinerTemplate);
1026  mosaicObject = PTR_CAST(ossimImageCombiner,
1028  }
1029  if (!mosaicObject.valid())
1030  {
1031  mosaicObject = PTR_CAST(ossimImageCombiner,
1033  if(!mosaicObject.valid())
1034  {
1036  createObject(ossimString("ossimImageMosaic")));
1037  }
1038  }
1039 
1040  // Keep this pointer around for special processing if blend mosaic:
1041  ossimBlendMosaic* obm = PTR_CAST(ossimBlendMosaic, mosaicObject.get());
1042 
1043  // An orthomosaic implies that all input images are already orthorectified to a common projection
1044  // so the input chains do not require a renderer:
1045  bool orthoMosaic = (PTR_CAST(ossimOrthoImageMosaic, mosaicObject.get()) != 0);
1046 
1047  // Establish default individual input chain from template, if any:
1048  templateKwl.clear();
1049  ossimRefPtr<ossimImageChain> default_single_image_chain = 0;
1050  if(theChainTemplate.exists())
1051  {
1052  templateKwl.addFile(theChainTemplate);
1053  ossimObject* obj = 0;
1054  if(templateKwl.find("type"))
1055  obj = ossimObjectFactoryRegistry::instance()->createObject(templateKwl);
1056  else if(templateKwl.find("object1.type"))
1057  obj = ossimObjectFactoryRegistry::instance()->createObject(templateKwl, "object1.");
1058  default_single_image_chain = PTR_CAST(ossimImageChain, obj);
1059  }
1060  if(!default_single_image_chain.valid()) // then create a default rendering chain
1061  {
1062  default_single_image_chain = new ossimImageChain;
1063  {
1064  // Only need a renderer if an output projection or an explicit GSD was specified.
1065  if(!orthoMosaic)
1066  {
1067  ossimImageRenderer* renderer = new ossimImageRenderer;
1068  if (renderer->getResampler())
1069  renderer->getResampler()->setFilterType(theResamplerType);
1070  default_single_image_chain->addChild(renderer);
1071  }
1072  }
1073  }
1074 
1075  ossim_uint32 num_inputs = (ossim_uint32)theSrcRecords.size();
1076  ossim_uint32 idx;
1077  ossimString prefix ("object1.object");
1078  theReferenceProj = 0;
1079 
1080  // Loop over each input image file to establish a single image chain that will be added to the
1081  // output mosaic:
1082  ossimImageSource* current_source = 0;
1083  for(idx = 0; idx < num_inputs; ++idx)
1084  {
1085  // first lets add an input handler to the chain:
1086  ossimFilename input = theSrcRecords[idx].getFilename();
1088  if(!handler.valid())
1089  {
1090  ossimNotify(ossimNotifyLevel_WARN) << "Could not open input file <" << input << ">. "
1091  << "Skipping this entry." << std::endl;
1092  continue;
1093  }
1094 
1095  // Pass on any reader properties if there are any.
1096  ossimPropertyInterface* propInterface = (ossimPropertyInterface*)handler.get();
1097  PropertyMap::iterator iter = theReaderProperties.begin();
1098  while(iter != theReaderProperties.end())
1099  {
1100  propInterface->setProperty(iter->first, iter->second);
1101  ++iter;
1102  }
1103 
1104  // Presently, handler->loadState() is called only on vector data, though in the future we
1105  // should stuff many of the members in ossimSrcRecord in a KWL (similar to what is currently
1106  // done with vector properties) so that the handler is initialized via loadState() instead of
1107  // individual calls to set methods. OLK 10/10
1108  if (theSrcRecords[idx].isVectorData())
1109  handler->loadState(theSrcRecords[idx].getAttributesKwl());
1110 
1111  std::vector<ossim_uint32> entryList;
1112  if(theSrcRecords[idx].getEntryIndex() > -1 )
1113  entryList.push_back(theSrcRecords[idx].getEntryIndex());
1114  else
1115  handler->getEntryList(entryList);
1116 
1117  // Input image file may have multiple entries. Loop over each and establish single image
1118  // chains for each:
1119  ossim_uint32 entryIdx = 0;
1120  for(entryIdx = 0; entryIdx < entryList.size(); ++entryIdx)
1121  {
1122  // Instantiate the chain for one input image source. Copy existing default chain
1123  // which may already possess a renderer (so don't do any addFirst()!):
1124  ossimImageChain* singleImageChain = (ossimImageChain*) default_single_image_chain->dup();
1125 
1126  // Establish the image handler for this particular frame. This may be just
1127  // the handler already opened in the case of single image per file:
1128  ossimImageHandler* img_handler = 0;
1129  if (entryList.size() == 1)
1130  img_handler = handler.get();
1131  else
1132  img_handler = (ossimImageHandler*)handler->dup();
1133 
1134  // The user can specify an external "support" (a.k.a. supplementary directory) several ways
1135  if ( theSupplementaryDirectory.empty() == false )
1136  {
1137  img_handler->setSupplementaryDirectory( theSupplementaryDirectory );
1138  }
1139  else if (theSrcRecords[idx].getSupportDir().empty() == false)
1140  {
1141  img_handler->setSupplementaryDirectory(theSrcRecords[idx].getSupportDir());
1142  }
1143  else if (theSrcRecords[idx].getOverviewPath().empty() == false)
1144  {
1145  if (theSrcRecords[idx].getOverviewPath().isDir())
1146  img_handler->setSupplementaryDirectory(theSrcRecords[idx].getOverviewPath());
1147  else
1148  img_handler->setSupplementaryDirectory(theSrcRecords[idx].getOverviewPath().path());
1149  }
1150  img_handler->setCurrentEntry(entryList[entryIdx]);
1151  if ( img_handler->hasOverviews() )
1152  {
1153  img_handler->openOverview();
1154  }
1155  if (theSrcRecords[idx].isRgbData() && theSrcRecords[idx].getBands().size() > 0 &&
1156  theSrcRecords[idx].getOverviewPath().empty())
1157  {
1158  img_handler->setOutputBandList(theSrcRecords[idx].getBands());
1159  }
1160 
1161  // Image handler is ready to insert on the input side of the chain:
1162  singleImageChain->addLast(img_handler);
1163  current_source = img_handler;
1164 
1165  // PIXEL_IS_AREA HACK -- Scan the pixel alignment to see if all inputs are "area",
1166  // in which case we override the command-line writer property setting. THIS NEEDS TO BE
1167  // REMOVED WHEN THE EW GUI PROVIDES FOR THE USER TO SET THIS PROPERTY (OLK 09/11):
1168  if (img_handler->getPixelType() == OSSIM_PIXEL_IS_POINT)
1169  thePixelAlignment = OSSIM_PIXEL_IS_POINT;
1170 
1171  // This call will check for the presence of a raster mask file alongside the image,
1172  // and insert the mask filter in the chain if present:
1173  current_source = setupRasterMask(singleImageChain, theSrcRecords[idx]);
1174 
1175  // If this is the first input chain, use it as the reference projection to help with
1176  // the instantiation of the product projection (the view):
1177  if (!theReferenceProj.valid())
1178  {
1179  ossimRefPtr<ossimImageGeometry> geom = img_handler->getImageGeometry();
1180  if ( geom.valid() )
1181  theReferenceProj = geom->getProjection();
1182  }
1183 
1184  // Insert a partial-pixel flipper to remap null-valued pixels to min.
1185  // This is set via preference keyword "orthoigen.flip_null_pixels"
1186  current_source = setupPixelFlipper(singleImageChain, theSrcRecords[idx]);
1187 
1188  // Install a band selector if needed:
1189  if (theSrcRecords[idx].getBands().size() && (img_handler->getNumberOfOutputBands() > 1))
1190  {
1191  ossim_uint32 bands = img_handler->getNumberOfOutputBands();
1192  bool validBand = true;
1193  for (ossim_uint32 i = 0; i < theSrcRecords[idx].getBands().size(); ++i)
1194  {
1195  if (theSrcRecords[idx].getBands()[i] >= bands)
1196  {
1197  validBand = false;
1198  ossimNotify(ossimNotifyLevel_FATAL) << " ERROR:" << "\nBand list range error!"
1199  << "\nHighest available band: " << bands << std::endl;
1200  }
1201  }
1202  if (validBand)
1203  {
1205  singleImageChain->insertRight(bs.get(), current_source);
1206  bs->setOutputBandList(theSrcRecords[idx].getBands());
1207  current_source = bs.get();
1208  }
1209  }
1210 
1211  // Install a histogram object if needed. This inserts just to the left of the resampler.
1212  setupHistogram(singleImageChain, theSrcRecords[idx]);
1213 
1214  // Add a cache just to the left of the resampler.
1215  if (!theCacheExcludedFlag)
1216  addChainCache(singleImageChain);
1217 
1218  // Add the single image chain to the mosaic and save it to the product spec file:
1219  singleImageChain->makeUniqueIds();
1220 
1221  if (theSrcRecords[idx].isRgbData())
1222  {
1223  if (!bandMergeObject)
1224  {
1225  bandMergeObject = new ossimBandMergeSource();
1226  }
1227  bandMergeObject->connectMyInputTo(singleImageChain);
1228  singleImageChain->changeOwner(bandMergeObject.get());
1229  }
1230  else
1231  {
1232  mosaicObject->connectMyInputTo(singleImageChain);
1233  singleImageChain->changeOwner(mosaicObject.get());
1234  }
1235  //theContainer->addChild(singleImageChain);
1236 
1237  // Set the weight for this image when doing a blend mosaic:
1238  if (obm)
1239  obm->setWeight(idx, theSrcRecords[idx].getWeight());
1240  }
1241  }
1242 
1243  // Finished initializing the inputs to the mosaic. Add the mosaic to the product chain.
1245  if (bandMergeObject)
1246  {
1247  theProductChain->addFirst(bandMergeObject.get());
1248  }
1249  theProductChain->addFirst(mosaicObject.get());
1250 
1251  // Now need to pass the product chain through the histogram setup for possible remapper given
1252  // target histogram (used when histo-matching selected):
1253  setupHistogram();
1254 
1255  // When mosaicking common input projections without rendering each, need to add a renderer to the
1256  // mosaic for reprojecting to output projection:
1257  if(orthoMosaic)
1258  {
1259  ossimImageRenderer* renderer = new ossimImageRenderer;
1260  renderer->getResampler()->setFilterType(theResamplerType);
1261  theProductChain->addFirst(current_source);
1262  }
1263 
1264  //---
1265  // Now that "theProductChain" is initialized we must initialize elevation if needed as it can
1266  // affect the tie point of the output projection.
1267  //---
1268  if ( isAffectedByElevation() )
1269  {
1271 
1272  // Chain gsd's affected by elevation so recompute.
1273  reComputeChainGsds();
1274  }
1275 
1276  // Set up the output product's projection:
1277  setupProjection();
1278 
1279  // Annotation setup...
1280  setupAnnotation();
1281 
1282  // Output rect cutter:
1283  setupCutter();
1284 
1285  // Output radiometry filter:
1286  setupOutputRadiometry();
1287 
1288  // After all the connections have been established, add the product chain to the overall
1289  // product container. This container will also hold the writer object.
1291 
1292  // Lastly, set up the write object (object2):
1293  setupWriter();
1294 
1295 }
1296 
1297 //*************************************************************************************************
1298 // Initializes the Cut Rect filter to crop the mosaic to specified rectangle.
1299 // This method assumes that the view (theProductProjection) has already been propagated to all
1300 // the renderers (via call to setView()). This was done by prior call to setupProjection().
1301 //*************************************************************************************************
1302 void ossimOrthoIgen::setupCutter()
1303 {
1304  // The command line accepts cut rect specification in several formats. Consolidate them to
1305  // a common form (UL tiepoint <theCutOrigin> and distance to LR pixel center <theCutDxDy>. This
1306  // method also updates the product projection with new bounds:
1307  consolidateCutRectSpec();
1308 
1309  ossimImageSource* input_source = theProductChain->getFirstSource();
1310  if((theCutDxDy.hasNans()&&theMaskShpFile.empty())||!theProductProjection.valid()||!input_source)
1311  return;
1312 
1313  //user may pass the shape filename with an query (e.g C:/myshp.shp|select * from myshp),
1314  //parse the name of mask shape file here
1315  ossimString query = "";
1316  if (!theMaskShpFile.empty())
1317  {
1318  if (theMaskShpFile.contains("|"))
1319  {
1320  ossimString fileName = theMaskShpFile;
1321  std::vector<ossimString> fileList = fileName.split("|");
1322  if (fileList.size() > 1)
1323  {
1324  theMaskShpFile = fileList[0];
1325  query = fileList[1];
1326  }
1327  }
1328  }
1329 
1330  if (!theMaskShpFile.exists())
1331  {
1332  if (theCutOriginUnit == OSSIM_METERS) // projection in meters...
1333  {
1336  ossimDpt lr (theCutOrigin.x + theCutDxDy.x - mpp.x, theCutOrigin.y - theCutDxDy.y + mpp.y);
1337  cutter->setView(theProductProjection.get());
1338  cutter->setEastingNorthingRectangle(theCutOrigin, lr);
1339  theProductChain->addFirst(cutter);
1340  }
1341  else // geographic projection, units = decimal degrees.
1342  {
1343  ossimGeoPolyCutter* cutter = new ossimGeoPolyCutter;
1344  std::vector<ossimGpt> polygon;
1345 
1347  ossimGpt ul(theCutOrigin.lat, theCutOrigin.lon );
1348  ossimGpt ur(theCutOrigin.lat, theCutOrigin.lon + theCutDxDy.x - dpp.x);
1349  ossimGpt lr(theCutOrigin.lat - theCutDxDy.y + dpp.y, theCutOrigin.lon + theCutDxDy.x - dpp.x);
1350  ossimGpt ll(theCutOrigin.lat - theCutDxDy.y + dpp.y, theCutOrigin.lon );
1351 
1352  polygon.push_back(ul);
1353  polygon.push_back(ur);
1354  polygon.push_back(lr);
1355  polygon.push_back(ll);
1356 
1357  cutter->setView(theProductProjection.get());
1358  cutter->setNumberOfPolygons(1);
1359  cutter->setPolygon(polygon);
1360  theProductChain->addFirst(cutter);
1361  }
1362  }
1363  else
1364  {
1365  ossimIrect inputRect = input_source->getBoundingRect();
1366 
1367  ossimGeoPolyCutter* exteriorCutter = new ossimGeoPolyCutter;
1368  exteriorCutter->setView(theProductProjection.get());
1369 
1370  ossimGeoPolyCutter* interiorCutter = NULL;
1371 
1374  if (shpInterface != NULL)
1375  {
1376  if (!query.empty())
1377  {
1378  shpInterface->setQuery(query);
1379  }
1380  std::multimap<long, ossimAnnotationObject*> features = shpInterface->getFeatureTable();
1381  if (features.size() > 0)
1382  {
1383  std::multimap<long, ossimAnnotationObject*>::iterator it = features.begin();
1384  while (it != features.end())
1385  {
1386  ossimAnnotationObject* anno = it->second;
1387  if (anno != NULL)
1388  {
1390  ossimGeoAnnotationMultiPolyObject* annoMultiPoly = NULL;
1391  if (annoPoly == NULL)
1392  {
1393  annoMultiPoly = PTR_CAST(ossimGeoAnnotationMultiPolyObject, anno);
1394  }
1395  if (annoPoly != NULL)
1396  {
1397  std::vector<ossimGpt> polygon;
1398 
1399  //get the points of a polygon
1400  std::vector<ossimGpt> points = annoPoly->getPoints();
1401  for (ossim_uint32 i = 0; i < points.size(); i++)
1402  {
1403  polygon.push_back(points[i]);
1404  }
1405 
1406  //get polygon type, if it is an internal polygon, initialize the internal cutter
1409  {
1410  if (interiorCutter == NULL)
1411  {
1412  interiorCutter = new ossimGeoPolyCutter;
1413  interiorCutter->setView(theProductProjection.get());
1415  }
1416  interiorCutter->addPolygon(polygon);
1417  }
1418  else
1419  {
1420  exteriorCutter->addPolygon(polygon);
1421  }
1422  }
1423  else if (annoMultiPoly != NULL)
1424  {
1425  std::vector<ossimGeoPolygon> multiPolys = annoMultiPoly->getMultiPolygon();
1426  for (ossim_uint32 i = 0; i < multiPolys.size(); i++)
1427  {
1428  ossimGeoPolygon geoPoly = multiPolys[i];
1429  std::vector<ossimGeoPolygon> holePolys = geoPoly.getHoleList();
1430  if (holePolys.size() > 0)
1431  {
1432  if (interiorCutter == NULL)
1433  {
1434  interiorCutter = new ossimGeoPolyCutter;
1435  interiorCutter->setView(theProductProjection.get());
1437  }
1438  for (ossim_uint32 j = 0; j < holePolys.size(); j++)
1439  {
1440  interiorCutter->addPolygon(holePolys[j]);
1441  }
1442  }
1443  exteriorCutter->addPolygon(multiPolys[i]);
1444  }
1445  }
1446  else
1447  {
1448  throw(ossimException(std::string("The geometry type of the mask shape file is not polygon.")));
1449  }
1450  }
1451  it++;
1452  }
1453  }
1454  }
1455 
1456  //if user define the cut box, add it to the image chain
1457  ossimGeoPolyCutter* boundCutter = NULL;
1458  if (!theCutDxDy.hasNans() && !theCutOrigin.hasNans())
1459  {
1460  std::vector<ossimGpt> bound;
1461  if (theCutOriginUnit == OSSIM_METERS)
1462  {
1464  ossimGpt ul = theProductProjection->inverse(ossimDpt(theCutOrigin.x, theCutOrigin.y));
1465  ossimGpt ur = theProductProjection->inverse(ossimDpt(theCutOrigin.x + theCutDxDy.x - mpp.x, theCutOrigin.y));
1466  ossimGpt lr = theProductProjection->inverse(ossimDpt(theCutOrigin.x + theCutDxDy.x - mpp.x, theCutOrigin.y - theCutDxDy.y + mpp.y));
1467  ossimGpt ll = theProductProjection->inverse(ossimDpt(theCutOrigin.x, theCutOrigin.y - theCutDxDy.y + mpp.y));
1468 
1469  bound.push_back(ul);
1470  bound.push_back(ur);
1471  bound.push_back(lr);
1472  bound.push_back(ll);
1473  }
1474  else
1475  {
1477  ossimGpt ul(theCutOrigin.lat, theCutOrigin.lon );
1478  ossimGpt ur(theCutOrigin.lat, theCutOrigin.lon + theCutDxDy.x - dpp.x);
1479  ossimGpt lr(theCutOrigin.lat - theCutDxDy.y + dpp.y, theCutOrigin.lon + theCutDxDy.x - dpp.x);
1480  ossimGpt ll(theCutOrigin.lat - theCutDxDy.y + dpp.y, theCutOrigin.lon );
1481 
1482  bound.push_back(ul);
1483  bound.push_back(ur);
1484  bound.push_back(lr);
1485  bound.push_back(ll);
1486  }
1487  boundCutter = new ossimGeoPolyCutter;
1488 
1489  boundCutter->setView(theProductProjection.get());
1490  boundCutter->setNumberOfPolygons(1);
1491  boundCutter->setPolygon(bound);
1492  }
1493 
1494  if (boundCutter == NULL)
1495  {
1496  ossimIrect shpRect = shpHandler->getBoundingRect();
1497  if (shpRect.width() > inputRect.width() && shpRect.height() > inputRect.height())
1498  {
1499  exteriorCutter->setRectangle(inputRect);
1500  }
1501  }
1502 
1503  theProductChain->addFirst(exteriorCutter);
1504 
1505  if (interiorCutter != NULL)
1506  {
1507  theProductChain->addFirst(interiorCutter);
1508  }
1509 
1510  if (boundCutter != NULL)
1511  {
1512  theProductChain->addFirst(boundCutter);
1513  }
1514  }
1515 }
1516 
1517 //*************************************************************************************************
1518 // METHOD
1519 //*************************************************************************************************
1520 void ossimOrthoIgen::setupWriter()
1521 {
1522  if (!theProductChain.valid())
1523  return;
1524 
1526 
1527  if (theWriterType.size())
1528  {
1529  // User selected writer with -w or --writer option.
1530  writer = ossimImageWriterFactoryRegistry::instance()->createWriter(theWriterType);
1531  }
1532  else if ( theWriterTemplate.size() && theWriterTemplate.exists() )
1533  {
1534  // User sent us a writer template.
1535  ossimKeywordlist kwlTemplate;
1536  kwlTemplate.addFile(theWriterTemplate);
1537 
1538  // Try first with no prefix.
1540  if ( !writer.valid() )
1541  writer = ossimImageWriterFactoryRegistry::instance()->createWriter(kwlTemplate, "object2.");
1542  }
1543  else if ( theTilingFilename == "%SRTM%")
1544  {
1545  ossimKeywordlist kwlWriter;
1546  kwlWriter.add("type", "ossimGeneralRasterWriter", true);
1547  kwlWriter.add("byte_order", "big_endian");
1549  theProductFilename = theProductFilename.path();
1550  }
1551  else if (!theTilingFilename.empty())
1552  {
1553  if (theProductFilename.isDir())
1554  {
1555  theProductFilename = theProductFilename + "/" + theTilingFilename;
1556  }
1557  }
1558 
1559  try
1560  {
1561  //---
1562  // Set the output file name if not already set.
1563  // NOTE: Could be outputing to stdout in which case outputFilename does not
1564  // make sense. Leaving here though to not break code downstream. (drb)
1565  //---
1566  if ( theProductFilename == ossimFilename::NIL )
1567  {
1568  throw(ossimException(std::string("Writer output filename not set.")));
1569  }
1570 
1571  //---
1572  // Final check for writer.
1573  //---
1574  if ( !writer.valid() )
1575  {
1576  // Derive writer from the extension.
1577  ossimFilename ext = theProductFilename.ext();
1578  if ( ext.size() )
1580 
1581  //---
1582  // Lastly default to tiff. Perhaps throw exception here instead. (drb)
1583  //---
1584  if( !writer.valid() )
1585  {
1586  writer = new ossimTiffWriter;
1587  theProductFilename.setExtension("tif");
1588  }
1589  }
1590 
1591  // PIXEL_IS_AREA HACK: Temporary patch to override command line alignment type with source
1592  // image's alignment type. TO BE REMOVED ONCE EW GUI PROVIDES FOR USER-SETTING OF THIS
1593  // PROPERTY (OLK 09/11):
1594  if (thePixelAlignment == OSSIM_PIXEL_IS_AREA)
1595  {
1596  ossimString pixelType ("pixel_type");
1597  theWriterProperties.erase(pixelType);
1598  theWriterProperties.insert(std::make_pair(pixelType, ossimString("area")));
1599  }
1600 
1601  //---
1602  // Set writer filename, connect and add to writer to keyword list.
1603  //---
1604  if ( writer.valid() )
1605  {
1606  writer->setFilename(theProductFilename);
1607  writer->connectMyInputTo(0, theProductChain.get());
1608 
1609  ossimPropertyInterface* propInterface = (ossimPropertyInterface*)writer.get();
1610  PropertyMap::iterator iter = theWriterProperties.begin();
1611  while(iter != theWriterProperties.end())
1612  {
1613  propInterface->setProperty(iter->first, iter->second);
1614  ++iter;
1615  }
1616  theContainer->addChild(writer.get());
1617  }
1618  else
1619  {
1620  throw(ossimException(std::string("Unable to create writer.")));
1621  }
1622  }
1623  catch (const ossimException& e)
1624  {
1625  if (traceDebug())
1626  ossimNotify(ossimNotifyLevel_DEBUG) << e.what() << std::endl;
1627  throw; // re-throw exception
1628  }
1629 }
1630 
1631 
1632 //*************************************************************************************************
1633 // This method establishes the output (view) projection of the product.
1634 // NOTE: Completely rewritten to simplify and reduce redundancy. OLK 3/10
1635 //*************************************************************************************************
1636 void ossimOrthoIgen::setupProjection()
1637 {
1638  if (traceDebug())
1639  {
1640  ossimNotify(ossimNotifyLevel_DEBUG)<<"Entering ossimOrthoIgen::setupProjection():"<<std::endl;
1641  }
1642 
1644 
1645  // Throw exception if no valid input image projection was established:
1646  if(!theReferenceProj.valid())
1647  {
1648  std::string errMsg = "ossimOrthoIgen::setupProjection() -- Could not establish input image's "
1649  "projection. Cannot setup output view.";
1650  throw(ossimException(errMsg));
1651  }
1652 
1653  // Fetch the reference input projection first. Settings may be copied to the product projection:
1654  ossimMapProjection* ref_map = PTR_CAST(ossimMapProjection, theReferenceProj.get());
1655 
1656  // Now focus on establishing the output product projection.
1657  // Consider externally specified geometry first:
1658  if (theProjectionType == OSSIM_EXTERNAL_PROJECTION)
1659  {
1660  if (!theTemplateView.isReadable())
1661  {
1662  ossimString errMsg = "ossimOrthoIgen::setupProjection() -- Could not read the product "
1663  "projection template file at <";
1664  errMsg += theTemplateView;
1665  errMsg += ">. Cannot establish output projection.";
1666  throw(ossimException(errMsg));
1667  }
1668 
1669  // Default template format is no prefix, but consider alternate with prefix if first attempt
1670  // fails:
1671  ossimKeywordlist templateKwl (theTemplateView);
1673  ossimRefPtr<ossimObject> productObj = ofr->createObject(templateKwl, "product.projection.");
1674  if(!productObj.valid())
1675  productObj = ofr->createObject(templateKwl);
1677  }
1678 
1679  // Geographic? (Assuming WGS 84 for now.)
1680  else if (theProjectionType == OSSIM_GEO_PROJECTION)
1681  {
1683  ossimGpt gpt(0.0, 0.0);
1684  if (theGeoScalingLatitude == 999.0) // flags that lat is to be computed
1685  {
1686  computeGeoScalingLatitude();
1687  gpt = ossimGpt(theGeoScalingLatitude, 0.0);
1688  }
1689  else if (!ossim::isnan(theGeoScalingLatitude))
1690  gpt = ossimGpt(theGeoScalingLatitude, 0.0);
1692  }
1693 
1694  // CRS code specified on the command line
1695  else if (theProjectionType == OSSIM_SRS_PROJECTION)
1696  {
1697  ossimProjection* base_proj =
1699 
1702  {
1703  // Reassign the type for geographic. Now we know
1705  {
1706  theProjectionType = OSSIM_GEO_PROJECTION;
1707  ossimGpt gpt(0.0, 0.0);
1708  if (!ossim::isnan(theGeoScalingLatitude))
1709  gpt = ossimGpt(theGeoScalingLatitude, 0.0);
1711  }
1712  }
1713  else
1714  {
1715  theProjectionType = OSSIM_UNKNOWN_PROJECTION;
1717  << "ossimOrthoIgen::setupProjection() WARNING:" << " Unsupported spatial reference system."
1718  << " Will default to the projection from the input image."
1719  << std::endl;
1720  }
1721  }
1722 
1723  // UTM?
1724  else if (theProjectionType == OSSIM_UTM_PROJECTION)
1725  {
1727  ossimGpt refGpt;
1728  theReferenceProj->lineSampleToWorld(ossimDpt(0,0), refGpt);
1729 
1730  utm->setZone(refGpt);
1731  utm->setHemisphere(refGpt);
1732  theProductProjection = utm;
1733  }
1734 
1735  // None of the above?
1736  else
1737  {
1738  // Either OSSIM_INPUT_PROJECTION or OSSIM_UNKNOWN_PROJECTION. In both cases
1739  // just use the first image's input projection for the output. Need to make
1740  // sure the input_proj is a map projection though:
1741  if (ref_map)
1742  {
1744  theProjectionType = OSSIM_INPUT_PROJECTION; // just in case it was unknown before
1745  }
1746  else
1747  {
1748  theProjectionType = OSSIM_GEO_PROJECTION;
1750 
1751  ossimGpt gpt(0.0, 0.0);
1752  if (!ossim::isnan(theGeoScalingLatitude))
1753  gpt = ossimGpt(theGeoScalingLatitude, 0.0);
1755  }
1756  }
1757 
1758  // At this point there should be a valid output projection defined:
1759  if (!theProductProjection.valid())
1760  {
1761  std::string errMsg = "ossimOrthoIgen::setupProjection() -- Could not establish valid output "
1762  "projection";
1763  throw(ossimException(errMsg));
1764  }
1765 
1766  // HACK (OLK 06/10): The projection may not have had the PCS code initialized even though it
1767  // is an EPSG projection, so take this opportunity to identify a PCS for output:
1769  if (pcs_code == 0)
1770  {
1772  findProjectionCode(*(theProductProjection.get()));
1773  theProductProjection->setPcsCode(pcs_code);
1774  }
1775 
1776  // Bootstrap the process of establishing the mosaic tiepoint by setting it to the reference proj.
1777  if (ref_map)
1778  theProductProjection->setUlGpt(ref_map->getUlGpt());
1779 
1780  // cout << "ref_map->getUlGpt(): " << ref_map->getUlGpt() << endl;
1781 
1782  // Base class makes sure the product view projection is properly wired into the chain.
1783  setView();
1784 
1785  // Set the desired image GSD. This is nontrivial due to the many ways GSD can be implied and/or
1786  // explicitly provided. This method also does a setView before returning:
1787  setProductGsd();
1788 
1789  theProjectionName = theProductProjection->getProjectionName();
1790 
1791  // At this point, the product projection will not have a tiepoint (UL corner coordinates)
1792  // defined unless it is the same projection as the input reference. Need to set it now. Note that
1793  // if a cut-rect is specified, the tie-point will be modified later in setupCutter()
1794  establishMosaicTiePoint();
1795 
1796  if (traceDebug())
1797  {
1799  << "ossimOrthoIgen::setupProjection DEBUG:"
1800  << "Leaving...." << __LINE__
1801  << std::endl;
1802  }
1803 }
1804 
1805 //*************************************************************************************************
1806 // METHOD
1807 //*************************************************************************************************
1808 void ossimOrthoIgen::setupAnnotation()
1809 {
1810  ossimImageSource* input_source = theProductChain->getFirstSource();
1811  if (!input_source)
1812  return;
1813 
1814  if(theAnnotationTemplate.exists() == false)
1815  return;
1816 
1817  ossimKeywordlist templateKwl;
1818  if (templateKwl.addFile(theAnnotationTemplate) == false)
1819  return;
1820 
1822  createObject(templateKwl, "object1.");
1823  if (obj.valid())
1824  {
1826  if (oga)
1827  {
1830  theProductChain->addFirst(oga);
1831  }
1832  }
1833  return;
1834 }
1835 
1836 //*************************************************************************************************
1837 // Set up multi-file tiling if indicated on the command line.
1838 //*************************************************************************************************
1839 bool ossimOrthoIgen::setupTiling()
1840 {
1841  if(traceDebug())
1842  {
1843  ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimOrthoIgen::setupTiling: Entered......" << std::endl;
1844  }
1845  ossimKeywordlist templateKwl;
1846  ossimFilename outputFilename = theProductFilename;
1847  theTilingEnabled = false;
1848 
1849  if ((theTilingTemplate == "")||(!templateKwl.addFile(theTilingTemplate)))
1850  {
1851  if(traceDebug())
1852  {
1853  ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimOrthoIgen::setupTiling: Leaving......" << __LINE__ << std::endl;
1854  }
1855  return false;
1856  }
1857 
1858  ossimString prefix ("igen.tiling.");
1859  while (1)
1860  {
1861  if(outputFilename.isDir())
1862  {
1863  if(templateKwl.find(prefix.chars(), "type"))
1864  {
1865  theTilingFilename = templateKwl.find(prefix.chars(),"tile_name_mask");
1866  theTilingEnabled = true;
1867  break;
1868  }
1869  else if (templateKwl.find(prefix.chars(), "tile_size") || templateKwl.find(prefix.chars(), "tile_source"))
1870  {
1871  theTilingFilename = templateKwl.find(prefix.chars(),"output_file_name");
1872  theTilingEnabled = true;
1873  break;
1874  }
1875  }
1876  else
1877  {
1878  theTilingFilename = outputFilename.file();
1879  if (!theTilingFilename.contains("%"))
1880  {
1881  ossimString fileNoExt = theTilingFilename.fileNoExtension();
1882  ossimString ext = theTilingFilename.ext();
1883  theTilingFilename = fileNoExt + "_%r%_%c%." + ext;
1884  }
1885  if(templateKwl.find(prefix.chars(), "type"))
1886  {
1887  templateKwl.add(prefix.chars(), "tile_name_mask", theTilingFilename.c_str(), true);
1888  ossimFilename path (outputFilename.path());
1889  theProductFilename = path;
1890  theTilingEnabled = true;
1891  break;
1892  }
1893  else if (templateKwl.find(prefix.chars(), "tile_size") || templateKwl.find(prefix.chars(), "tile_source"))
1894  {
1895  templateKwl.add(prefix.chars(), "output_file_name", theTilingFilename.c_str(), true);
1896  ossimFilename path (outputFilename.path());
1897  theProductFilename = path;
1898  theTilingEnabled = true;
1899  break;
1900  }
1901  }
1902 
1903  // If we got here, then no matches were found in the template. Try again but without a prefix:
1904  if (prefix.empty())
1905  break;
1906  prefix.clear();
1907  }
1908 
1909  // Initialize the tiling object if enabled:
1910  if (templateKwl.find(prefix.chars(), "tile_size"))
1911  {
1912  theTiling = 0;
1913  theTiling = new ossimTilingRect;
1914  }
1915 
1916  if (templateKwl.find(prefix.chars(), "tile_source"))
1917  {
1918  theTiling = 0;
1919  theTiling = new ossimTilingPoly;
1920  }
1921 
1922  if (theTilingEnabled && !theTiling->loadState(templateKwl, prefix))
1923  theTilingEnabled = false;
1924 
1925  if(traceDebug())
1926  {
1927  ossimNotify(ossimNotifyLevel_DEBUG) << "ossimOrthoIgen::setupTiling: templateKwl = \n" << templateKwl << std::endl;
1928  ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimOrthoIgen::setupTiling: Leaving......" << __LINE__ << std::endl;
1929  }
1930 
1931  return true;
1932 }
1933 
1934 //*************************************************************************************************
1935 // Consolidates specification of bounding rect given various ways of specifying on the command
1936 // line. This avoids multiple, redundant checks scattered throughout the code. On exit:
1937 //
1938 // 1. theCutOriginType is converted to OSSIM_UPPER_LEFT_ORIGIN
1939 // 2. theCutOrigin is converted to the proper coordinates (lat/lon or easting/northing) and
1940 // associated theCutOriginUnits is assigned accordingly.
1941 // 3. theCutDxDy reflects the full size of the rect, in the units corresponding to the projection
1942 // and associated theCutDxDyUnit is set to METERS for UTM, DEGREES for geographic
1943 // 4. The product projection's origin (image center) and tie point are updated to reflect the
1944 // output rectangle.
1945 //
1946 //*************************************************************************************************
1947 void ossimOrthoIgen::consolidateCutRectSpec()
1948 {
1949  if (!theProductProjection.valid() || theCutDxDy.hasNans() || theCutOrigin.hasNans())
1950  return;
1951 
1952  if ((theCutDxDyUnit != OSSIM_METERS) &&
1953  (theCutDxDyUnit != OSSIM_DEGREES) &&
1954  (theCutDxDyUnit != OSSIM_UNIT_UNKNOWN))
1955  {
1956  ossimNotify(ossimNotifyLevel_WARN) << "ossimOrthoIgen::consolidateCutRectSpec: An unhandled"
1957  " type of units was encountered. The cut rect needs to be specified in either meters or"
1958  " degrees. The resulting cut rect and origin may be incorrect." << std::endl;
1959  return;
1960  }
1961 
1962  ossimGpt originPLH;
1963  ossimDpt resolution;
1964 
1965  // Geographic Projection (lat/lon cut rect) requested?
1967  {
1968  // geographic projection; units need to be decimal degrees. First check for consistent origin:
1969  if (theCutOriginUnit == OSSIM_METERS)
1970  {
1971  originPLH = theProductProjection->inverse(theCutOrigin);
1972  theCutOrigin.x = originPLH.lon;
1973  theCutOrigin.y = originPLH.lat;
1974  }
1975  else
1976  {
1977  originPLH.lat = theCutOrigin.y;
1978  originPLH.lon = theCutOrigin.x;
1979  }
1980 
1981  // Check for consistent rect size:
1982  if (theCutDxDyUnit == OSSIM_METERS)
1983  {
1984  ossimDpt mtrs_per_deg (originPLH.metersPerDegree());
1985  theCutDxDy.x = theCutDxDy.x/mtrs_per_deg.x;
1986  theCutDxDy.y = theCutDxDy.y/mtrs_per_deg.y;
1987  }
1988 
1989  // Set these to the correct units. May already be correct, but just in case...
1990  theCutOriginUnit = OSSIM_DEGREES;
1991  theCutDxDyUnit = OSSIM_DEGREES;
1992 
1993  if (theClipToValidRectFlag)
1994  {
1995  // Now we need to clip the cut rect by the valid image footprint for the entire mosaic:
1996  ossimDrect boundingRect = theProductChain->getBoundingRect(); // in view coordinates
1997 
1998  // The bounding rect is in image space. Since pixel-is-point, the actual valid area on the
1999  // ground will extend 1/2 pixel beyond the centers, so grow the bounding rect by 1/2 p:
2000  boundingRect.expand(ossimDpt(0.5, 0.5));
2001  ossimGpt mosaic_ul, mosaic_lr;
2002  theProductProjection->lineSampleHeightToWorld(boundingRect.ul(), 0, mosaic_ul);
2003  theProductProjection->lineSampleHeightToWorld(boundingRect.lr(), 0, mosaic_lr);
2004 
2005  // Establish the LR bound defined by the cut-rect and clip the cut-rect if necessary:
2006  ossimGpt cutrect_lr (theCutOrigin.lat - theCutDxDy.lat, theCutOrigin.lon + theCutDxDy.lon);
2007  if (mosaic_ul.lat < theCutOrigin.lat)
2008  theCutOrigin.lat = mosaic_ul.lat;
2009  if (mosaic_lr.lat > cutrect_lr.lat)
2010  theCutDxDy.lat = theCutOrigin.lat - mosaic_lr.lat;
2011  if (mosaic_ul.lon > theCutOrigin.lon)
2012  theCutOrigin.lon = mosaic_ul.lon;
2013  if (mosaic_lr.lon < cutrect_lr.lon)
2014  theCutDxDy.lon = mosaic_lr.lon - theCutOrigin.lon;
2015  }
2016 
2018  }
2019 
2020  // Map Projection (easting, northing cut rect) requested?
2021  else
2022  {
2023  // Special case code to account for origin and delta being specified in geographic, leading to
2024  // offset error due to northing difference between UL and UR corners at constant lat:
2025  if ((theCutOriginType == OSSIM_UPPER_LEFT_ORIGIN) &&
2026  (theCutOriginUnit == OSSIM_DEGREES) && (theCutDxDyUnit == OSSIM_DEGREES))
2027  {
2028  ossimGpt ulgp (theCutOrigin.lat , theCutOrigin.lon , 0);
2029  ossimGpt urgp (theCutOrigin.lat , theCutOrigin.lon + theCutDxDy.lon, 0);
2030  ossimGpt llgp (theCutOrigin.lat - theCutDxDy.lat, theCutOrigin.lon , 0);
2031  ossimGpt lrgp (theCutOrigin.lat - theCutDxDy.lat, theCutOrigin.lon + theCutDxDy.lon, 0);
2032 
2033  ossimDpt ulen (theProductProjection->forward(ulgp));
2034  ossimDpt uren (theProductProjection->forward(urgp));
2035  ossimDpt llen (theProductProjection->forward(llgp));
2036  ossimDpt lren (theProductProjection->forward(lrgp));
2037 
2038  double n_top = (ulen.y > uren.y ? ulen.y : uren.y);
2039  double n_bottom = (llen.y < lren.y ? llen.y : lren.y);
2040  double e_left = (ulen.x < llen.x ? ulen.x : llen.x);
2041  double e_right = (uren.x > lren.x ? uren.x : lren.x);
2042 
2043  theCutOrigin.x = e_left;
2044  theCutOrigin.y = n_top;
2045 
2046  theCutDxDy.x = e_right - e_left;
2047  theCutDxDy.y = n_top - n_bottom;
2048 
2049  if (theClipToValidRectFlag)
2050  {
2051  // Now we need to clip the cut rect by the valid image footprint for the entire mosaic:
2052  ossimDrect boundingRect = theProductChain->getBoundingRect(); // in view coordinates
2053  boundingRect.expand(ossimDpt(0.5, 0.5));
2054  ossimDpt mosaic_ul, mosaic_lr;
2055  theProductProjection->lineSampleToEastingNorthing(boundingRect.ul(), mosaic_ul);
2056  theProductProjection->lineSampleToEastingNorthing(boundingRect.lr(), mosaic_lr);
2057 
2058  // Establish the LR bound defined by the cut-rect and clip the cut-rect if necessary:
2059  ossimDpt cutrect_lr (theCutOrigin.x + theCutDxDy.x, theCutOrigin.y - theCutDxDy.y);
2060  if (mosaic_ul.y < theCutOrigin.y)
2061  theCutOrigin.y = mosaic_ul.y;
2062  if (mosaic_lr.y > cutrect_lr.y)
2063  theCutDxDy.y = theCutOrigin.y - mosaic_lr.y;
2064  if (mosaic_ul.x > theCutOrigin.x)
2065  theCutOrigin.x = mosaic_ul.x;
2066  if (mosaic_lr.x < cutrect_lr.x)
2067  theCutDxDy.x = mosaic_lr.x - theCutOrigin.x;
2068  }
2069  }
2070  else
2071  {
2072  // Just map the geographic coordinates to easting/northing, without regard to corner
2073  // mismatch:
2074  if (theCutOriginUnit == OSSIM_DEGREES)
2075  {
2076  originPLH.lat = theCutOrigin.y;
2077  originPLH.lon = theCutOrigin.x;
2078  theCutOrigin = theProductProjection->forward(originPLH);
2079  }
2080  else
2081  {
2082  // Determine the geographic position that might be needed for scaling below:
2083  originPLH = theProductProjection->inverse(theCutOrigin);
2084  }
2085 
2086  // Check for consistent rect size:
2087  if (theCutDxDyUnit == OSSIM_DEGREES)
2088  {
2089  // POTENTIAL BUG: conversion from degrees longitude to meters should be a function
2090  // of latitude here. Implemented here but needs testing:
2091  ossimDpt mtrs_per_deg (originPLH.metersPerDegree());
2092  theCutDxDy.x = theCutDxDy.x * mtrs_per_deg.x;
2093  theCutDxDy.y = theCutDxDy.y * mtrs_per_deg.y;
2094  }
2095  }
2096 
2097  // Set these to the correct units. May already be correct, but just in case...
2098  theCutOriginUnit = OSSIM_METERS;
2099  theCutDxDyUnit = OSSIM_METERS;
2100 
2101  resolution = theProductProjection->getMetersPerPixel();
2102  }
2103 
2104  // The cut rect corresponds to the edges of the pixel ("edge-to-edge"), while OSSIM considers
2105  // coordinates to correspond to the pixel centers. Need to shift the origin to the SE by 1/2p:
2106  ossimDpt half_pixel = resolution * 0.5;
2107  theCutOrigin.y -= half_pixel.y;
2108  theCutOrigin.x += half_pixel.x;
2109 
2110  // The size of the cutrect needs to be an integral number of pixels in output space:
2111  theCutDxDy.x = (floor(theCutDxDy.x/resolution.x + 0.5))* resolution.x;
2112  theCutDxDy.y = (floor(theCutDxDy.y/resolution.y + 0.5))* resolution.y;
2113 
2114  // Adjust a center origin specification to be Upper Left corner:
2115  if (theCutOriginType == OSSIM_CENTER_ORIGIN)
2116  {
2117  theCutOrigin.y += theCutDxDy.y;
2118  theCutOrigin.x -= theCutDxDy.x;
2119 
2120  // theCutDxDy in this case represented a radius. This needs to be converted to
2121  // OSSIM_UPPER_LEFT_ORIGIN form:
2122  theCutDxDy.x *= 2.0;
2123  theCutDxDy.y *= 2.0;
2124  theCutOriginType = OSSIM_UPPER_LEFT_ORIGIN;
2125  }
2126 
2127  // Finally, update the product projection with new rectangle:
2128  ossimDpt cutCenter (theCutOrigin.x + theCutDxDy.x/2.0, theCutOrigin.y - theCutDxDy.y/2.0);
2129  ossimGpt gpt;
2130  if (theCutDxDyUnit == OSSIM_METERS)
2131  {
2132  // Set the E/N values for the cut origin as the tie point:
2133  theProductProjection->setUlTiePoints(theCutOrigin);
2134  }
2135  else
2136  {
2137  // Set the projection center (origin) latitude at the center of the cut rect:
2138  gpt.lat = cutCenter.y;
2139  gpt.lon = 0.0;
2141 
2142  // Set the lat/lon values for the cut origin as the tie point:
2143  gpt.lat = theCutOrigin.y;
2144  gpt.lon = theCutOrigin.x;
2146  }
2147 
2148  // cout << "\n**************** proj 2:\n";
2149  // theProductProjection->print(cout);
2150 
2151  // Propagates changes to the projection to the processing chain:
2152  setView();
2153 }
2154 
2155 //*************************************************************************************************
2157 //*************************************************************************************************
2158 void ossimOrthoIgen::setupHistogram(ossimImageChain* input_chain, const ossimSrcRecord& src_record)
2159 {
2160  // Check if the source passed in is the output mosaic object, because the target
2161  // histogram remapper needs to be connected to it (only valid when histo matching is requested):
2162  if (input_chain == NULL)
2163  {
2164  if (!theTargetHistoFileName.isReadable())
2165  return;
2166 
2168  remapper->openHistogram(theTargetHistoFileName);
2169  theProductChain->addFirst(remapper);
2170  return;
2171  }
2172 
2173  // Check if any histo operation was requested on individual image:
2174  if ((ossim::isnan(theHighPercentClip) || ossim::isnan(theLowPercentClip)) &&
2175  !theUseAutoMinMaxFlag && (theStdDevClip < 0) && src_record.getHistogramOp().empty() &&
2176  theTargetHistoFileName.empty())
2177  {
2178  return; // no histo op requested
2179  }
2180 
2181  // Remaining operations require a histogram on the input image source:
2182  ossimImageHandler* handler = PTR_CAST(ossimImageHandler, input_chain->getLastSource());
2183  if (handler == NULL)
2184  {
2185  ossimNotify(ossimNotifyLevel_FATAL)<<"Could not locate an image handler object in the image"
2186  << "chain provided. This should not happen. Ignoring histogram request." << std::endl;
2187  return;
2188  }
2189 
2190  // Establish the ideal filename for this histogram. The following do-block is all for testing
2191  // different histogram file naming schemes since alternate directory and entry-indexing might be
2192  // used:
2193  ossimFilename histoFilename (src_record.getHistogramPath());
2194  ossimFilename candidateHistoFilename;
2195  ossimFilename defaultHistoFilename (handler->createDefaultHistogramFilename());
2196  ossimFilename entryName (handler->getFilenameWithThisExtension(ossimString(".his"), true));
2197 
2198  do
2199  {
2200  if (!histoFilename.empty())
2201  {
2202  // Try histogram filename based on specified name in the .src file:
2203  if (histoFilename.isDir())
2204  histoFilename = histoFilename.dirCat(defaultHistoFilename.file());
2205  if (histoFilename.exists()) break;
2206 
2207  // Try specified name with entry index:
2208  if (src_record.getEntryIndex() >= 0)
2209  {
2210  histoFilename = histoFilename.path().dirCat(entryName.file());
2211  if (histoFilename.exists()) break;
2212  }
2213 
2214  // Not found so set the candidate filename in case we need to generate it:
2215  candidateHistoFilename = histoFilename;
2216  }
2217 
2218  // Next try looking for a histogram based on the default name:
2219  histoFilename = defaultHistoFilename;
2220  if (histoFilename.exists()) break;
2221 
2222  //---
2223  // Last possibility is the default name with entry index. We will test
2224  // even if there is only one entry, like "file_e0.his".
2225  //---
2226  histoFilename = entryName;
2227  if (histoFilename.exists()) break;
2228 
2229  // If not already set, set the candidate filename in case we need to generate it:
2230  if (candidateHistoFilename.empty())
2231  candidateHistoFilename = histoFilename;
2232  }
2233  while (false); // only pass through once
2234 
2235 
2236  // If the histogram was still not located, look into creating one:
2237  if (!histoFilename.exists())
2238  {
2239  // Check the preferences for histogram autogeneration:
2240  ossimString lookup = ossimPreferences::instance()->findPreference(AUTOGENERATE_HISTOGRAM_KW);
2241  if (lookup.toBool())
2242  {
2243  // No histogram available for this image, need to create one:
2244  histoFilename = candidateHistoFilename;
2245  ossimNotify(ossimNotifyLevel_WARN) <<"Histogram file <" << histoFilename
2246  << "> not found. Creating one now..." << std::endl;
2247  bool success = createHistogram(input_chain, histoFilename);
2248  if (!success)
2249  {
2250  ossimNotify(ossimNotifyLevel_WARN) <<"Error encountered creating histogram file <"
2251  << histoFilename << ">. Ignoring histogram request." << std::endl;
2252  return;
2253  }
2254  }
2255  }
2256 
2257  // Need to insert any histogram object to the left of the renderer in the chain. Search for a
2258  // renderer and save for later:
2259  // ossimConnectableObject* renderer = PTR_CAST(ossimConnectableObject,
2260  // input_chain->findFirstObjectOfType(ossimString("ossimImageRenderer")));
2261 
2262  ossimTypeNameVisitor visitor( ossimString("ossimImageRenderer"),
2263  true, // firstofTypeFlag
2266  input_chain->accept( visitor );
2267  ossimRefPtr<ossimImageRenderer> renderer = visitor.getObjectAs<ossimImageRenderer>(0);
2268 
2269  // Histo Match?
2270  if (theTargetHistoFileName.isReadable())
2271  {
2272  // A histogram match was requested. This involves applying a histo equalization to the input
2273  // chain and then applying an inverted equalization using the target histogram:
2276 
2277  // Init equalizers with the source and target histogram files:
2278  forwardEq->setInverseFlag(false);
2279  forwardEq->setHistogram(histoFilename);
2280  inverseEq->setInverseFlag(true);
2281  inverseEq->setHistogram(theTargetHistoFileName);
2282 
2283  // Need check that source and target histograms are compatible:
2284  ossimRefPtr<ossimMultiResLevelHistogram> sourceHisto = forwardEq->getHistogram();
2285  ossimRefPtr<ossimMultiResLevelHistogram> targetHisto = inverseEq->getHistogram();
2286  bool are_incompatible = false;
2287  if (!sourceHisto.valid() || !targetHisto.valid())
2288  {
2289  are_incompatible = true;
2290  }
2291  else
2292  {
2293  ossim_uint32 num_source_bands = sourceHisto->getNumberOfBands();
2294  if (num_source_bands != targetHisto->getNumberOfBands())
2295  {
2296  are_incompatible = true;
2297  }
2298  else
2299  {
2300  for (ossim_uint32 band=0; band<num_source_bands; band++)
2301  {
2302  ossimRefPtr<ossimHistogram> sourceBandHisto = sourceHisto->getHistogram(band);
2303  ossimRefPtr<ossimHistogram> targetBandHisto = targetHisto->getHistogram(band);
2304  if (!sourceBandHisto.valid() || !targetBandHisto.valid() ||
2305  (sourceBandHisto->GetRes() != targetBandHisto->GetRes()))
2306  {
2307  are_incompatible = true;
2308  break;
2309  }
2310  }
2311  }
2312  }
2313  if (are_incompatible)
2314  {
2315  // Error was encountered establishing histograms for match operation:
2316  ossimNotify(ossimNotifyLevel_WARN)<<"Error encountered setting up histogram match "
2317  "operation. Check that source and target histograms are compatible. No histogram "
2318  "operations will be performed on this image." << std::endl;
2319  return;
2320  }
2321 
2322  // The source and target histos are compatible, insert to the left of renderer if one exists:
2323  if ( renderer.valid() )
2324  input_chain->insertLeft( forwardEq.get(), renderer.get() );
2325  else
2326  input_chain->addFirst(forwardEq.get());
2327  input_chain->insertRight(inverseEq.get(), forwardEq.get());
2328 
2329  return;
2330  }
2331 
2332  // Remaining possibilities (clip or stretch) require a remapper.
2333  // Insert to the left of renderer if one exists:
2335  if ( renderer.valid() )
2336  input_chain->insertLeft( remapper.get(), renderer.get() );
2337  else
2338  input_chain->addFirst(remapper.get());
2339 
2340  // Fetch the input histogram:
2341  bool histo_read_ok = remapper->openHistogram(histoFilename);
2342  if (!histo_read_ok)
2343  {
2344  // No histogram available for this image, need to create one (TODO):
2345  ossimNotify(ossimNotifyLevel_WARN)<<"Error encountered loading histogram file <"
2346  << histoFilename << ">. No histogram operations will be performed on this image."
2347  << std::endl;
2348  return;
2349  }
2350 
2351  // Set values to construct remap table:
2352  if (!ossim::isnan(theHighPercentClip) && !ossim::isnan(theLowPercentClip))
2353  {
2354  // Hi/Lo clip requested
2355  remapper->setHighNormalizedClipPoint(1.0-theHighPercentClip);
2356  remapper->setLowNormalizedClipPoint(theLowPercentClip);
2357  }
2358 
2359  else
2360  {
2361  // Consider histogram stretch operations. These can be on a per-image basis or global for all
2362  // input images. Give priority to the img_histo_op (per-image spec) over general flags below:
2364  ossimString img_histo_op (src_record.getHistogramOp());
2365  if (img_histo_op=="auto-minmax")
2367  else if (img_histo_op.contains("std-stretch"))
2368  {
2369  if (img_histo_op.contains("1"))
2371  else if (img_histo_op.contains("2"))
2373  else if (img_histo_op.contains("3"))
2375  }
2376  else if (theUseAutoMinMaxFlag)
2378  else if (theStdDevClip > 0)
2379  mode = (ossimHistogramRemapper::StretchMode) theStdDevClip;
2380 
2381  // Finally init the remapper with proper stretch mode:
2383  remapper->setStretchMode(mode, true);
2384  }
2385 
2386  return;
2387 }
2388 
2389 
2390 //*************************************************************************************************
2392 //*************************************************************************************************
2393 bool ossimOrthoIgen::createHistogram(ossimImageChain* chain, const ossimFilename& histo_filename)
2394 {
2397 
2398  histoSource->connectMyInputTo(chain);
2399  histoSource->enableSource();
2401 
2402  writer->connectMyInputTo(histoSource.get());
2403  writer->setFilename(histo_filename);
2404  writer->addListener(&theStdOutProgress);
2405  bool success = writer->execute();
2406 
2407  writer=0;
2408  histoSource=0;
2409 
2410  if (success)
2411  {
2413  }
2414  else
2415  {
2416  ossimNotify(ossimNotifyLevel_WARN)<<"Error encountered creating Histogram file <"
2417  << histo_filename << ">. No histogram operations will be performed on this image."
2418  << std::endl;
2419  }
2420 
2421  return success;
2422 }
2423 
2424 //*************************************************************************************************
2425 // METHOD
2426 //*************************************************************************************************
2427 void ossimOrthoIgen::addChainCache(ossimImageChain* chain) const
2428 {
2429  if (chain)
2430  {
2431  //ossimConnectableObject* renderer =
2432  // PTR_CAST(ossimConnectableObject,
2433  // chain->findFirstObjectOfType(ossimString("ossimImageRenderer")));
2434 
2435  ossimTypeNameVisitor visitor( ossimString("ossimImageRenderer"),
2436  true, // firstofTypeFlag
2439  chain->accept( visitor );
2440  ossimRefPtr<ossimImageRenderer> renderer = visitor.getObjectAs<ossimImageRenderer>(0);
2441  if ( renderer.valid() )
2442  {
2444  chain->insertLeft( cache, renderer.get() );
2445  }
2446  }
2447 }
2448 
2449 //*************************************************************************************************
2450 // Generates a log KWL file that could be fed directly to Igen. Used for verifying chain.
2451 //*************************************************************************************************
2452 void ossimOrthoIgen::generateLog()
2453 {
2454  if (!theSrcRecords.size() || !theProductChain.valid() || theProductFilename.empty())
2455  return;
2456 
2457  // Establish output filename:
2458  ossimFilename logFile = theProductFilename;
2459  logFile.setExtension("log");
2460 
2461  // Fill a KWL with all info:
2462  ossimKeywordlist kwl;
2463  theContainer->saveState(kwl);
2464 
2466  theProductProjection->saveState(kwl, "product.projection.");
2467 
2468  kwl.write(logFile.chars());
2469 }
2470 
2471 //*************************************************************************************************
2474 //*************************************************************************************************
2475 void ossimOrthoIgen::establishMosaicTiePoint()
2476 {
2477  if (!theProductChain.valid())
2478  return;
2479 
2480  // Need to find all image handlers to query for their UL ground point:
2481 #if 0
2483  theProductChain->findAllInputsOfType(clientList, STATIC_TYPE_INFO(ossimImageHandler), true, true);
2484 
2485  if (clientList.size() == 0)
2486  {
2487  ossimNotify(ossimNotifyLevel_WARN)<<"ossimOrthoIgen::establishMosaicTiePoint() WARNING -- "
2488  "Expected to find image handler in the chain but none was identified."<<std::endl;
2489  return;
2490  }
2491 #endif
2492 
2493  ossimTypeNameVisitor visitor( ossimString("ossimImageHandler"),
2494  false, // firstofTypeFlag
2497  theProductChain->accept( visitor );
2498 
2499  if ( visitor.getObjects().empty() )
2500  {
2501  ossimNotify(ossimNotifyLevel_WARN)<<"ossimOrthoIgen::establishMosaicTiePoint() WARNING -- "
2502  "Expected to find image handler in the chain but none was identified."<<std::endl;
2503  return;
2504  }
2505 
2506  ossimGpt tie_gpt_i, tie_gpt;
2507  ossimDpt tie_dpt_i, tie_dpt;
2508  tie_gpt.makeNan();
2509  tie_gpt.height(0.0);
2510  tie_dpt.makeNan();
2511 
2512  // Loop over all input handlers and latch the most NW tiepoint as the mosaic TP:
2513  // ossimConnectableObject::ConnectableObjectList::iterator iter = clientList.begin();
2514  // while (iter != clientList.end())
2515  for( ossim_uint32 i = 0; i < visitor.getObjects().size(); ++i )
2516  {
2517  // ossimImageHandler* handler = PTR_CAST(ossimImageHandler, (*iter).get());
2518  // iter++;
2519 
2520  ossimImageHandler* handler = visitor.getObjectAs<ossimImageHandler>( i );
2521  if (!handler) break;
2522 
2524  if (!geom.valid())
2525  continue; // Skip over any non geometry inputs (e.g., masks)
2526 
2528  {
2529  geom->getTiePoint( tie_gpt_i, true ); // True to get edge of tie.
2530  if ( tie_gpt_i.hasNans() == false )
2531  {
2532  if (tie_gpt.hasNans())
2533  tie_gpt = tie_gpt_i;
2534  else
2535  {
2536  if (tie_gpt_i.lat > tie_gpt.lat)
2537  tie_gpt.lat = tie_gpt_i.lat;
2538  if (tie_gpt_i.lon < tie_gpt.lon)
2539  tie_gpt.lon = tie_gpt_i.lon;
2540  }
2541  }
2542  }
2543  else
2544  {
2545  geom->getTiePoint( tie_dpt_i, true ); // True to get edge of tie.
2546  if ( tie_dpt_i.hasNans() == false )
2547  {
2548  if (tie_dpt.hasNans())
2549  tie_dpt = tie_dpt_i;
2550  else
2551  {
2552  if (tie_dpt_i.y > tie_dpt.y)
2553  tie_dpt.y = tie_dpt_i.y;
2554  if (tie_dpt_i.x < tie_dpt.x)
2555  tie_dpt.x = tie_dpt_i.x;
2556  }
2557  }
2558  }
2559  }
2560 
2561 #if 0
2562  // Establish input image bounding rect, making sure to expand to include the FULL pixel since
2563  // pixel is point -- i.e. the pixel coordinate corresponds to the center of the pixel area,
2564  // not the edge. Therefore shift the image point by 1/2 pixel to correspond to edges:
2565  // (OLK 09/11)
2566  ossimDrect boundingRect (handler->getBoundingRect());
2567  vector<ossimDpt> img_vertices;
2568  img_vertices.push_back(boundingRect.ul() + ossimDpt(-0.5, -0.5));
2569  img_vertices.push_back(boundingRect.ur() + ossimDpt( 0.5, -0.5));
2570  img_vertices.push_back(boundingRect.lr() + ossimDpt( 0.5, 0.5));
2571  img_vertices.push_back(boundingRect.ll() + ossimDpt(-0.5, 0.5));
2572 
2573 
2574  // The tie point will be in easting/northing or lat/lon depending on the type of projection
2575  // used for the product. Need to consider all image corners since the orientation of the image
2576  // is not known:
2577  for (int j=0; j<4; j++)
2578  {
2579  geom->localToWorld(img_vertices[j], tie_gpt_i);
2581  {
2582  tie_gpt.height(0.0);
2583  if (tie_gpt.hasNans())
2584  tie_gpt = tie_gpt_i;
2585  else
2586  {
2587  if (tie_gpt_i.lat > tie_gpt.lat)
2588  tie_gpt.lat = tie_gpt_i.lat;
2589  if (tie_gpt_i.lon < tie_gpt.lon)
2590  tie_gpt.lon = tie_gpt_i.lon;
2591  }
2592  }
2593  else
2594  {
2595  tie_dpt_i = theProductProjection->forward(tie_gpt_i);
2596  if (tie_dpt.hasNans())
2597  tie_dpt = tie_dpt_i;
2598  else
2599  {
2600  if (tie_dpt_i.y > tie_dpt.y)
2601  tie_dpt.y = tie_dpt_i.y;
2602  if (tie_dpt_i.x < tie_dpt.x)
2603  tie_dpt.x = tie_dpt_i.x;
2604  }
2605  }
2606  }
2607  }
2608 
2609 #endif
2610 
2611  // The tie point coordinates currently reflect the UL edge of the UL pixel. We'll need to shift
2612  // the tie point from the edge to the center. (OLK 09/11)
2613  ossimDpt half_pixel_shift(0,0);
2614  if (theProductProjection->isGeographic())
2615  {
2616  half_pixel_shift = theProductProjection->getDecimalDegreesPerPixel() * 0.5;
2617  if (!tie_gpt.hasNans())
2618  {
2619  tie_gpt.lat -= half_pixel_shift.lat;
2620  tie_gpt.lon += half_pixel_shift.lon;
2621  theProductProjection->setUlTiePoints(tie_gpt);
2622  }
2623  }
2624  else
2625  {
2626  half_pixel_shift = theProductProjection->getMetersPerPixel() * 0.5;
2627  tie_dpt.y -= half_pixel_shift.y;
2628  tie_dpt.x += half_pixel_shift.x;
2629  theProductProjection->setUlTiePoints(tie_dpt);
2630  }
2631 
2632  // Propagates changes to the projection to the processing chain:
2633  setView();
2634 }
2635 
2636 //*************************************************************************************************
2638 //*************************************************************************************************
2639 void ossimOrthoIgen::computeGeoScalingLatitude()
2640 {
2641  if (!theProductChain.valid())
2642  return;
2643 
2644  // Need to find all image handlers to query for their UL ground point:
2645  ossimTypeNameVisitor visitor( ossimString("ossimImageHandler"),
2646  false, // firstofTypeFlag
2649  theProductChain->accept( visitor );
2650  if ( visitor.getObjects().empty() )
2651  {
2652  ossimNotify(ossimNotifyLevel_WARN)<<"ossimOrthoIgen::establishMosaicTiePoint() WARNING -- "
2653  "Expected to find image handler in the chain but none was identified."<<std::endl;
2654  return;
2655  }
2656 
2657  ossimGpt ul_i, ur_i, lr_i, ll_i;
2658  ossimGrect bbox;
2659  bbox.makeNan();
2660 
2661  // Loop over all input handlers and latch the extremes of the corner points:
2662  for (ossim_uint32 i = 0; i < visitor.getObjects().size(); ++i)
2663  {
2664  ossimImageHandler* handler = visitor.getObjectAs<ossimImageHandler>(i);
2665  if (!handler)
2666  break;
2667 
2669  if (!geom.valid())
2670  continue; // Skip over any non geometry inputs (e.g., masks)
2671 
2672  geom->getCornerGpts(ul_i, ur_i, lr_i, ll_i);
2673  ossimGrect bbox_i(ul_i, ur_i, lr_i, ll_i);
2674  bbox = bbox.combine(bbox_i);
2675  }
2676 
2677  // Fetch midpoint and assign scaling latitude:
2678  ossimGpt midPoint (bbox.midPoint());
2679  if (!midPoint.isLatNan())
2680  theGeoScalingLatitude = midPoint.lat;
2681  else
2682  theGeoScalingLatitude = 0.0;
2683 }
2684 
2685 //*************************************************************************************************
2686 // Initialize the pixel flipper in the source chain if one is called for
2687 //*************************************************************************************************
2688 ossimImageSource* ossimOrthoIgen::setupPixelFlipper(ossimImageChain* singleImageChain,
2689  const ossimSrcRecord& src_record)
2690 {
2691  if (singleImageChain == NULL)
2692  return NULL;
2693 
2694  // Fetch the image handler that should be the last (left-most) source in the chain:
2695  ossimImageSource* current_source = singleImageChain->getLastSource();
2696  if (current_source == NULL)
2697  return NULL;
2698 
2699  // There are two possibilities for specifying pixel flipping -- either as a command line option
2700  // that applies to all input imagery, or specified for a particular input via the .src file.
2701  // The .src file takes precedence:
2702  const ossimSrcRecord::PixelFlipParams& flipParams = src_record.getPixelFlipParams();
2703 
2704  // The replacement can be specified globally in the preferences if none found in the src record:
2705  ossimString replaceModeStr = flipParams.replacementMode;
2706  if (replaceModeStr.empty())
2707  replaceModeStr = thePixelReplacementMode;
2708 
2709  // First consider if a range of clipped pixels was specified:
2710  ossim_float64 clip_min = flipParams.clipMin;
2711  if (ossim::isnan(clip_min))
2712  clip_min = theClipPixelMin;
2713  ossim_float64 clip_max = flipParams.clipMax;
2714  if (ossim::isnan(clip_max))
2715  clip_max = theClipPixelMax;
2716 
2717  ossimPixelFlipper* flipper = 0;
2718  if (!ossim::isnan(clip_min) && !ossim::isnan(clip_max))
2719  {
2720  // A clip within a range of pixel values was requested. All pixels within the specified range
2721  // are mapped to NULL. Create the remapper and insert it into the chain just after the handler
2722  flipper = new ossimPixelFlipper();
2723  flipper->setTargetRange(clip_min, clip_max);
2724  flipper->setReplacementValue(current_source->getNullPixelValue());
2725  flipper->setReplacementMode(replaceModeStr);
2726  singleImageChain->insertRight(flipper, current_source);
2727  current_source = flipper;
2728  }
2729 
2730  // The user can also specify a clamping similar to the pixel clipping above. This would be a
2731  // second flipper object in the chain:
2732  ossim_float64 clamp_min = flipParams.clampMin;
2733  if (ossim::isnan(clamp_min))
2734  clamp_min = theClampPixelMin;
2735  ossim_float64 clamp_max = flipParams.clampMax;
2736  if (ossim::isnan(clamp_max))
2737  clamp_max = theClampPixelMax;
2738 
2739  flipper = 0; // no leak since chain assumes ownership of prior instance.
2740  if (!ossim::isnan(clamp_min))
2741  {
2742  // A bottom clamping was requested. All pixels below this value are set to this value:
2743  flipper = new ossimPixelFlipper();
2744  flipper->setClampValue(clamp_min, false); // false = clamp bottom
2745  }
2746  if (!ossim::isnan(clamp_max))
2747  {
2748  // A top clamping was requested. All pixels above this value are set to this value.
2749  // The same flipper object can be used as the bottom clamp (if created):
2750  if (!flipper)
2751  flipper = new ossimPixelFlipper();
2752  flipper->setClampValue(clamp_max, true); // true = clamp top
2753  }
2754  if (flipper)
2755  {
2756  // Common code for top and bottom clamping:
2757  flipper->setReplacementMode(replaceModeStr);
2758  singleImageChain->insertRight(flipper, current_source);
2759  current_source = flipper;
2760  }
2761 
2762  return current_source;
2763 }
2764 
2765 //*************************************************************************************************
2766 // Checks for the presence of a raster mask file alongside the image, and inserts the mask
2767 // filter in the chain if mask file exists. Returns pointer to the "current (last added) source
2768 // in the single image chain.
2769 //*************************************************************************************************
2770 ossimImageSource* ossimOrthoIgen::setupRasterMask(ossimImageChain* singleImageChain,
2771  const ossimSrcRecord& src_record)
2772 {
2773  if (singleImageChain == NULL)
2774  return NULL;
2775 
2776  // Search for the image handler in the chain:
2777  ossimImageHandler* img_handler =
2778  dynamic_cast<ossimImageHandler*>(singleImageChain->getLastSource());
2779  if (img_handler == NULL)
2780  return NULL;
2781 
2782  // See if a raster mask was specified in the SRC record:
2783  ossimFilename mask_file = src_record.getMaskPath();
2784  if (!mask_file.exists())
2785  return img_handler;
2786 
2787  // Open up the mask file and verify it is good:
2788  ossimImageHandler* mask_handler = ossimImageHandlerRegistry::instance()->open(mask_file);
2789  if (mask_handler == NULL)
2790  {
2791  ossimNotify(ossimNotifyLevel_WARN)<<"ossimOrthoIgen::setupRasterMask() -- Could not open "
2792  "raster mask file <"<<mask_file<<">. Maske request will be ignored."<<endl;
2793  return img_handler;
2794  }
2795 
2796  // Create the mask filter and give it the image and mask tile sources. Add it to the chain.
2797  // IMPORTANT NOTE: the mask filter is an image combiner. It is being inserted into a single
2798  // image chain. Since it owns its two inputs (the image handler and the mask), it must
2799  // replace the handler in the chain. Also, see note in ossimMaskFilter::setInputSources().
2800  //singleImageChain->deleteLast(); // Remove the handler
2801  // ossimImageSource* nextInChain = singleImageChain->getLastSource();
2803  singleImageChain->insertRight(mask_filter.get(), img_handler);
2804  mask_filter->setMaskSource(mask_handler); // assumes ownership of object
2805 
2806  //---
2807  // Set the mode to SELECT_CLAMP_MIN. This clamps data to min pixel value in the valid image
2808  // area if the input pixel is null(essentially a pixel flip).
2809  //---
2811 
2812  return mask_filter.get();
2813 }
2814 
2815 //*************************************************************************************************
2816 // Adds a scalar remapper to the extreme right of the chain is specified by the
2817 // --output-radiometry option.
2818 //*************************************************************************************************
2819 void ossimOrthoIgen::setupOutputRadiometry()
2820 {
2821  if (theOutputRadiometry.empty())
2822  return;
2823 
2824  // Map the specified radiometry to a valid type:
2825  ossimScalarType scalar_type =
2826  ossimScalarTypeLut::instance()->getScalarTypeFromString(theOutputRadiometry);
2827  if (scalar_type == OSSIM_SCALAR_UNKNOWN)
2828  return;
2829 
2830  // Add a scalar remapper to the product chain:
2831  if(theProductChain->getOutputScalarType() != scalar_type)
2832  {
2833  ossimScalarRemapper* remapper = new ossimScalarRemapper;
2834  remapper->setOutputScalarType(scalar_type);
2835  theProductChain->addFirst(remapper);
2836  }
2837 }
2838 
2839 //*************************************************************************************************
2840 // Private method to see if any image chain input projections are affected by elevation.
2841 //*************************************************************************************************
2842 bool ossimOrthoIgen::isAffectedByElevation()
2843 {
2844  bool result = false;
2845 
2846  // Get a list of all the image handlers.
2847  // ossimConnectableObject::ConnectableObjectList clientList;
2848  // theProductChain->findAllInputsOfType(clientList, STATIC_TYPE_INFO(ossimImageHandler),
2849  // true, true);
2850 
2851  ossimTypeNameVisitor visitor( ossimString("ossimImageHandler"),
2852  false, // firstofTypeFlag
2855  theProductChain->accept( visitor );
2856 
2857  // Loop over all input handlers and see if affected by elevation.
2858  // ossimConnectableObject::ConnectableObjectList::iterator iter = clientList.begin();
2859  // while (iter != clientList.end())
2860  for( ossim_uint32 i = 0; i < visitor.getObjects().size(); ++i )
2861  {
2862  // ossimRefPtr<ossimImageHandler> handler = PTR_CAST(ossimImageHandler, (*iter).get());
2863  ossimRefPtr<ossimImageHandler> handler = visitor.getObjectAs<ossimImageHandler>( i );
2864  if ( handler.valid() )
2865  {
2867  if (geom.valid())
2868  {
2870  if ( proj.valid() )
2871  {
2872  if ( proj->isAffectedByElevation() )
2873  {
2874  result = true;
2875  break;
2876  }
2877  }
2878  }
2879  }
2880  // ++iter;
2881  }
2882  return result;
2883 }
2884 
2885 //*************************************************************************************************
2886 // Private method to recompute the gsd on all image handlers that have projections affected by
2887 // elevation.
2888 //*************************************************************************************************
2889 void ossimOrthoIgen::reComputeChainGsds()
2890 {
2891  // Get a list of all the image handlers.
2892  // ossimConnectableObject::ConnectableObjectList clientList;
2893  // theProductChain->findAllInputsOfType(clientList, STATIC_TYPE_INFO(ossimImageHandler),
2894  // true, true);
2895 
2896  // Loop over all input handlers and see if affected by elevation.
2897  // ossimConnectableObject::ConnectableObjectList::iterator iter = clientList.begin();
2898  // while (iter != clientList.end())
2899 
2900  ossimTypeNameVisitor visitor( ossimString("ossimImageHandler"),
2901  false, // firstofTypeFlag
2904  theProductChain->accept( visitor );
2905 
2906  for( ossim_uint32 i = 0; i < visitor.getObjects().size(); ++i )
2907  {
2908  // ossimRefPtr<ossimImageHandler> handler = PTR_CAST(ossimImageHandler, (*iter).get());
2909 
2910  ossimRefPtr<ossimImageHandler> handler = visitor.getObjectAs<ossimImageHandler>( i );
2911  if ( handler.valid() )
2912  {
2914  if (geom.valid())
2915  {
2917  if ( proj.valid() )
2918  {
2919  if ( proj->isAffectedByElevation() )
2920  proj->getMetersPerPixel();
2921  }
2922  }
2923  }
2924  // ++iter;
2925  }
2926 }
2927 
2928 //*************************************************************************************************
2929 // GSD Determination is nontrivial since there are various command-line options that control
2930 // this quantity. This method considers all information before setting the product's GSD.
2931 //*************************************************************************************************
2932 void ossimOrthoIgen::setProductGsd()
2933 {
2934  if (!theProductChain.valid())
2935  return;
2936 
2937  // Fetch the reference input projection first. Settings may be copied to the product projection:
2938  ossimMapProjection* ref_map = PTR_CAST(ossimMapProjection, theReferenceProj.get());
2939  ossimGpt origin;
2940 
2941  // The geo-scaling latitude effectively specifies the map projection's origin latitude, which
2942  // may affect the scaling of GSD in x-direction. This is only relevant for geographic projections
2944  {
2945  ossimGpt origin (0.0, theProductProjection->getOrigin().lon, 0.0);
2946  if (ossim::isnan(theGeoScalingLatitude))
2947  {
2948  // Loop over all input handlers and accumulate the geographic centers. This will allow
2949  // computing mosaic center point (approximate) for purposes of establishing reference
2950  // latitude for scale:
2951  origin.lat = 0.0;
2952  origin.lon = theProductProjection->getOrigin().lon;
2953 
2954  // ossimConnectableObject::ConnectableObjectList clientList;
2955  // theProductChain->findAllInputsOfType(clientList, STATIC_TYPE_INFO(ossimImageHandler), 1, 1);
2956  // ossimConnectableObject::ConnectableObjectList::iterator iter = clientList.begin();
2957 
2958  ossimTypeNameVisitor visitor( ossimString("ossimImageHandler"),
2959  false, // firstofTypeFlag
2962  theProductChain->accept( visitor );
2963 
2964  ossimDpt center_pt;
2965  ossimGpt geocenter;
2966  int num_contributors = 0;
2967  // while (iter != clientList.end())
2968 
2969  for( ossim_uint32 i = 0; i < visitor.getObjects().size(); ++i )
2970  {
2971  // ossimImageHandler* handler = PTR_CAST(ossimImageHandler, (*iter).get());
2972  ossimRefPtr<ossimImageHandler> handler = visitor.getObjectAs<ossimImageHandler>( i );
2973  if ( handler.valid() )
2974  {
2975  // iter++;
2977  if (!geom.valid())
2978  continue; // Skip over any non geometry inputs (e.g., masks)
2979 
2980  handler->getBoundingRect().getCenter(center_pt);
2981  if (!geom->localToWorld(center_pt, geocenter))
2982  continue;
2983  if (num_contributors == 0)
2984  origin.lat = geocenter.lat;
2985  else
2986  origin.lat += geocenter.lat;
2987  ++num_contributors;
2988  }
2989  else
2990  {
2991  break;
2992  }
2993  }
2994 
2995  // Compute average latitude among all contributors:
2996  if (num_contributors)
2997  origin.lat /= (double)num_contributors;
2998  }
2999  else
3000  {
3001  // A geo-scaling reference latitude was provided on the command line:
3002  origin.lat = theGeoScalingLatitude;
3003  }
3004 
3005  // Set the latitude of origin to the reference latitude (either specified on command line or
3006  // computed as scene center):
3007  theProductProjection->setOrigin(origin); // proj now can handle meters and degrees correctly
3008  }
3009 
3010  // Establish the resolution based on either command line option or reference proj if no values
3011  // provided on command line (--degrees or --meters):
3012  ossimDpt resolution (theDeltaPerPixelOverride);
3013  ossimUnitType resUnits = theDeltaPerPixelUnit;
3014  if (resolution.hasNans())
3015  {
3016  // No GSD specified, so copy it from the input projection:
3017  if (ref_map && ref_map->isGeographic())
3018  {
3019  resolution = ref_map->getDecimalDegreesPerPixel();
3020  resUnits = OSSIM_DEGREES;
3021  }
3022  else
3023  {
3024  resolution = theReferenceProj->getMetersPerPixel();
3025  resUnits = OSSIM_METERS;
3026  }
3027  }
3028 
3029  // Set the desired image GSD, accounting for possible mixing of units:
3030  if (resUnits == OSSIM_DEGREES)
3031  {
3032  // Need to adjust the resolution in the longitude direction if the user requested geo-scaling:
3033  if (!ossim::isnan(theGeoScalingLatitude))
3034  resolution.lon = resolution.lat/ossim::cosd(theGeoScalingLatitude);
3036  }
3037  else
3039 
3040  // Propagates changes to the projection to the processing chain:
3041  setView();
3042 }
Class used for parsing the command line *.src files.
void clear()
Erases the entire container.
Definition: ossimString.h:432
virtual const ossimDpt & getDecimalDegreesPerPixel() const
Returns decimal degrees per pixel as an ossimDpt with "x" representing longitude and "y" representing...
virtual bool addListener(ossimListener *listener)
ossimImageFileWriter * createWriterFromExtension(const ossimString &fileExtension) const
virtual ossimIrect getBoundingRect(ossim_uint32 resLevel=0) const
This will return the bounding rect of the source.
ossim_int32 getEntryIndex() const
void addCommandLineOption(const ossimString &option, const ossimString &explanation)
virtual ossimObject * dup() const =0
virtual std::vector< ossimGpt > getPoints()
ossimString before(const ossimString &str, std::string::size_type pos=0) const
METHOD: before(str, pos) Returns string beginning at pos and ending one before the token str If strin...
virtual void makeUniqueIds()
Will cycle through all sources setting their ids.
ossimRefPtr< ossimHistogram > getHistogram(ossim_uint32 band, ossim_uint32 resLevel=0)
virtual void setQuery(const ossimString &query)=0
Pure virtual setQuery method.
bool addLast(ossimConnectableObject *obj)
Adds it to the end.
void setComputationMode(ossimHistogramMode mode)
ossimScalarType getScalarTypeFromString(const ossimString &s) const
ossimString getRgbHistogramOp(int band) const
virtual void setPolygon(const vector< ossimDpt > &polygon, ossim_uint32 i=0)
static const ossimFilename NIL
This was taken from Wx widgets for performing touch and access date stamps.
Definition: ossimFilename.h:40
virtual ossimImageSource * getFirstSource()
Return the first source which is the one that first receives the getTile request. ...
virtual ossimImageHandler * open(const ossimFilename &fileName, bool trySuffixFirst=true, bool openOverview=true) const
open that takes a filename.
This will be a base for all combiners.
ossimUnitType
Represents serializable keyword/value map.
bool addFile(const char *file)
virtual ossim_uint32 getNumberOfOutputBands() const
Returns the number of bands in a tile returned from this TileSource.
bool valid() const
Definition: ossimRefPtr.h:75
const ossimFilename & getMaskPath() const
const char * find(const char *key) const
void makeNan()
Definition: ossimGrect.h:284
ossimFilename getRgbOverviewPath(int band) const
virtual ossim_uint32 getPcsCode() const
Returns the EPSG PCS code or 32767 if the projection is a custom (non-EPSG) projection.
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
void setHighNormalizedClipPoint(const ossim_float64 &clip)
Sets the high clip point.
bool read(const std::string &str)
search for an occurance of a string in the argument list, on sucess remove that occurance from the li...
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
This code was derived from https://gist.github.com/mshockwave.
Definition: Barrier.h:8
virtual void setHistogram(ossimRefPtr< ossimMultiResLevelHistogram > histogram)
const ossimDpt & ul() const
Definition: ossimDrect.h:339
double y
Definition: ossimDpt.h:165
virtual void setOrigin(const ossimGpt &origin)
Sets theOrigin to origin.
ossim_uint32 height() const
Definition: ossimIrect.h:487
bool contains(char aChar) const
Definition: ossimString.h:58
static ossimImageWriterFactoryRegistry * instance()
void makeNan()
Definition: ossimGpt.h:130
virtual bool isGeographic() const
void split(std::vector< ossimString > &result, const ossimString &separatorList, bool skipBlankFields=false) const
Splits this string into a vector of strings (fields) using the delimiter list specified.
void setEastingNorthingRectangle(const ossimDpt &ul, const ossimDpt &lr)
static ossimObjectFactoryRegistry * instance()
bool insertRight(ossimConnectableObject *newObj, ossimConnectableObject *rightOfThisObj)
virtual void setDecimalDegreesPerPixel(const ossimDpt &gsd)
bool getCornerGpts(ossimGpt &ul, ossimGpt &ur, ossimGpt &lr, ossimGpt &ll) const
Assigns the ossimGpts with the ground coordinates of the four corresponding image corner points...
OSSIM_DLL ossimStdOutProgress theStdOutProgress
ossimRefPtr< ossimConnectableContainer > theContainer
Definition: ossimIgen.h:55
ossimApplicationUsage * getApplicationUsage()
virtual ossimRefPtr< ossimMultiResLevelHistogram > getHistogram()
virtual void setGeometry(ossimImageGeometry *projection)
virtual ossimImageSource * getLastSource()
Return the last source which is the one that last receives the getTile request.
bool isDir() const
An image mosaic is a simple combiner that will just do a simple mosaic.
ossimFilename getRgbFilename(int band) const
void setClampValue(ossim_float64 clamp_value, bool is_high_clamp_value=true)
virtual bool write(const char *file, const char *comment=0) const
Methods to dump the ossimKeywordlist to a file on disk.
std::vector< ossimGeoPolygon > & getHoleList()
const ossimDrect & expand(const ossimDpt &padding)
Definition: ossimDrect.cpp:493
virtual ossimGpt inverse(const ossimDpt &projectedPoint) const =0
Will take a point in meters and convert it to ground.
bool theBuildThumbnailFlag
Definition: ossimIgen.h:60
virtual bool openOverview()
Searches for an overview.
const PixelFlipParams & getPixelFlipParams() const
ossimRefPtr< ossimMapProjection > theProductProjection
Definition: ossimIgen.h:56
int numberOfParams(const std::string &str, const ossimParameter value) const
void setReplacementMode(ossimPixelFlipper::ReplacementMode mode)
void setFilterType(ossimFilterResamplerType filterType)
virtual void setUlGpt(const ossimGpt &ulGpt)
virtual void setMetersPerPixel(const ossimDpt &gsd)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
void initializeElevation()
Definition: ossimInit.cpp:825
ossimRefPtr< ossimImageChain > theProductChain
Definition: ossimIgen.h:57
virtual ossimScalarType getOutputScalarType() const
This call is passed to the head of the list.
ossim_int32 toInt32() const
virtual void accept(ossimVisitor &visitor)
We will add a visitor interface for all connectable objects.
void setStretchMode(StretchMode mode, bool rebuildTableFlag=false)
Sets remap mode to mode.
double ossim_float64
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
int GetRes() const
virtual void setNumberOfPolygons(ossim_uint32 count)
static ossimScalarTypeLut * instance()
Returns the static instance of an ossimScalarTypeLut object.
std::vector< ossimRefPtr< ossimConnectableObject > > ConnectableObjectList
virtual void changeOwner(ossimObject *owner)
Permits changing the object&#39;s owner.
void setEntryIndex(ossim_int32 i)
double lat
Definition: ossimDpt.h:165
virtual bool setView(ossimObject *baseObject)
virtual void setOutputScalarType(ossimScalarType scalarType)
Sets the output scalar type.
const char * findPreference(const char *key) const
void setFilename(const ossimFilename &f)
yy_size_t size
bool exists() const
ossim_float64 lon
Definition: ossimGpt.h:266
virtual ossimRefPtr< ossimImageGeometry > getImageGeometry()
Returns the image geometry object associated with this tile source or NULL if non defined...
bool localToWorld(const ossimDpt &local_pt, ossimGpt &world_pt) const
Exposes the 3D projection from image to world coordinates.
ossim_uint32 theThreadCount
Definition: ossimIgen.h:67
virtual const char * what() const
Returns the error message.
virtual void setPcsCode(ossim_uint32 pcsCode)
virtual void lineSampleToEastingNorthing(const ossimDpt &liineSample, ossimDpt &eastingNorthing) const
std::string::size_type size() const
Definition: ossimString.h:405
static ossimEpsgProjectionDatabase * instance()
Instantiates singleton instance of this class:
bool toBool() const
String to numeric methods.
virtual void initialize(const ossimKeywordlist &kwl)
Definition: ossimIgen.cpp:247
virtual ossimDpt getMetersPerPixel() const =0
virtual ossimString getProjectionName() const
Returns the projection name.
ossimRefPtr< ossimTiling > theTiling
Definition: ossimIgen.h:58
unsigned int ossim_uint32
const char * chars() const
For backward compatibility.
Definition: ossimString.h:77
Cache Tile Source.
double height() const
Definition: ossimGpt.h:107
#define STATIC_TYPE_INFO(T)
Definition: ossimRtti.h:319
#define PTR_CAST(T, p)
Definition: ossimRtti.h:321
const std::vector< ossimGeoPolygon > & getMultiPolygon() const
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
ossimPixelType getPixelType() const
Returns the raster pixel alignment type.
ossimObject * createObject(const ossimString &objectType)
Definition: kwl.cpp:64
virtual void enableSource()
Definition: ossimSource.cpp:84
virtual ossim_int32 connectMyInputTo(ossimConnectableObject *inputObject, bool makeOutputConnection=true, bool createEventFlag=true)
Will try to connect this objects input to the passed in object.
virtual void addPolygon(const vector< ossimIpt > &polygon)
ossim_uint32 width() const
Definition: ossimIrect.h:500
double cosd(double x)
Definition: ossimCommon.h:259
virtual void getEntryList(std::vector< ossim_uint32 > &entryList) const
bool hasNans() const
Definition: ossimDpt.h:67
double lon
Definition: ossimDpt.h:164
ossimFilename getRgbHistogramPath(int band) const
virtual const ossimGpt & getUlGpt() const
static ossimPreferences * instance()
ossimIpt theThumbnailSize
Definition: ossimIgen.h:61
ossimFilterResampler * getResampler()
long theNumberOfTilesToBuffer
Definition: ossimIgen.h:62
const ossimFilename & getHistogramPath() const
Container class that holds both 2D transform and 3D projection information for an image Only one inst...
ossimScalarType
ossim_uint32 getNumberOfBands(ossim_uint32 resLevel=0) const
const ossimGpt & getOrigin() const
ossimGpt midPoint() const
Definition: ossimGrect.h:178
bool isReadable() const
void setZone(const ossimGpt &ground)
virtual ossimDpt forward(const ossimGpt &worldPoint) const =0
All map projections will convert the world coordinate to an easting northing (Meters).
virtual bool addChild(ossimConnectableObject *attachableObject)
Will add an object to the container and then set the added objects owner to this. ...
bool isRgbData() const
Returns TRUE if the record represents an rgb data set:
void setWeight(ossim_uint32 index, double weight)
void setSupportDir(const ossimFilename &f)
Sets supplementary data files dir.
virtual ossimIrect getBoundingRect(ossim_uint32 resLevel=0) const
Will pass this call to the head of the list.
virtual bool setView(ossimObject *baseObject)
virtual void setFilename(const ossimFilename &file)
const ossimProjection * getProjection() const
Access methods for projection (may be NULL pointer).
virtual void setInverseFlag(bool inverseFlag)
ossimGrect combine(const ossimGrect &rect) const
Definition: ossimGrect.h:213
void setTargetRange(ossim_float64 target_min, ossim_float64 target_max)
Instead of a single value for a target, this method allows for specifying a range of values to flip t...
if(yy_init)
bool theTilingEnabled
Definition: ossimIgen.h:64
void setView()
Initializes all clients of the view projection to the current product projection. ...
Definition: ossimIgen.cpp:653
bool valid() const
Returns TRUE if record is valid.
virtual bool addChild(ossimConnectableObject *attachableObject)
void setReplacementValue(ossim_float64 replacement_value)
void getTiePoint(ossimGpt &tie, bool edge) const
Get the latitude, longitude of the tie point.
virtual void setMaskType(ossimFileSelectionMaskType type)
Sets the mask type.
This class defines an abstract Handler which all image handlers(loaders) should derive from...
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
bool hasNans() const
Definition: ossimGpt.h:135
ossim_int32 y
Definition: ossimIpt.h:142
Class to scan pixels and flip target dn value to a replacement dn value.
virtual void setProperty(const ossimString &name, const ossimString &value)
const ossimDpt & ur() const
Definition: ossimDrect.h:340
virtual void setOutputBandList(const vector< ossim_uint32 > &outputBandList, bool disablePassThru=false)
Sets the output band list.
void setHistogramOp(const ossimString &s)
bool isVectorData() const
Returns TRUE if the record represents a vector data set:
double x
Definition: ossimDpt.h:164
virtual ossimObject * createObject(const ossimString &name) const
ossimFilename dirCat(const ossimFilename &file) const
bool empty() const
Definition: ossimString.h:411
virtual ossimProjection * createProjection(const ossimFilename &filename, ossim_uint32 entryIdx) const
STUB. Not implemented.
virtual void setSupplementaryDirectory(const ossimFilename &dir)
Sets the supplementary directory.
virtual ossimObject * dup() const
Definition: ossimObject.cpp:29
virtual bool isAffectedByElevation() const =0
Pure virtual method to query if projection is affected by elevation.
virtual ossimFilename createDefaultHistogramFilename() const
static ossimInit * instance()
Definition: ossimInit.cpp:89
virtual std::multimap< long, ossimAnnotationObject * > getFeatureTable()=0
Pure virtual getFeatureTable method.
ossimFilename file() const
virtual bool hasOverviews() const
ossimImageFileWriter * createWriter(const ossimFilename &filename) const
virtual void setUlTiePoints(const ossimGpt &gpt)
ossimString ext() const
ossimDpt metersPerDegree() const
Definition: ossimGpt.cpp:498
static ossimImageHandlerRegistry * instance()
virtual ossimIrect getBoundingRect(ossim_uint32 resLevel=0) const
Returns zero-based bounding rectangle of the image.
ossim_int32 x
Definition: ossimIpt.h:141
const ossimDpt & ll() const
Definition: ossimDrect.h:342
ossim_float64 lat
Definition: ossimGpt.h:265
void setRectangle(const ossimIrect &rect)
char ** argv()
return the argument array.
virtual ossimDpt getMetersPerPixel() const
virtual void setFilename(const ossimFilename &filename)
ossimFilename & setExtension(const ossimString &e)
Sets the extension of a file name.
ossimString after(const ossimString &str, std::string::size_type pos=0) const
METHOD: after(str, pos) Returns string immediately after the token str.
virtual void lineSampleHeightToWorld(const ossimDpt &lineSampPt, const double &heightAboveEllipsoid, ossimGpt &worldPt) const
This is the pure virtual that projects the image point to the given elevation above ellipsoid...
virtual bool setCurrentEntry(ossim_uint32 entryIdx)
virtual bool setOutputBandList(const std::vector< ossim_uint32 > &band_list)
If the image handler "isBandSeletor()" then the band selection of the output chip can be controlled...
const ossimDpt & lr() const
Definition: ossimDrect.h:341
const ossimString & getHistogramOp() const
void setBands(const std::vector< ossim_uint32 > &v)
ossimFilename getFilenameWithThisExtension(const ossimString &ext, bool set_e0_prefix=false) const
Returns the image file with extension set using supplentary directory for dirname if set...
int & argc()
return the argument count.
void setHemisphere(const ossimGpt &ground)
void setExpandEnvVarsFlag(bool flag)
void setLowNormalizedClipPoint(const ossim_float64 &clip)
Sets the low clip point.
bool insertLeft(ossimConnectableObject *newObj, const ossimId &id)
ossimFilename path() const
virtual double getNullPixelValue(ossim_uint32 band=0) const
Each band has a null pixel associated with it.
virtual void outputProduct()
Writes the output product image. Throws an ossimException if error encountered.
Definition: ossimIgen.cpp:373
static ossimEpsgProjectionFactory * instance()
Implements singleton pattern.
int toInt() const
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
void makeNan()
Definition: ossimDpt.h:65
bool openHistogram(const ossimFilename &histogram_file)
Open the histogram file.
void getCenter(ossimDpt &center_point) const
Definition: ossimIrect.cpp:672
void setCutType(ossimPolyCutterCutType cutType)
bool addFirst(ossimConnectableObject *obj)
Adds it to the start of the chain.
const double & getWeight() const
bool theStdoutFlag
Definition: ossimIgen.h:66
void setMaskSource(ossimImageSource *maskSource)
This set method is necessary when this object is being added to an ossimImageChain because ossimImage...
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91