8 #include "geos/operation/distance/DistanceOp.h"
9 #include "geos/util/IllegalArgumentException.h"
10 #include "geos/geom/Point.h"
11 #include "geos/opOverlay.h"
33 ImageOverlapSet::ImageOverlapSet(
bool continueOnError) {
34 p_continueAfterError = continueOnError;
36 p_calculatedSoFar = -1;
37 p_threadedCalculate =
false;
48 ImageOverlapSet::~ImageOverlapSet() {
49 for(
int i = 0; i < Size(); i++) {
50 if(p_lonLatOverlaps[i])
delete p_lonLatOverlaps[i];
68 for(
int i = 0; i < sns.
Size(); i++) {
75 QString msg =
"Unable to open cube for serial number [";
78 HandleError(error, &sns, msg);
88 geos::geom::MultiPolygon *tmp = PolygonTools::MakeMultiPolygon(
94 geos::geom::MultiPolygon *mp = NULL;
101 "] has an invalid footprint";
106 mp = PolygonTools::Despike(tmp);
116 HandleError(e, &sns);
121 p_lonLatOverlaps.push_back(CreateNewOverlap(sns.
SerialNumber(i), mp));
136 DespikeLonLatOverlaps();
138 if(p_threadedCalculate) {
144 FindAllOverlaps(&sns);
163 void ImageOverlapSet::FindImageOverlaps(
SerialNumberList &boundaries, QString outputFile) {
165 if(!p_lonLatOverlaps.empty()) {
166 string msg =
"FindImageOverlaps(SerialNumberList&,QString) may not be called on " \
167 "an ImageOverlapSet which already contains overlaps.";
172 p_calculatedSoFar = -1;
174 p_snlist = &boundaries;
177 p_threadedCalculate =
true;
179 FindImageOverlaps(boundaries);
183 while(p_calculatedSoFar != p_lonLatOverlaps.size()) {
184 WriteImageOverlaps(outputFile);
188 if(p_calculatedSoFar != p_writtenSoFar)
189 WriteImageOverlaps(outputFile);
195 p_lonLatOverlaps.clear();
197 p_calculatedSoFar = -1;
198 p_threadedCalculate =
false;
291 void ImageOverlapSet::FindImageOverlaps(std::vector<QString> sns,
292 std::vector<geos::geom::MultiPolygon *> polygons) {
294 if(sns.size() != polygons.size()) {
295 string message =
"Invalid argument sizes. Sizes must match.";
300 for(
unsigned int i = 0; i < sns.size(); ++i) {
301 p_lonLatOverlaps.push_back(CreateNewOverlap(sns[i], polygons[i]));
305 DespikeLonLatOverlaps();
316 void ImageOverlapSet::ReadImageOverlaps(
const QString &filename) {
321 std::ifstream inStream;
322 inStream.open(file.c_str(), fstream::in | fstream::binary);
324 while(!inStream.eof()) {
331 IString msg =
"The overlap file [" + filename +
"] does not contain a "
332 "valid list of image overlaps";
336 IString msg =
"The overlap file [" + filename +
"] does not contain a "
337 "valid list of image overlaps";
360 bool ImageOverlapSet::SetPolygon(geos::geom::Geometry *poly,
int position,
ImageOverlap *sncopy,
bool insert) {
361 bool success =
false;
362 geos::geom::MultiPolygon *multiPolygon = PolygonTools::MakeMultiPolygon(poly);
366 if(!multiPolygon->isValid() || (multiPolygon->getArea() < 1.0e-10 && !multiPolygon->isEmpty())) {
368 multiPolygon = Isis::globalFactory.createMultiPolygon();
371 if(position > p_lonLatOverlaps.size()) {
372 position = p_lonLatOverlaps.size();
376 if(!multiPolygon->isEmpty()) {
377 geos::geom::MultiPolygon *despiked = PolygonTools::Despike(multiPolygon);
379 multiPolygon = despiked;
385 if(multiPolygon->isValid() && (multiPolygon->isEmpty() || multiPolygon->getArea() > 1.0e-14)) {
387 p_lonLatOverlaps.at(position)->SetPolygon(multiPolygon);
390 AddSerialNumbers(p_lonLatOverlaps.at(position), sncopy);
393 else if(!multiPolygon->isEmpty()) {
400 AddSerialNumbers(imageOverlap, sncopy);
405 QMutexLocker locker(&p_lonLatOverlapsMutex);
406 p_lonLatOverlaps.insert(p_lonLatOverlaps.begin() + position, imageOverlap);
421 void ImageOverlapSet::WriteImageOverlaps(
const QString &filename) {
424 if(p_threadedCalculate) p_calculatePolygonMutex.lock();
426 if(p_lonLatOverlaps.size() == 0) {
427 IString msg =
"No overlaps were found.";
433 std::ofstream outStream;
435 if(p_writtenSoFar == 0) {
436 outStream.open(file.c_str(), fstream::out | fstream::trunc | fstream::binary);
439 outStream.open(file.c_str(), fstream::out | fstream::app | fstream::binary);
442 failed |= outStream.fail();
444 static bool overlapWritten =
false;
445 for(
int overlap = p_writtenSoFar; !failed && overlap <= p_calculatedSoFar; overlap++) {
447 QMutexLocker locker(&p_lonLatOverlapsMutex);
449 if(overlap < p_lonLatOverlaps.size() && p_lonLatOverlaps[overlap]) {
450 if(!p_lonLatOverlaps[overlap]->Polygon()->isEmpty()) {
452 outStream << std::endl;
455 p_lonLatOverlaps[overlap]->Write(outStream);
456 overlapWritten =
true;
459 delete p_lonLatOverlaps[overlap];
460 p_lonLatOverlaps[overlap] = NULL;
465 failed |= outStream.fail();
468 failed |= outStream.fail();
478 if(p_calculatedSoFar == p_lonLatOverlaps.size()) {
479 if(p_threadedCalculate) p_calculatePolygonMutex.unlock();
483 IString msg =
"Unable to write the image overlap list to [" + filename +
"]";
496 if(p_lonLatOverlaps.size() <= 1)
return;
499 p.
SetText(
"Calculating Image Overlaps");
503 geos::geom::MultiPolygon *emptyPolygon = Isis::globalFactory.createMultiPolygon();
506 for(
int outside = 0; outside < p_lonLatOverlaps.size() - 1; ++outside) {
507 p_calculatedSoFar = outside - 1;
510 if(p_calculatedSoFar % 10 == 0 && (!snlist || p_lonLatOverlaps.size() > snlist->
Size())) {
511 if(p_threadedCalculate) p_calculatePolygonMutex.unlock();
516 for(
int inside = outside + 1; inside < p_lonLatOverlaps.size(); ++inside) {
518 if(p_lonLatOverlaps.at(outside)->HasAnySameSerialNumber(*p_lonLatOverlaps.at(inside)))
continue;
521 const geos::geom::MultiPolygon *poly1 = p_lonLatOverlaps.at(outside)->Polygon();
522 const geos::geom::MultiPolygon *poly2 = p_lonLatOverlaps.at(inside)->Polygon();
526 if(PolygonTools::Equal(poly1, poly2)) {
527 AddSerialNumbers(p_lonLatOverlaps[outside], p_lonLatOverlaps[inside]);
528 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
534 if(poly2->isEmpty() || poly2->getArea() < 1.0e-14) {
535 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
540 geos::geom::Geometry *intersected = NULL;
542 intersected = PolygonTools::Intersect(poly1, poly2);
546 QString error =
"Intersection of overlaps failed.";
551 double outsideArea = poly1->getArea();
552 double insideArea = poly2->getArea();
553 double areaRatio = std::min(outsideArea, insideArea) / std::max(outsideArea, insideArea);
557 if(areaRatio < 0.1) {
558 if(poly1->getArea() > poly2->getArea()) {
559 error +=
" The first polygon will be removed.";
560 HandleError(e, snlist, error, inside, outside);
561 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
565 error +=
" The second polygon will be removed.";
566 HandleError(e, snlist, error, inside, outside);
567 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + outside);
572 error +=
" Both polygons will be removed to prevent the possibility of double counted areas.";
573 HandleError(e, snlist, error, inside, outside);
574 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
575 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + outside);
582 if(intersected->isEmpty() || intersected->getArea() < 1.0e-14) {
591 geos::geom::MultiPolygon *overlap = NULL;
593 overlap = PolygonTools::Despike(intersected);
599 if(!intersected->isValid()) {
603 HandleError(e, snlist,
"", inside, outside);
607 overlap = PolygonTools::MakeMultiPolygon(intersected);
613 catch(geos::util::GEOSException *exc) {
616 HandleError(exc, snlist,
"", inside, outside);
620 if(!overlap->isValid()) {
623 HandleError(snlist,
"Intersection produced invalid overlap area", inside, outside);
628 if(overlap->isEmpty() || overlap->getArea() < 1.0e-14) {
635 if(PolygonTools::Equal(poly1, overlap)) {
636 geos::geom::Geometry *tmpGeom = NULL;
638 tmpGeom = PolygonTools::Difference(poly2, poly1);
641 HandleError(e, snlist,
"Differencing overlap polygons failed. The first polygon will be removed.", inside, outside);
645 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + outside);
651 SetPolygon(tmpGeom, inside);
652 SetPolygon(overlap, outside, p_lonLatOverlaps[inside]);
656 else if(PolygonTools::Equal(poly2, overlap)) {
657 geos::geom::Geometry *tmpGeom = NULL;
659 tmpGeom = PolygonTools::Difference(poly1, poly2);
662 HandleError(e, snlist,
"Differencing overlap polygons failed. The second polygon will be removed.", inside, outside);
666 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
672 SetPolygon(tmpGeom, outside);
673 SetPolygon(overlap, inside, p_lonLatOverlaps[outside]);
678 geos::geom::Geometry *tmpGeom = NULL;
680 tmpGeom = PolygonTools::Difference(poly1, overlap);
688 if(tmpGeom == NULL) {
689 tmpGeom = PolygonTools::Difference(poly1, poly2);
694 HandleError(e, snlist,
"Differencing overlap polygons failed", inside, outside);
698 if(!SetPolygon(tmpGeom, outside)) {
699 SetPolygon(Isis::globalFactory.createMultiPolygon(), outside);
702 int oldSize = p_lonLatOverlaps.size();
703 if(SetPolygon(overlap, inside + 1, p_lonLatOverlaps[outside],
true)) {
704 int newSize = p_lonLatOverlaps.size();
705 int newSteps = newSize - oldSize;
708 if(newSize != oldSize) inside++;
714 HandleError(e, snlist,
"Unable to find overlap.", inside, outside);
717 catch(geos::util::IllegalArgumentException *ill) {
718 HandleError(NULL, snlist,
"Unable to find overlap", inside, outside);
720 catch(geos::util::GEOSException *exc) {
721 HandleError(exc, snlist,
"Unable to find overlap", inside, outside);
724 HandleError(snlist,
"Unknown Error: Unable to find overlap", inside, outside);
731 p_calculatedSoFar = p_lonLatOverlaps.size();
736 if(p_lonLatOverlaps.size() == snlist->
Size()) {
737 p_lonLatOverlaps.clear();
742 p_calculatePolygonMutex.unlock();
757 for(
int i = 0; i < from->Size(); i++) {
758 QString s = (*from)[i];
773 geos::geom::MultiPolygon *latLonPolygon) {
791 std::vector<ImageOverlap *> ImageOverlapSet::operator[](QString serialNumber) {
792 vector<ImageOverlap *> matches;
796 for(
int ov = 0; ov < p_lonLatOverlaps.size(); ++ov) {
797 for(
int sn = 0; sn < p_lonLatOverlaps[ov]->Size(); ++sn) {
798 if((*p_lonLatOverlaps[ov])[sn] == serialNumber) {
799 matches.push_back(p_lonLatOverlaps[ov]);
820 if(overlap1 >= 0 && overlap1 < p_lonLatOverlaps.size()) {
821 PvlKeyword serialNumbers(
"PolySerialNumbers");
825 for(
int i = 0; i < p_lonLatOverlaps.at(overlap1)->Size(); i++) {
826 serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i];
829 filename += snlist->
FileName((*p_lonLatOverlaps.at(overlap1))[i]);
832 polygon += p_lonLatOverlaps.at(overlap1)->Polygon()->toString().c_str();
834 err += serialNumbers;
836 if(filename.
size() != 0) {
843 if(overlap2 >= 0 && overlap1 < p_lonLatOverlaps.size() && overlap2 < p_lonLatOverlaps.size()) {
844 PvlKeyword serialNumbers(
"PolySerialNumbers");
848 for(
int i = 0; i < p_lonLatOverlaps.at(overlap2)->Size(); i++) {
849 serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i];
852 filename += snlist->
FileName((*p_lonLatOverlaps.at(overlap2))[i]);
855 polygon += p_lonLatOverlaps.at(overlap2)->Polygon()->toString().c_str();
857 err += serialNumbers;
859 if(filename.
size() != 0) {
872 p_errorLog.push_back(err);
874 if(!p_continueAfterError)
throw;
887 void ImageOverlapSet::HandleError(geos::util::GEOSException *exc,
SerialNumberList *snlist, QString msg,
int overlap1,
int overlap2) {
890 if(overlap1 >= 0 && overlap1 < p_lonLatOverlaps.size()) {
891 PvlKeyword serialNumbers(
"PolySerialNumbers");
894 for(
int i = 0; i < p_lonLatOverlaps.at(overlap1)->Size(); i++) {
895 serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i];
898 filename += snlist->
FileName((*p_lonLatOverlaps.at(overlap1))[i]);
902 err += serialNumbers;
904 if(filename.
size() != 0) {
909 if(overlap2 >= 0 && overlap1 < p_lonLatOverlaps.size() && overlap2 < p_lonLatOverlaps.size()) {
910 PvlKeyword serialNumbers(
"PolySerialNumbers");
913 for(
int i = 0; i < p_lonLatOverlaps.at(overlap2)->Size(); i++) {
914 serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i];
917 filename += snlist->
FileName((*p_lonLatOverlaps.at(overlap2))[i]);
921 err += serialNumbers;
923 if(filename.
size() != 0) {
934 p_errorLog.push_back(err);
938 if(!p_continueAfterError) {
940 err[
"Description"][0],
955 void ImageOverlapSet::HandleError(
SerialNumberList *snlist, QString msg,
int overlap1,
int overlap2) {
958 if(overlap1 >= 0 && overlap1 < p_lonLatOverlaps.size()) {
959 PvlKeyword serialNumbers(
"PolySerialNumbers");
962 for(
int i = 0; i < p_lonLatOverlaps.at(overlap1)->Size(); i++) {
963 serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i];
966 filename += snlist->
FileName((*p_lonLatOverlaps.at(overlap1))[i]);
970 err += serialNumbers;
972 if(filename.
size() != 0) {
977 if(overlap2 >= 0 && overlap1 < p_lonLatOverlaps.size() && overlap2 < p_lonLatOverlaps.size()) {
978 PvlKeyword serialNumbers(
"PolySerialNumbers");
981 for(
int i = 0; i < p_lonLatOverlaps.at(overlap2)->Size(); i++) {
982 serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i];
985 filename += snlist->
FileName((*p_lonLatOverlaps.at(overlap2))[i]);
989 err += serialNumbers;
991 if(filename.
size() != 0) {
998 p_errorLog.push_back(err);
1000 if(!p_continueAfterError) {
1002 err[
"Description"][0],
1013 void ImageOverlapSet::DespikeLonLatOverlaps() {
1014 for(
int i = 0; i < Size(); i++) {
1016 p_lonLatOverlaps[i]->SetPolygon(
1017 PolygonTools::Despike(p_lonLatOverlaps[i]->Polygon()));