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