10 #include "geos/operation/distance/DistanceOp.h" 11 #include "geos/util/IllegalArgumentException.h" 12 #include "geos/geom/Point.h" 13 #include "geos/opOverlay.h" 21 #include "QMessageBox" 36 ImageOverlapSet::ImageOverlapSet(
bool continueOnError) {
38 p_continueAfterError = continueOnError;
40 p_calculatedSoFar = -1;
41 p_threadedCalculate =
false;
52 ImageOverlapSet::~ImageOverlapSet() {
54 for (
int i = 0; i < Size(); i++) {
55 if (p_lonLatOverlaps[i])
delete p_lonLatOverlaps[i];
74 for (
int i = 0; i < sns.
size(); i++) {
81 QString msg =
"Unable to open cube for serial number [";
84 HandleError(error, &sns, msg);
93 geos::geom::MultiPolygon *tmp = PolygonTools::MakeMultiPolygon(poly->
Polys());
98 geos::geom::MultiPolygon *mp = NULL;
101 if(!tmp->isValid()) {
105 "] has an invalid footprint";
110 mp = PolygonTools::Despike(tmp);
113 if (tmp->isValid()) {
120 HandleError(e, &sns);
125 p_lonLatOverlapsMutex.lock();
126 p_lonLatOverlaps.push_back(CreateNewOverlap(sns.
serialNumber(i), mp));
127 p_lonLatOverlapsMutex.unlock();
142 DespikeLonLatOverlaps();
144 if (p_threadedCalculate) {
150 FindAllOverlaps(&sns);
170 void ImageOverlapSet::FindImageOverlaps(
SerialNumberList &boundaries, QString outputFile) {
173 if (!p_lonLatOverlaps.empty()) {
174 string msg =
"FindImageOverlaps(SerialNumberList&,QString) may not be called on " \
175 "an ImageOverlapSet which already contains overlaps.";
180 p_calculatedSoFar = -1;
182 p_snlist = &boundaries;
185 p_threadedCalculate =
true;
187 FindImageOverlaps(boundaries);
191 while (p_calculatedSoFar != p_lonLatOverlaps.size()) {
192 WriteImageOverlaps(outputFile);
196 if (p_calculatedSoFar != p_writtenSoFar)
197 WriteImageOverlaps(outputFile);
204 p_lonLatOverlaps.clear();
206 p_calculatedSoFar = -1;
207 p_threadedCalculate =
false;
300 void ImageOverlapSet::FindImageOverlaps(std::vector<QString> sns,
301 std::vector<geos::geom::MultiPolygon *> polygons) {
303 if (sns.size() != polygons.size()) {
304 string message =
"Invalid argument sizes. Sizes must match.";
309 for (
unsigned int i = 0; i < sns.size(); ++i) {
310 p_lonLatOverlapsMutex.lock();
311 p_lonLatOverlaps.push_back(CreateNewOverlap(sns[i], polygons[i]));
312 p_lonLatOverlapsMutex.unlock();
316 DespikeLonLatOverlaps();
328 void ImageOverlapSet::ReadImageOverlaps(
const QString &filename) {
334 std::ifstream inStream;
335 QByteArray fileArray = file.toLatin1();
336 inStream.open(fileArray.constData(), fstream::in | fstream::binary);
338 while (!inStream.eof()) {
339 p_lonLatOverlapsMutex.lock();
341 p_lonLatOverlapsMutex.unlock();
347 p_lonLatOverlapsMutex.unlock();
348 QString msg =
"The overlap file [" + filename +
"] does not contain a " 349 "valid list of image overlaps";
353 p_lonLatOverlapsMutex.unlock();
354 QString msg =
"The overlap file [" + filename +
"] does not contain a " 355 "valid list of image overlaps";
378 bool ImageOverlapSet::SetPolygon(geos::geom::Geometry *poly,
383 bool success =
false;
384 geos::geom::MultiPolygon *multiPolygon = PolygonTools::MakeMultiPolygon(poly);
388 if (!multiPolygon->isValid() ||
389 (multiPolygon->getArea() < 1.0e-10 && !multiPolygon->isEmpty())) {
391 multiPolygon = Isis::globalFactory.createMultiPolygon();
394 if (position > p_lonLatOverlaps.size()) {
395 position = p_lonLatOverlaps.size();
399 if (!multiPolygon->isEmpty()) {
400 geos::geom::MultiPolygon *despiked = PolygonTools::Despike(multiPolygon);
402 multiPolygon = despiked;
408 if (multiPolygon->isValid() &&
409 (multiPolygon->isEmpty() || multiPolygon->getArea() > 1.0e-14)) {
411 p_lonLatOverlaps.at(position)->SetPolygon(multiPolygon);
414 AddSerialNumbers(p_lonLatOverlaps.at(position), sncopy);
417 else if (!multiPolygon->isEmpty()) {
424 AddSerialNumbers(imageOverlap, sncopy);
429 p_lonLatOverlapsMutex.lock();
430 p_lonLatOverlaps.insert(p_lonLatOverlaps.begin() + position, imageOverlap);
431 p_lonLatOverlapsMutex.unlock();
446 void ImageOverlapSet::WriteImageOverlaps(
const QString &filename) {
450 bool noOverlaps =
false;
452 if (p_threadedCalculate) {
453 p_calculatePolygonMutex.lock();
458 std::ofstream outStream;
460 QByteArray fileArray = file.toLatin1();
461 if (p_writtenSoFar == 0) {
462 outStream.open(fileArray.constData(), fstream::out | fstream::trunc | fstream::binary);
465 outStream.open(fileArray.constData(), fstream::out | fstream::app | fstream::binary);
468 failed |= outStream.fail();
470 static bool overlapWritten =
false;
471 for (
int overlap = p_writtenSoFar; !failed && overlap <= p_calculatedSoFar; overlap++) {
473 p_lonLatOverlapsMutex.lock();
475 if (p_lonLatOverlaps.size() == 0) {
479 if (overlap < p_lonLatOverlaps.size() && p_lonLatOverlaps[overlap]) {
481 if (!p_lonLatOverlaps[overlap]->Polygon()->isEmpty()) {
483 if (overlapWritten) {
484 outStream << std::endl;
487 p_lonLatOverlaps[overlap]->Write(outStream);
488 overlapWritten =
true;
491 delete p_lonLatOverlaps[overlap];
492 p_lonLatOverlaps[overlap] = NULL;
496 p_lonLatOverlapsMutex.unlock();
499 failed |= outStream.fail();
502 failed |= outStream.fail();
512 if (p_calculatedSoFar == p_lonLatOverlaps.size()) {
513 if (p_threadedCalculate && !noOverlaps) {
514 p_calculatePolygonMutex.tryLock();
515 p_calculatePolygonMutex.unlock();
520 p_calculatePolygonMutex.tryLock();
521 p_calculatePolygonMutex.unlock();
522 QString msg =
"Unable to write the image overlap list to [" + filename +
"]";
525 else if (noOverlaps) {
526 p_calculatePolygonMutex.tryLock();
527 p_calculatePolygonMutex.unlock();
528 QString msg =
"No overlaps were found.";
542 bool foundOverlap =
false;
543 if (p_lonLatOverlaps.size() <= 1)
return;
546 p.
SetText(
"Calculating Image Overlaps");
550 geos::geom::MultiPolygon *emptyPolygon = Isis::globalFactory.createMultiPolygon();
553 for (
int outside = 0; outside < p_lonLatOverlaps.size() - 1; ++outside) {
554 p_calculatedSoFar = outside - 1;
557 if (p_calculatedSoFar % 10 == 0 && (!snlist || (p_lonLatOverlaps.size() > snlist->
size()))) {
558 if (p_threadedCalculate) {
559 p_calculatePolygonMutex.tryLock();
560 p_calculatePolygonMutex.unlock();
566 for (
int inside = outside + 1; inside < p_lonLatOverlaps.size(); ++inside) {
568 if (p_lonLatOverlaps.at(outside)->HasAnySameSerialNumber(*p_lonLatOverlaps.at(inside)))
572 const geos::geom::MultiPolygon *poly1 = p_lonLatOverlaps.at(outside)->Polygon();
573 const geos::geom::MultiPolygon *poly2 = p_lonLatOverlaps.at(inside)->Polygon();
577 if (PolygonTools::Equal(poly1, poly2)) {
578 p_lonLatOverlapsMutex.lock();
579 AddSerialNumbers(p_lonLatOverlaps[outside], p_lonLatOverlaps[inside]);
580 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
581 p_lonLatOverlapsMutex.unlock();
587 if (poly2->isEmpty() || poly2->getArea() < 1.0e-14) {
588 p_lonLatOverlapsMutex.lock();
589 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
590 p_lonLatOverlapsMutex.unlock();
595 geos::geom::Geometry *intersected = NULL;
597 intersected = PolygonTools::Intersect(poly1, poly2);
601 QString error =
"Intersection of overlaps failed.";
606 double outsideArea = poly1->getArea();
607 double insideArea = poly2->getArea();
608 double areaRatio = std::min(outsideArea, insideArea) /
609 std::max(outsideArea, insideArea);
614 if (areaRatio < 0.1) {
615 if (poly1->getArea() > poly2->getArea()) {
616 error +=
" The first polygon will be removed.";
617 HandleError(e, snlist, error, inside, outside);
618 p_lonLatOverlapsMutex.lock();
619 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
620 p_lonLatOverlapsMutex.unlock();
624 error +=
" The second polygon will be removed.";
625 HandleError(e, snlist, error, inside, outside);
626 p_lonLatOverlapsMutex.lock();
627 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + outside);
628 p_lonLatOverlapsMutex.unlock();
633 error +=
" Both polygons will be removed to prevent the " 634 "possibility of double counted areas.";
635 HandleError(e, snlist, error, inside, outside);
636 p_lonLatOverlapsMutex.lock();
637 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
638 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + outside);
639 p_lonLatOverlapsMutex.unlock();
646 if (intersected->isEmpty() || intersected->getArea() < 1.0e-14) {
655 geos::geom::MultiPolygon *overlap = NULL;
657 overlap = PolygonTools::Despike(intersected);
663 if (!intersected->isValid()) {
667 HandleError(e, snlist,
"", inside, outside);
671 overlap = PolygonTools::MakeMultiPolygon(intersected);
677 catch (geos::util::GEOSException *exc) {
680 HandleError(exc, snlist,
"", inside, outside);
684 if (!overlap->isValid()) {
687 HandleError(snlist,
"Intersection produced invalid overlap area", inside, outside);
692 if (overlap->isEmpty() || overlap->getArea() < 1.0e-14) {
699 if (PolygonTools::Equal(poly1, overlap)) {
700 geos::geom::Geometry *tmpGeom = NULL;
702 tmpGeom = PolygonTools::Difference(poly2, poly1);
705 HandleError(e, snlist,
"Differencing overlap polygons failed." 706 "The first polygon will be removed.", inside, outside);
710 p_lonLatOverlapsMutex.lock();
711 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + outside);
712 p_lonLatOverlapsMutex.unlock();
716 if (SetPolygon(tmpGeom, inside) &&
717 SetPolygon(overlap, outside, p_lonLatOverlaps[inside]))
721 else if (PolygonTools::Equal(poly2, overlap)) {
722 geos::geom::Geometry *tmpGeom = NULL;
724 tmpGeom = PolygonTools::Difference(poly1, poly2);
727 HandleError(e, snlist,
"Differencing overlap polygons failed." 728 "The second polygon will be removed.", inside, outside);
731 p_lonLatOverlapsMutex.lock();
732 p_lonLatOverlaps.erase(p_lonLatOverlaps.begin() + inside);
733 p_lonLatOverlapsMutex.unlock();
737 if (SetPolygon(tmpGeom, outside) &&
738 SetPolygon(overlap, inside, p_lonLatOverlaps[outside]))
744 geos::geom::Geometry *tmpGeom = NULL;
746 tmpGeom = PolygonTools::Difference(poly1, overlap);
755 if (tmpGeom == NULL) {
756 tmpGeom = PolygonTools::Difference(poly1, poly2);
761 HandleError(e, snlist,
"Differencing overlap polygons failed", inside, outside);
765 if (!SetPolygon(tmpGeom, outside)) {
766 if (SetPolygon(Isis::globalFactory.createMultiPolygon(), outside))
770 int oldSize = p_lonLatOverlaps.size();
771 if (SetPolygon(overlap, inside + 1, p_lonLatOverlaps[outside],
true)) {
772 int newSize = p_lonLatOverlaps.size();
773 int newSteps = newSize - oldSize;
776 if (newSize != oldSize) inside++;
782 HandleError(e, snlist,
"Unable to find overlap.", inside, outside);
785 catch (geos::util::IllegalArgumentException *ill) {
786 HandleError(NULL, snlist,
"Unable to find overlap", inside, outside);
788 catch (geos::util::GEOSException *exc) {
789 HandleError(exc, snlist,
"Unable to find overlap", inside, outside);
792 HandleError(snlist,
"Unknown Error: Unable to find overlap", inside, outside);
799 p_calculatedSoFar = p_lonLatOverlaps.size();
803 if (foundOverlap ==
false) {
804 p_lonLatOverlapsMutex.lock();
805 p_lonLatOverlaps.clear();
806 p_lonLatOverlapsMutex.unlock();
812 p_calculatePolygonMutex.tryLock();
813 p_calculatePolygonMutex.unlock();
827 for (
int i = 0; i < from->Size(); i++) {
828 QString s = (*from)[i];
841 geos::geom::MultiPolygon *latLonPolygon) {
858 std::vector<ImageOverlap *> ImageOverlapSet::operator[](QString serialNumber) {
860 vector<ImageOverlap *> matches;
864 for (
int ov = 0; ov < p_lonLatOverlaps.size(); ++ov) {
865 for (
int sn = 0; sn < p_lonLatOverlaps[ov]->Size(); ++sn) {
866 if ((*p_lonLatOverlaps[ov])[sn] == serialNumber) {
867 matches.push_back(p_lonLatOverlaps[ov]);
889 int overlap1,
int overlap2) {
893 if (overlap1 >= 0 && overlap1 < p_lonLatOverlaps.size()) {
894 PvlKeyword serialNumbers(
"PolySerialNumbers");
898 for (
int i = 0; i < p_lonLatOverlaps.at(overlap1)->Size(); i++) {
899 serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i];
901 if (snlist != NULL) {
902 filename += snlist->
fileName((*p_lonLatOverlaps.at(overlap1))[i]);
905 polygon += p_lonLatOverlaps.at(overlap1)->Polygon()->toString().c_str();
907 err += serialNumbers;
909 if (filename.
size() != 0) {
916 if (overlap2 >= 0 && overlap1 < p_lonLatOverlaps.size() &&
917 overlap2 < p_lonLatOverlaps.size()) {
918 PvlKeyword serialNumbers(
"PolySerialNumbers");
922 for (
int i = 0; i < p_lonLatOverlaps.at(overlap2)->Size(); i++) {
923 serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i];
925 if (snlist != NULL) {
926 filename += snlist->
fileName((*p_lonLatOverlaps.at(overlap2))[i]);
929 polygon += p_lonLatOverlaps.at(overlap2)->Polygon()->toString().c_str();
931 err += serialNumbers;
933 if (filename.
size() != 0) {
942 if (!msg.isEmpty()) {
946 p_errorLog.push_back(err);
948 if (!p_continueAfterError)
throw;
962 void ImageOverlapSet::HandleError(geos::util::GEOSException *exc,
965 int overlap1,
int overlap2) {
969 if (overlap1 >= 0 && overlap1 < p_lonLatOverlaps.size()) {
970 PvlKeyword serialNumbers(
"PolySerialNumbers");
973 for (
int i = 0; i < p_lonLatOverlaps.at(overlap1)->Size(); i++) {
974 serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i];
976 if (snlist != NULL) {
977 filename += snlist->
fileName((*p_lonLatOverlaps.at(overlap1))[i]);
981 err += serialNumbers;
983 if (filename.
size() != 0) {
988 if (overlap2 >= 0 && overlap1 < p_lonLatOverlaps.size() &&
989 overlap2 < p_lonLatOverlaps.size()) {
990 PvlKeyword serialNumbers(
"PolySerialNumbers");
993 for (
int i = 0; i < p_lonLatOverlaps.at(overlap2)->Size(); i++) {
994 serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i];
996 if (snlist != NULL) {
997 filename += snlist->
fileName((*p_lonLatOverlaps.at(overlap2))[i]);
1001 err += serialNumbers;
1003 if (filename.
size() != 0) {
1010 if (!msg.isEmpty()) {
1014 p_errorLog.push_back(err);
1018 if (!p_continueAfterError) {
1035 int overlap1,
int overlap2) {
1039 if (overlap1 >= 0 && overlap1 < p_lonLatOverlaps.size()) {
1040 PvlKeyword serialNumbers(
"PolySerialNumbers");
1043 for (
int i = 0; i < p_lonLatOverlaps.at(overlap1)->Size(); i++) {
1044 serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i];
1046 if (snlist != NULL) {
1047 filename += snlist->
fileName((*p_lonLatOverlaps.at(overlap1))[i]);
1051 err += serialNumbers;
1053 if (filename.
size() != 0) {
1058 if (overlap2 >= 0 && overlap1 < p_lonLatOverlaps.size() &&
1059 overlap2 < p_lonLatOverlaps.size()) {
1060 PvlKeyword serialNumbers(
"PolySerialNumbers");
1063 for (
int i = 0; i < p_lonLatOverlaps.at(overlap2)->Size(); i++) {
1064 serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i];
1066 if (snlist != NULL) {
1067 filename += snlist->
fileName((*p_lonLatOverlaps.at(overlap2))[i]);
1071 err += serialNumbers;
1073 if (filename.
size() != 0) {
1080 p_errorLog.push_back(err);
1082 if (!p_continueAfterError) {
1093 void ImageOverlapSet::DespikeLonLatOverlaps() {
1095 for (
int i = 0; i < Size(); i++) {
1097 p_lonLatOverlaps[i]->SetPolygon(PolygonTools::Despike(p_lonLatOverlaps[i]->Polygon()));
const char * what() const
Returns a string representation of this exception in its current state.
void SetMaximumSteps(const int steps)
This sets the maximum number of steps in the process.
File name manipulation and expansion.
QString serialNumber(const QString &filename)
Return a serial number given a filename.
void Add(QString &sn)
This method will add a new serial number to the list of serial numbers alread associated with the ove...
Namespace for the standard library.
virtual void SetPolygon(const geos::geom::MultiPolygon &polygon)
This method will replace the existing polygon that defines the overlap with a new one...
Create cube polygons, read/write polygons to blobs.
void CheckStatus()
Checks and updates the status.
QString fileName(const QString &sn)
Return a filename given a serial number.
Program progress reporter.
int size() const
Returns the number of values stored in this keyword.
void AddSteps(const int steps)
If the initial step size was a guess, it can be modified using this method.
void SetText(const QString &text)
Changes the value of the text string reported just before 0% processed.
Contains multiple PvlContainers.
#define _FILEINFO_
Macro for the filename and line number.
A single keyword-value pair.
void close(bool remove=false)
Closes the cube and updates the labels.
void read(Blob &blob) const
This method will read data from the specified Blob object.
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
void open(const QString &cfile, QString access="r")
This method will open an isis cube for reading or reading/writing.
int size() const
How many serial number / filename combos are in the list.
Namespace for ISIS/Bullet specific routines.
Individual overlap container.
geos::geom::MultiPolygon * Polys()
Return a geos Multipolygon.
Serial Number list generator.
IO Handler for Isis Cubes.