1 //*******************************************************************
2 //
3 // License:  LGPL
4 //
5 // See LICENSE.txt file in the top level directory for more details.
6 //
7 // Author: Mingjie Su
8 //
9 //********************************************************************
10 // $Id: ossimImageCacheBase.cpp 2685 2011-06-07 16:24:41Z david.burken $
11 #include <algorithm>
12 using namespace std;
13 
14 #include <ossim/imaging/ossimImageCacheBase.h>
15 
16 #include <ossim/base/ossimStdOutProgress.h>
17 #include <ossim/base/ossimNBandLutDataObject.h>
18 #include <ossim/imaging/ossimHistogramWriter.h>
19 #include <ossim/imaging/ossimImageHistogramSource.h>
20 #include <ossim/base/ossimConstants.h>
21 #include <ossim/base/ossimCommon.h>
22 #include <ossim/base/ossimStringProperty.h>
23 #include <ossim/base/ossimContainerProperty.h>
24 #include <ossim/base/ossimKeywordNames.h>
25 #include <ossim/base/ossimKeywordlist.h>
26 #include <ossim/base/ossimEllipsoid.h>
27 #include <ossim/base/ossimDatum.h>
28 #include <ossim/base/ossimNotify.h>
29 #include <ossim/support_data/ossimRpfFrame.h>
30 #include <ossim/support_data/ossimRpfToc.h>
31 #include <ossim/support_data/ossimRpfTocEntry.h>
32 #include <ossim/support_data/ossimRpfCompressionSection.h>
33 #include <ossim/imaging/ossimImageDataFactory.h>
34 #include <ossim/projection/ossimEquDistCylProjection.h>
35 #include <ossim/projection/ossimCylEquAreaProjection.h>
36 #include <ossim/base/ossimEndian.h>
37 #include <ossim/base/ossimTrace.h>
38 #include <ossim/base/ossimPolygon.h>
39 
40 static ossimTrace traceDebug = ossimTrace("ossimImageCacheBase:debug");
41 
42 #ifdef OSSIM_ID_ENABLED
43 static const char OSSIM_ID[] = "$Id: ossimImageCacheBase.cpp 2685 2011-06-07 16:24:41Z david.burken $";
44 #endif
45 
46 RTTI_DEF1(ossimImageCacheBase, "ossimImageCacheBase", ossimImageHandler)
47 
ossimImageCacheBase()48 ossimImageCacheBase::ossimImageCacheBase()
49    :
50    ossimImageHandler(),
51    m_actualImageRect(),
52    m_numberOfLines(0),
53    m_numberOfSamples(0),
54    m_numberOfBands(0),
55    m_fileNames(),
56    m_tileSize(128, 128),
57    m_workFrame(new ossimRpfFrame),
58    m_bBox_LL_Lon(0.0),
59    m_bBox_LL_Lat(0.0),
60    m_bBox_UR_Lon(0.0),
61    m_bBox_UR_Lat(0.0),
62    m_numOfFramesVertical(0),
63    m_numOfFramesHorizontal(0),
64    m_frame_width(0),
65    m_frame_height(0),
66    m_frameEntryArray()
67 {
68   if (traceDebug())
69   {
70     ossimNotify(ossimNotifyLevel_DEBUG)
71       << "ossimImageCacheBase::ossimImageCacheBase entered...\n";
72 #ifdef OSSIM_ID_ENABLED
73     ossimNotify(ossimNotifyLevel_DEBUG)
74       << "OSSIM_ID:  " << OSSIM_ID << "\n";
75 #endif
76   }
77 
78   m_actualImageRect.makeNan();
79 
80 }
81 
~ossimImageCacheBase()82 ossimImageCacheBase::~ossimImageCacheBase()
83 {
84   if(m_workFrame)
85   {
86     delete m_workFrame;
87     m_workFrame = 0;
88   }
89   close();
90 }
91 
close()92 void ossimImageCacheBase::close()
93 {
94   deleteAll();
95 }
96 
isOpen() const97 bool ossimImageCacheBase::isOpen()const
98 {
99   //return (theTableOfContents!=0);
100   ossimString ext = theImageFile.ext().downcase();
101 
102   if(ext == "rpf")
103   {
104     return true;
105   }
106   else
107   {
108     return false;
109   }
110 }
111 
buildFrameEntryArray(ossimFilename imageFile,ossim_uint32 frameWidth,ossim_uint32 frameHeight)112 bool ossimImageCacheBase::buildFrameEntryArray(ossimFilename imageFile,
113                                                ossim_uint32 frameWidth,
114                                                ossim_uint32 frameHeight)
115 {
116    static const char MODULE[] = "ossimImageCacheBase::buildFrameEntryArray";
117    if ( traceDebug() )
118    {
119       ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered..." << endl;
120    }
121 
122    // use to check if tiles have overlap pixels
123    ossim_float64 avgLat = 0.0;
124    ossim_float64 avgLon = 0.0;
125 
126    m_frame_width = frameWidth;
127    m_frame_height = frameHeight;
128 
129    std::ifstream in((imageFile).c_str() );
130 
131    std::string line;
132    ossim_uint32 index = 0; // used throughout
133    while( in.good() )
134    {
135       // Read in a line.
136       std::getline(in, line);
137 
138       ossimString tmpStr = ossimString(line);
139       if (!tmpStr.empty())
140       {
141          if (index == 0)
142          {
143             std::vector<ossimString> box_lat_lon;
144             tmpStr.split(box_lat_lon, "|");
145 
146             if (box_lat_lon.size() > 2)
147             {
148                std::vector<ossimString> ll;
149                std::vector<ossimString> ur;
150 
151                box_lat_lon[0].split(ll, ",");
152                box_lat_lon[1].split(ur, ",");
153                ossimString bandStr = box_lat_lon[2];
154 
155                m_bBox_LL_Lon = ll[0].toFloat64();
156                m_bBox_LL_Lat = ll[1].toFloat64();
157                m_bBox_UR_Lon = ur[0].toFloat64();
158                m_bBox_UR_Lat = ur[1].toFloat64();
159 
160                checkLongitude(m_bBox_LL_Lon, m_bBox_UR_Lon);
161 
162                m_numberOfBands = ossimString(bandStr).toInt32();
163             }
164             else
165             {
166                return false;
167             }
168          }
169          else if (index == 1)
170          {
171             m_fileNames.push_back(tmpStr);
172             std::vector<ossimString> frame_lat_lon = tmpStr.split("|");
173             if (frame_lat_lon.size() > 2)
174             {
175                ossimString ll_lon_lat = frame_lat_lon[1];
176                ossimString ur_lon_lat = frame_lat_lon[2];
177                ossim_float64 ll_lon = ossimString(ll_lon_lat.split(",")[0]).toDouble();
178                ossim_float64 ll_lat = ossimString(ll_lon_lat.split(",")[1]).toDouble();
179                ossim_float64 ur_lon = ossimString(ur_lon_lat.split(",")[0]).toDouble();
180                ossim_float64 ur_lat = ossimString(ur_lon_lat.split(",")[1]).toDouble();
181 
182                checkLongitude(ll_lon, ur_lon);
183 
184                ossim_float64 bBox_lat_diff = std::fabs(m_bBox_UR_Lat - m_bBox_LL_Lat);
185                ossim_float64 bBox_lon_diff = std::fabs(m_bBox_UR_Lon - m_bBox_LL_Lon);
186 
187                ossim_float64 lat_diff = std::fabs(ur_lat - ll_lat);
188                ossim_float64 lon_diff = std::fabs(ur_lon - ll_lon);
189 
190                m_numOfFramesVertical   = static_cast<ossim_uint32>(bBox_lat_diff/lat_diff + 0.5);
191                m_numOfFramesHorizontal = static_cast<ossim_uint32>(bBox_lon_diff/lon_diff + 0.5);
192 
193                avgLon = std::fabs(bBox_lon_diff/m_numOfFramesHorizontal);
194                avgLat = std::fabs(bBox_lat_diff/m_numOfFramesVertical);
195 
196                m_numberOfLines   = m_numOfFramesVertical*m_frame_height;
197                m_numberOfSamples = m_numOfFramesHorizontal*m_frame_width;
198 
199                if ( traceDebug() )
200                {
201                   ossimNotify(ossimNotifyLevel_DEBUG)
202                      << "\nscene height in degrees: " << bBox_lat_diff
203                      << "\nscene width in degrees:  " << bBox_lon_diff
204                      << "\nframe height in degrees: " << lat_diff
205                      << "\nframe width in degrees:  " << lon_diff
206                      << "\nframes vertical:         " << m_numOfFramesVertical
207                      << "\nframes horizontal:       " << m_numOfFramesHorizontal
208                      << "\nlines:                   " << m_numberOfLines
209                      << "\nsamples:                 " << m_numberOfSamples << "\n";
210                }
211             }
212             else
213             {
214                return false;
215             }
216          }
217          else
218          {
219             m_fileNames.push_back(tmpStr);
220          }
221 
222       } // matches: if (!tmpStr.empty())
223 
224       ++index;
225 
226    } // matches: while( in.good() )
227    in.close();
228 
229    m_frameEntryArray.resize(m_numOfFramesVertical);
230    for(index = 0; index < m_frameEntryArray.size(); ++index)
231    {
232       m_frameEntryArray[index].resize(m_numOfFramesHorizontal);
233    }
234 
235    for(index = 0; index < m_fileNames.size(); ++index)
236    {
237       ossimString tmpStr = m_fileNames[index];
238       std::vector<ossimString> frameInfos = tmpStr.split("|");
239       if (frameInfos.size() > 1)
240       {
241          ossimString fileName = frameInfos[0];
242          ossimString ll_lon_lat = frameInfos[1];
243          ossimString ur_lon_lat = frameInfos[2];
244          double ll_lon = ossimString(ll_lon_lat.split(",")[0]).toDouble();
245          double ll_lat = ossimString(ll_lon_lat.split(",")[1]).toDouble();
246          double ur_lon = ossimString(ur_lon_lat.split(",")[0]).toDouble();
247          double ur_lat = ossimString(ur_lon_lat.split(",")[1]).toDouble();
248 
249          checkLongitude(ll_lon, ur_lon);
250 
251          ossim_float64 tmpColPostion = std::fabs(ll_lon - m_bBox_LL_Lon);
252          ossim_float64 tmpFrameLon = std::fabs(ur_lon - ll_lon);
253 
254          if (std::fabs(tmpFrameLon - avgLon) > 0.002)
255          {
256             ossimNotify(ossimNotifyLevel_WARN) << fileName << " has overlap pixels with other image." << std::endl;
257             return false;
258          }
259 
260          ossim_float64 tmpRowPostion = std::fabs(m_bBox_UR_Lat - ur_lat);
261          ossim_float64 tmpFrameLat = std::fabs(ur_lat - ll_lat);
262 
263          if (std::fabs(tmpFrameLat - avgLat) > 0.002)
264          {
265             ossimNotify(ossimNotifyLevel_WARN) << fileName << " has overlap pixels with other image." << std::endl;
266             return false;
267          }
268 
269          ossim_uint32 colNum = static_cast<ossim_uint32>(tmpColPostion/tmpFrameLon + 0.5);
270          ossim_uint32 rowNum = static_cast<ossim_uint32>(tmpRowPostion/tmpFrameLat + 0.5);
271 
272          if (colNum >= m_numOfFramesHorizontal)
273          {
274             colNum = m_numOfFramesHorizontal-1; // Clamp to last column.
275          }
276 
277          if (rowNum >= m_numOfFramesVertical)
278          {
279             rowNum = m_numOfFramesVertical-1; // Clamp to last row.
280          }
281 
282          ossimRpfFrameEntry tempEntry;
283          tempEntry.setEntry(ossimFilename(""), fileName);
284          m_frameEntryArray[rowNum][colNum] = tempEntry;
285       }
286       else
287       {
288          return false;
289       }
290    }
291 
292    return true;
293 }
294 
checkLongitude(ossim_float64 & leftLon,const ossim_float64 & rightLon) const295 void ossimImageCacheBase::checkLongitude(ossim_float64& leftLon,
296                                              const ossim_float64& rightLon) const
297 {
298    //---
299    // Test for scene coordinates being 180 to 180 and adjust leftLon to -180
300    // if so.
301    //
302    // NOTE:
303    // Setting tolerance to 1/7200 about 15 meters.
304    // Not sure if this is too loose or not. (drb)
305    //---
306    const ossim_float64 TOLERANCE = 0.000138889; // 1/7200 about 15 meters.
307 
308    if ( ossim::almostEqual(leftLon, 180.0, TOLERANCE) )
309    {
310       if ( ossim::almostEqual(rightLon, 180.0, TOLERANCE) )
311       {
312          leftLon = -180.0;
313       }
314    }
315 }
316 
getNumberOfInputBands() const317 ossim_uint32 ossimImageCacheBase::getNumberOfInputBands()const
318 {
319    return m_numberOfBands;
320 }
321 
getNumberOfOutputBands() const322 ossim_uint32 ossimImageCacheBase::getNumberOfOutputBands()const
323 {
324   return m_numberOfBands;
325 }
326 
getNumberOfLines(ossim_uint32 reduced_res_level) const327 ossim_uint32 ossimImageCacheBase::getNumberOfLines(ossim_uint32 reduced_res_level) const
328 {
329    if (reduced_res_level == 0)
330    {
331       return m_numberOfLines;
332    }
333    else if (theOverview.valid())
334    {
335       return theOverview->getNumberOfLines(reduced_res_level);
336    }
337 
338    return 0;
339 }
340 
getNumberOfSamples(ossim_uint32 reduced_res_level) const341 ossim_uint32 ossimImageCacheBase::getNumberOfSamples(ossim_uint32 reduced_res_level) const
342 {
343    if (reduced_res_level == 0)
344    {
345       return m_numberOfSamples;
346    }
347    else if (theOverview.valid())
348    {
349       return theOverview->getNumberOfSamples(reduced_res_level);
350    }
351 
352    return 0;
353 }
354 
setActualImageRect()355 void ossimImageCacheBase::setActualImageRect()
356 {
357    m_actualImageRect = ossimIrect(0,0,m_numberOfLines, m_numberOfSamples);
358 }
359 
getImageRectangle(ossim_uint32 reduced_res_level) const360 ossimIrect ossimImageCacheBase::getImageRectangle(ossim_uint32 reduced_res_level) const
361 {
362    return ossimIrect(0,                         // upper left x
363                      0,                         // upper left y
364                      getNumberOfSamples(reduced_res_level) - 1,  // lower right x
365                      getNumberOfLines(reduced_res_level)   - 1); // lower right y
366 }
367 
368 
369 
getTileWidth() const370 ossim_uint32 ossimImageCacheBase::getTileWidth() const
371 {
372    return m_tileSize.x;
373 }
374 
getTileHeight() const375 ossim_uint32 ossimImageCacheBase::getTileHeight() const
376 {
377    return m_tileSize.y;
378 }
379 
getEntryList(std::vector<ossim_uint32> & entryList) const380 void ossimImageCacheBase::getEntryList(std::vector<ossim_uint32>& entryList)const
381 {
382    entryList.push_back(0);
383 }
384 
isValidRLevel(ossim_uint32 reduced_res_level) const385 bool ossimImageCacheBase::isValidRLevel(ossim_uint32 reduced_res_level) const
386 {
387    if (reduced_res_level == 0)
388    {
389       return true;
390    }
391    else if (theOverview.valid())
392    {
393       return theOverview->isValidRLevel(reduced_res_level);
394    }
395    else
396    {
397       return false;
398    }
399 }
400 
getIntersectingEntries(const ossimIrect & rect)401 vector<ossimImageCacheBase::ossimFrameEntryData> ossimImageCacheBase::getIntersectingEntries(const ossimIrect& rect)
402 {
403    vector<ossimFrameEntryData> result;
404 
405    // make sure we have the Toc entry to render
406    if(!isOpen()) return result;
407 
408    ossimIrect imageRect = getImageRectangle();
409    if(rect.intersects(imageRect))
410    {
411       ossimIrect clipRect  = rect.clipToRect(imageRect);
412       ossimIrect frameRect(clipRect.ul().x/m_frame_width,
413                            clipRect.ul().y/m_frame_height,
414                            clipRect.lr().x/m_frame_width,
415                            clipRect.lr().y/m_frame_height);
416 
417       for(ossim_int32 row = frameRect.ul().y; row <= frameRect.lr().y; ++row)
418       {
419          for(ossim_int32 col = frameRect.ul().x; col <= frameRect.lr().x; ++col)
420          {
421             ossimRpfFrameEntry tempEntry = m_frameEntryArray[row][col];
422             if(tempEntry.exists())
423             {
424                result.push_back(ossimFrameEntryData(row,
425                                                     col,
426                                                     row*m_frame_height,
427                                                     col*m_frame_width,
428                                                     tempEntry));
429             }
430          }
431       }
432    }
433 
434    return result;
435 }
436 
deleteAll()437 void ossimImageCacheBase::deleteAll()
438 {
439    theOverview = 0;
440 }
441 
saveState(ossimKeywordlist & kwl,const char * prefix) const442 bool ossimImageCacheBase::saveState(ossimKeywordlist& kwl,
443                                         const char* prefix)const
444 {
445    bool result = ossimImageHandler::saveState(kwl, prefix);
446 
447    return result;
448 }
449 
loadState(const ossimKeywordlist & kwl,const char * prefix)450 bool ossimImageCacheBase::loadState(const ossimKeywordlist& kwl,
451                                         const char* prefix)
452 {
453    const char* MODULE = "ossimImageCacheBase::loadState";
454 
455    if(traceDebug())
456    {
457       CLOG << "Entering..." << endl;
458    }
459    bool result = ossimImageHandler::loadState(kwl, prefix);
460 
461    if(!result)
462    {
463       if(traceDebug())
464       {
465          CLOG << "Leaving..." << endl;
466       }
467       return false;
468    }
469    const char* lookup = 0;
470    lookup = kwl.find(ossimString(prefix), "entry");
471    ossim_int32 entry = ossimString(lookup).toInt32();
472 
473    // if an entry is specified then
474    // call the open with an entry number
475    if(lookup)
476    {
477       if(traceDebug())
478       {
479          CLOG << "Leaving..." << endl;
480       }
481       result = ossimImageHandler::open(theImageFile);
482       setCurrentEntry(entry);
483       return result;
484    }
485 
486    result = ossimImageHandler::open(theImageFile);
487 
488    return result;
489 }
490 
getImageTileWidth() const491 ossim_uint32 ossimImageCacheBase::getImageTileWidth() const
492 {
493    return 256;
494 }
495 
getImageTileHeight() const496 ossim_uint32 ossimImageCacheBase::getImageTileHeight() const
497 {
498    return 256;
499 }
500 
establishDecimationFactors()501 void ossimImageCacheBase::establishDecimationFactors()
502 {
503    theDecimationFactors.clear();
504 
505    // Just needed to set the first R level here, the base class can do the rest:
506    ossimImageHandler::establishDecimationFactors();
507 }
508 
getImageGeometry()509 ossimRefPtr<ossimImageGeometry> ossimImageCacheBase::getImageGeometry()
510 {
511    if (theGeometry.valid()) return theGeometry;
512 
513    // datum
514    // WGS 84
515    ossimKeywordlist kwl;
516    const char* prefix = 0; // legacy
517    kwl.add(prefix,
518       ossimKeywordNames::DATUM_KW,
519       "WGE",
520       true);
521 
522    ossimGpt ul(m_bBox_UR_Lat,m_bBox_LL_Lon);
523    ossimGpt ll(m_bBox_LL_Lat,m_bBox_LL_Lon);
524    ossimGpt ur(m_bBox_UR_Lat,m_bBox_UR_Lon);
525    ossimGpt lr(m_bBox_LL_Lat,m_bBox_UR_Lon);
526 
527    double latInterval = fabs(ul.latd() - lr.latd())/ getNumberOfLines();
528    double lonInterval = fabs(ul.lond() - ur.lond())/ getNumberOfSamples();
529 
530    kwl.add(prefix,
531       ossimKeywordNames::UL_LAT_KW,
532       ul.latd(),//-(latInterval/2.0),
533       true);
534 
535    kwl.add(prefix,
536       ossimKeywordNames::UL_LON_KW,
537       ul.lond(),//+(lonInterval/2.0),
538       true);
539 
540    kwl.add(prefix,
541       ossimKeywordNames::LL_LAT_KW,
542       ll.latd(),//+(latInterval/2.0),
543       true);
544 
545    kwl.add(prefix,
546       ossimKeywordNames::LL_LON_KW,
547       ll.lond(),//+(lonInterval/2.0),
548       true);
549 
550    kwl.add(prefix,
551       ossimKeywordNames::LR_LAT_KW,
552       lr.latd(),//+(latInterval/2.0),
553       true);
554 
555    kwl.add(prefix,
556       ossimKeywordNames::LR_LON_KW,
557       lr.lond(),//-(lonInterval/2.0),
558       true);
559 
560    kwl.add(prefix,
561       ossimKeywordNames::UR_LAT_KW,
562       ur.latd(),//-(latInterval/2.0),
563       true);
564 
565    kwl.add(prefix,
566       ossimKeywordNames::UR_LON_KW,
567       ur.lond(),//-(latInterval/2.0),
568       true);
569 
570    kwl.add(prefix,
571       ossimKeywordNames::NUMBER_INPUT_BANDS_KW,
572       getNumberOfInputBands(),
573       true);
574 
575    kwl.add(prefix,
576       ossimKeywordNames::NUMBER_OUTPUT_BANDS_KW,
577       getNumberOfOutputBands(),
578       true);
579 
580    kwl.add(prefix,
581       ossimKeywordNames::NUMBER_LINES_KW,
582       getNumberOfLines(),
583       true);
584 
585    kwl.add(prefix,
586       ossimKeywordNames::NUMBER_SAMPLES_KW,
587       getNumberOfSamples(),
588       true);
589 
590 
591    //---
592    // Make a projection to get the easting / northing of the tie point and
593    // the scale in meters.  This will only be used by the CIB.
594    //---
595    kwl.add(prefix,
596       ossimKeywordNames::DATUM_KW,
597       "WGE",
598       true);
599 
600    ossimGpt origin((ul.latd()+lr.latd())*.5,
601       (ul.lond()+lr.lond())*.5,
602       0.0);
603 
604    double deltaLatPerPixel = latInterval;
605    double deltaLonPerPixel = lonInterval;
606 
607    ossimDpt tie;
608 
609    tie.lat = ul.latd() - deltaLatPerPixel/2.0;
610    tie.lon = ul.lond() + deltaLonPerPixel/2.0;
611 
612    kwl.add(prefix,
613       ossimKeywordNames::TIE_POINT_XY_KW,
614       tie.toString(),
615       true);
616 
617    kwl.add(prefix,
618       ossimKeywordNames::DECIMAL_DEGREES_PER_PIXEL_LAT,
619       deltaLatPerPixel,
620       true);
621 
622    kwl.add(prefix,
623       ossimKeywordNames::DECIMAL_DEGREES_PER_PIXEL_LON,
624       deltaLonPerPixel,
625       true);
626 
627    kwl.add(prefix,
628       ossimKeywordNames::ORIGIN_LATITUDE_KW,
629       origin.latd(),
630       true);
631 
632    kwl.add(prefix,
633       ossimKeywordNames::CENTRAL_MERIDIAN_KW,
634       origin.lond(),
635       true);
636 
637    kwl.add(prefix,
638       ossimKeywordNames::TIE_POINT_LAT_KW,
639       ul.latd()-(deltaLatPerPixel/2.0),
640       true);
641 
642    kwl.add(prefix,
643       ossimKeywordNames::TIE_POINT_LON_KW,
644       ul.lond()+(deltaLonPerPixel/2.0),
645       true);
646 
647    kwl.add(prefix,
648       ossimKeywordNames::TYPE_KW,
649       "ossimEquDistCylProjection",
650       true);
651 
652    // Capture this for next time.
653    theGeometry = new ossimImageGeometry;
654    theGeometry->loadState(kwl, prefix);
655 
656    // Set image things the geometry object should know about.
657    initImageParameters( theGeometry.get() );
658 
659    return theGeometry;
660 }
661 
662