Skip to content

Commit 2f3c73b

Browse files
Adds support for accessing COG shape models from STAC API (#5919)
* grab COG shape models from stac api * Remove silent failures and fixed test * fix test * Make api shape model optional in spiceinit * Adds pull request in changelog * fix md link
1 parent 165f72f commit 2f3c73b

File tree

7 files changed

+104
-1
lines changed

7 files changed

+104
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ ctest FunctionalTestJigsawApollo to validate this output. [#5710](https://github
5555
- Added PAD or SHRINK options to crop for crops that extend beyond the source image [#5843](https://github.com/DOI-USGS/ISIS3/pull/5843)
5656
- Added std:: namespace for isinf, fixes build errors for some versions of c++
5757
- Adds PROJ into ISIS, and exposes the capability with a new class called IProj. [#5317](https://github.com/DOI-USGS/ISIS3/pull/5317)
58+
- Added support for accessing Cloud Optimized GeoTIFF (COG) shape models via STAC API. [#5919](https://github.com/DOI-USGS/ISIS3/pull/5919)
5859

5960
### Changed
6061
- Removed Arm dependency on xalan-c, as it does not build for now on conda-forge. This requires turning off doc building on Arm. Also changed some variables to avoid name clashes on Arm with clang 16. [#5802](https://github.com/DOI-USGS/ISIS3/pull/5802)

isis/src/base/apps/spiceinit/spiceinit.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,15 @@ namespace Isis {
186186
else if (ui.GetString("SHAPE") == "SYSTEM") {
187187
dem = baseKernels.dem(lab);
188188
}
189+
else if (ui.GetString("SHAPE") == "WEB") {
190+
QString tiffUrl = baseKernels.getDemTiffUrl(lab);
191+
if (!tiffUrl.isEmpty()) {
192+
dem.push_back(tiffUrl);
193+
}
194+
else {
195+
dem = baseKernels.dem(lab);
196+
}
197+
}
189198

190199
bool kernelSuccess = false;
191200

isis/src/base/apps/spiceinit/spiceinit.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,16 @@
805805
the <b>ShapeModel</b> keyword.
806806
</description>
807807
</option>
808+
<option value="WEB">
809+
<brief>Search default shape model from ISIS STAC API</brief>
810+
<description>
811+
This option searches the ISIS STAC API for a shape model that matches the target of
812+
the input cube. If no matching shape model is found, spiceinit will fall back to using
813+
SYSTEM to search for a shape model in the data area. The label will contain a vsicurl
814+
URL pointing to the GeoTIFF shape model file in an S3 bucket and can be found in the cube labels
815+
Kernels Group under the <b>ShapeModel</b> keyword.
816+
</description>
817+
</option>
808818
</list>
809819
</parameter>
810820

isis/src/system/objs/KernelDb/KernelDb.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,55 @@ namespace Isis {
691691
return matchKeywords && matchTime;
692692
}
693693

694+
QString KernelDb::getDemTiffUrl(const Pvl &lab) {
695+
QString tiffUrl;
696+
697+
PvlGroup inst = lab.findGroup("Instrument", Pvl::Traverse);
698+
std::string target = (inst.findKeyword("TargetName")[0]).toStdString();
699+
700+
std::string url = "https://3hr5l9mbj6.execute-api.us-west-2.amazonaws.com/prod/search";
701+
std::string jsonData = "{ \"query\": { \"target\": {\"eq\": \"" + target + "\"} } }";
702+
703+
704+
std::string responseBody = curlPostRequest(url, jsonData);
705+
706+
auto json = nlohmann::json::parse(responseBody);
707+
708+
if (json.contains("tiff_url")) {
709+
tiffUrl = "/vsicurl/" + QString::fromStdString(json["tiff_url"]);
710+
}
711+
712+
return tiffUrl;
713+
}
714+
715+
std::string KernelDb::curlPostRequest(const std::string url, const std::string jsonData) {
716+
CURL *curl = curl_easy_init();
717+
if (!curl) {
718+
throw IException(IException::Programmer, "Failed to initialize CURL", _FILEINFO_);
719+
}
720+
721+
std::string responseBody;
722+
struct curl_slist* headers = nullptr;
723+
headers = curl_slist_append(headers, "Content-Type: application/json");
724+
725+
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
726+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
727+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());
728+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &KernelDb::writeCallback);
729+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBody);
730+
731+
CURLcode res = curl_easy_perform(curl);
732+
733+
curl_easy_cleanup(curl);
734+
curl_slist_free_all(headers);
735+
736+
if (res != CURLE_OK) {
737+
throw IException(IException::Io, "CURL error: " + QString(curl_easy_strerror(res)), _FILEINFO_);
738+
}
739+
740+
return responseBody;
741+
}
742+
694743
/**
695744
* Loads the appropriate kernel database files with the defined BASE and
696745
* MISSION info for each type of kernel.

isis/src/system/objs/KernelDb/KernelDb.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ find files of those names at the top level of this repository. **/
2020
#include "iTime.h"//???
2121
#include "Kernel.h"
2222
#include "Pvl.h"
23+
#include <curl/curl.h>
2324

2425
class KernelDbFixture_TestKernelsSmithOffset_Test;
2526

@@ -121,6 +122,9 @@ namespace Isis {
121122
Kernel frame(Pvl &lab);
122123
Kernel instrumentAddendum(Pvl &lab);
123124
Kernel dem(Pvl &lab);
125+
QString getDemTiffUrl(const Pvl &lab);
126+
127+
virtual std::string curlPostRequest(const std::string url, const std::string jsonData);
124128

125129
Kernel findLast(const QString &entry, Pvl &lab);
126130
QList< std::priority_queue<Kernel> > findAll(const QString &entry,
@@ -156,6 +160,16 @@ namespace Isis {
156160
Pvl m_kernelData; /**< Pvl containing the information in the kernel
157161
database(s) that is read in from the constructor
158162
and whenever the loadSystemDb() method is called.*/
163+
164+
static size_t writeCallback(void* ptr, size_t size, size_t nmemb, void* userdata){
165+
const size_t total = size * nmemb;
166+
if (!ptr || !userdata || total == 0) return 0;
167+
168+
auto* response = static_cast<std::string*>(userdata);
169+
response->append(static_cast<char*>(ptr), total);
170+
171+
return total;
172+
}
159173
};
160174
};
161175

isis/tests/KernelDbTests.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "FileName.h"
88
#include "KernelDb.h"
9+
#include "Mocks.h"
910
#include "Pvl.h"
1011
#include "PvlGroup.h"
1112
#include "TestUtilities.h"
@@ -47,6 +48,7 @@ class KernelDbFixture : public ::testing::Test {
4748
Group = Instrument
4849
SpacecraftName = IdealSpacecraft
4950
InstrumentId = IdealCamera
51+
TargetName = Mars
5052
StartTime = "2005 JUN 15 12:00:00.000 TDB"
5153
StopTime = "2005 DEC 15 12:00:00.000 TDB"
5254
End_Group
@@ -294,7 +296,7 @@ TEST_F(KernelDbFixture, SystemKernels) {
294296
ASSERT_EQ(dbFiles.size(), 10);
295297

296298
QStringList tspks = db.targetPosition(cubeLabel).kernels();
297-
ASSERT_EQ(tspks.size(), 1);
299+
ASSERT_EQ(tspks.size(), 2);
298300
EXPECT_PRED_FORMAT2(AssertQStringsEqual, tspks[0], "$base/kernels/spk/de430.bsp");
299301

300302
QList< std::priority_queue<Kernel> > cklist = db.spacecraftPointing(cubeLabel);
@@ -362,3 +364,13 @@ TEST_F(KernelDbFixture, TestKernelsSmithOffset) {
362364
QStringList cklist = cKernels.kernels();
363365
EXPECT_PRED_FORMAT2(AssertQStringsEqual, cklist[0], "data/kerneldbgen/thmIR.bc");
364366
}
367+
368+
TEST_F(KernelDbFixture, TestDemTiffUrl) {
369+
MockKernelDb db(Kernel::Predicted);
370+
371+
EXPECT_CALL(db, curlPostRequest(testing::_, testing::_))
372+
.WillOnce(testing::Return("{\"id\": \"molaMarsPlanetaryRadius0005\", \"tiff_url\": \"https://asc-isisdata.s3.us-west-2.amazonaws.com/isis-stac/isis-dtm-collection/molaMarsPlanetaryRadius0005.tiff\"}"));
373+
374+
QString url = db.getDemTiffUrl(cubeLabel);
375+
EXPECT_PRED_FORMAT2(AssertQStringsEqual, url, "/vsicurl/https://asc-isisdata.s3.us-west-2.amazonaws.com/isis-stac/isis-dtm-collection/molaMarsPlanetaryRadius0005.tiff");
376+
}

isis/tests/Mocks.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "Distance.h"
1313
#include "Interpolator.h"
1414
#include "iTime.h"
15+
#include "KernelDb.h"
1516
#include "Latitude.h"
1617
#include "Longitude.h"
1718
#include "Process.h"
@@ -69,6 +70,13 @@ class MockCamera : public Camera {
6970
MOCK_METHOD(iTime, time, (), (const, override));
7071
};
7172

73+
74+
class MockKernelDb : public KernelDb {
75+
public:
76+
MockKernelDb(Kernel::Type type) : KernelDb(type) {}
77+
MOCK_METHOD(std::string, curlPostRequest, (const std::string url, const std::string jsonData), (override));
78+
};
79+
7280
class MockTProjection : public TProjection {
7381
public:
7482
MockTProjection(Pvl &label): TProjection(label) {}

0 commit comments

Comments
 (0)