Skip to content

Commit

Permalink
Merge pull request #10949 from rouault/safe_footprint
Browse files Browse the repository at this point in the history
SAFE (Sentinel1): report a FOOTPRINT metadata item
  • Loading branch information
rouault authored Oct 8, 2024
2 parents c83a64b + 6d3b00f commit d652760
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 35 deletions.
6 changes: 6 additions & 0 deletions autotest/gdrivers/safe.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ def test_safe_1():
tst = gdaltest.GDALTest("SAFE", "SAFE_FAKE/test.SAFE/manifest.safe", 1, 65372)
tst.testOpen()

ds = gdal.Open("data/SAFE_FAKE/test.SAFE/manifest.safe")
assert (
ds.GetMetadataItem("FOOTPRINT")
== "POLYGON((-8.407759 38.130520,-11.335915 38.535374,-11.026125 40.036644,-8.035001 39.633217, -8.407759 38.130520))"
)


def test_safe_2():

Expand Down
95 changes: 66 additions & 29 deletions frmts/safe/safedataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,6 @@ SAFEDataset::~SAFEDataset()
{
SAFEDataset::FlushCache(true);

CPLDestroyXMLNode(psManifest);
if (nGCPCount > 0)
{
GDALDeinitGCPs(nGCPCount, pasGCPList);
Expand Down Expand Up @@ -657,13 +656,14 @@ int SAFEDataset::CloseDependentDatasets()
/* GetMetaDataObject() */
/************************************************************************/

CPLXMLNode *SAFEDataset::GetMetaDataObject(CPLXMLNode *psMetaDataObjects,
const char *metadataObjectId)
const CPLXMLNode *
SAFEDataset::GetMetaDataObject(const CPLXMLNode *psMetaDataObjects,
const char *metadataObjectId)
{
/* -------------------------------------------------------------------- */
/* Look for DataObject Element by ID. */
/* -------------------------------------------------------------------- */
for (CPLXMLNode *psMDO = psMetaDataObjects->psChild; psMDO != nullptr;
for (const CPLXMLNode *psMDO = psMetaDataObjects->psChild; psMDO != nullptr;
psMDO = psMDO->psNext)
{
if (psMDO->eType != CXT_Element ||
Expand All @@ -690,13 +690,13 @@ CPLXMLNode *SAFEDataset::GetMetaDataObject(CPLXMLNode *psMetaDataObjects,
/* GetDataObject() */
/************************************************************************/

CPLXMLNode *SAFEDataset::GetDataObject(CPLXMLNode *psDataObjects,
const char *dataObjectId)
const CPLXMLNode *SAFEDataset::GetDataObject(const CPLXMLNode *psDataObjects,
const char *dataObjectId)
{
/* -------------------------------------------------------------------- */
/* Look for DataObject Element by ID. */
/* -------------------------------------------------------------------- */
for (CPLXMLNode *psDO = psDataObjects->psChild; psDO != nullptr;
for (const CPLXMLNode *psDO = psDataObjects->psChild; psDO != nullptr;
psDO = psDO->psNext)
{
if (psDO->eType != CXT_Element ||
Expand All @@ -719,14 +719,15 @@ CPLXMLNode *SAFEDataset::GetDataObject(CPLXMLNode *psDataObjects,
return nullptr;
}

CPLXMLNode *SAFEDataset::GetDataObject(CPLXMLNode *psMetaDataObjects,
CPLXMLNode *psDataObjects,
const char *metadataObjectId)
const CPLXMLNode *
SAFEDataset::GetDataObject(const CPLXMLNode *psMetaDataObjects,
const CPLXMLNode *psDataObjects,
const char *metadataObjectId)
{
/* -------------------------------------------------------------------- */
/* Look for MetadataObject Element by ID. */
/* -------------------------------------------------------------------- */
CPLXMLNode *psMDO =
const CPLXMLNode *psMDO =
SAFEDataset::GetMetaDataObject(psMetaDataObjects, metadataObjectId);

if (psMDO != nullptr)
Expand Down Expand Up @@ -989,7 +990,7 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* Ingest the manifest.safe file. */
/* -------------------------------------------------------------------- */

CPLXMLNode *psManifest = CPLParseXMLFile(osMDFilename);
auto psManifest = CPLXMLTreeCloser(CPLParseXMLFile(osMDFilename));
if (psManifest == nullptr)
return nullptr;

Expand All @@ -1000,7 +1001,6 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
if (poOpenInfo->eAccess == GA_Update)
{
CPLDestroyXMLNode(psManifest);
CPLError(CE_Failure, CPLE_NotSupported,
"The SAFE driver does not support update access to existing"
" datasets.\n");
Expand All @@ -1010,11 +1010,10 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
/* Get contentUnit parent element. */
/* -------------------------------------------------------------------- */
CPLXMLNode *psContentUnits = CPLGetXMLNode(
psManifest, "=xfdu:XFDU.informationPackageMap.xfdu:contentUnit");
const CPLXMLNode *psContentUnits = CPLGetXMLNode(
psManifest.get(), "=xfdu:XFDU.informationPackageMap.xfdu:contentUnit");
if (psContentUnits == nullptr)
{
CPLDestroyXMLNode(psManifest);
CPLError(CE_Failure, CPLE_OpenFailed,
"Failed to find <xfdu:XFDU><informationPackageMap>"
"<xfdu:contentUnit> in manifest file.");
Expand All @@ -1024,11 +1023,10 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
/* Get Metadata Objects element. */
/* -------------------------------------------------------------------- */
CPLXMLNode *psMetaDataObjects =
CPLGetXMLNode(psManifest, "=xfdu:XFDU.metadataSection");
const CPLXMLNode *psMetaDataObjects =
CPLGetXMLNode(psManifest.get(), "=xfdu:XFDU.metadataSection");
if (psMetaDataObjects == nullptr)
{
CPLDestroyXMLNode(psManifest);
CPLError(CE_Failure, CPLE_OpenFailed,
"Failed to find <xfdu:XFDU><metadataSection>"
"in manifest file.");
Expand All @@ -1038,11 +1036,10 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
/* Get Data Objects element. */
/* -------------------------------------------------------------------- */
CPLXMLNode *psDataObjects =
CPLGetXMLNode(psManifest, "=xfdu:XFDU.dataObjectSection");
const CPLXMLNode *psDataObjects =
CPLGetXMLNode(psManifest.get(), "=xfdu:XFDU.dataObjectSection");
if (psDataObjects == nullptr)
{
CPLDestroyXMLNode(psManifest);
CPLError(CE_Failure, CPLE_OpenFailed,
"Failed to find <xfdu:XFDU><dataObjectSection> in document.");
return nullptr;
Expand All @@ -1053,7 +1050,7 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
auto poDS = std::make_unique<SAFEDataset>();

poDS->psManifest = psManifest;
poDS->psManifest = std::move(psManifest);

/* -------------------------------------------------------------------- */
/* Look for "Measurement Data Unit" contentUnit elements. */
Expand Down Expand Up @@ -1087,7 +1084,7 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
if (*pszDataObjectID == '\0' || *pszDmdID == '\0')
continue;

CPLXMLNode *psDataObject =
const CPLXMLNode *psDataObject =
SAFEDataset::GetDataObject(psDataObjects, pszDataObjectID);

const char *pszRepId = CPLGetXMLValue(psDataObject, "repID", "");
Expand All @@ -1111,7 +1108,7 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
continue;

// Map the metadata ID to the object element
CPLXMLNode *psDO = SAFEDataset::GetDataObject(
const CPLXMLNode *psDO = SAFEDataset::GetDataObject(
psMetaDataObjects, psDataObjects, pszId);
if (psDO == nullptr)
continue;
Expand Down Expand Up @@ -1731,7 +1728,7 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
/* Platform information */
/* -------------------------------------------------------------------- */
CPLXMLNode *psPlatformAttrs =
const CPLXMLNode *psPlatformAttrs =
SAFEDataset::GetMetaDataObject(psMetaDataObjects, "platform");

if (psPlatformAttrs != nullptr)
Expand Down Expand Up @@ -1768,7 +1765,7 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
/* Acquisition Period information */
/* -------------------------------------------------------------------- */
CPLXMLNode *psAcquisitionAttrs =
const CPLXMLNode *psAcquisitionAttrs =
SAFEDataset::GetMetaDataObject(psMetaDataObjects, "acquisitionPeriod");

if (psAcquisitionAttrs != nullptr)
Expand All @@ -1789,7 +1786,7 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
/* Processing information */
/* -------------------------------------------------------------------- */
CPLXMLNode *psProcessingAttrs =
const CPLXMLNode *psProcessingAttrs =
SAFEDataset::GetMetaDataObject(psMetaDataObjects, "processing");

if (psProcessingAttrs != nullptr)
Expand All @@ -1803,7 +1800,7 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
/* -------------------------------------------------------------------- */
/* Measurement Orbit Reference information */
/* -------------------------------------------------------------------- */
CPLXMLNode *psOrbitAttrs = SAFEDataset::GetMetaDataObject(
const CPLXMLNode *psOrbitAttrs = SAFEDataset::GetMetaDataObject(
psMetaDataObjects, "measurementOrbitReference");

if (psOrbitAttrs != nullptr)
Expand All @@ -1821,6 +1818,46 @@ GDALDataset *SAFEDataset::Open(GDALOpenInfo *poOpenInfo)
poDS->SetMetadataItem("ORBIT_DIRECTION", pszItem);
}

/* -------------------------------------------------------------------- */
/* Footprint */
/* -------------------------------------------------------------------- */
const CPLXMLNode *psFrameSet = SAFEDataset::GetMetaDataObject(
psMetaDataObjects, "measurementFrameSet");

if (psFrameSet)
{
const auto psFootPrint = CPLGetXMLNode(psFrameSet, "metadataWrap."
"xmlData."
"safe:frameSet."
"safe:frame."
"safe:footPrint");
if (psFootPrint)
{
const char *pszSRSName =
CPLGetXMLValue(psFootPrint, "srsName", nullptr);
const char *pszCoordinates =
CPLGetXMLValue(psFootPrint, "gml:coordinates", nullptr);
if (pszSRSName &&
EQUAL(pszSRSName,
"http://www.opengis.net/gml/srs/epsg.xml#4326") &&
pszCoordinates)
{
const CPLStringList aosValues(
CSLTokenizeString2(pszCoordinates, " ,", 0));
if (aosValues.size() == 8)
{
poDS->SetMetadataItem(
"FOOTPRINT",
CPLSPrintf("POLYGON((%s %s,%s %s,%s %s,%s %s, %s %s))",
aosValues[1], aosValues[0], aosValues[3],
aosValues[2], aosValues[5], aosValues[4],
aosValues[7], aosValues[6], aosValues[1],
aosValues[0]));
}
}
}
}

/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
Expand Down
14 changes: 8 additions & 6 deletions frmts/safe/safedataset.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

class SAFEDataset final : public GDALPamDataset
{
CPLXMLNode *psManifest = nullptr;
CPLXMLTreeCloser psManifest{nullptr};

int nGCPCount = 0;
GDAL_GCP *pasGCPList = nullptr;
Expand All @@ -48,10 +48,12 @@ class SAFEDataset final : public GDALPamDataset
protected:
virtual int CloseDependentDatasets() override;

static CPLXMLNode *GetMetaDataObject(CPLXMLNode *, const char *);
static const CPLXMLNode *GetMetaDataObject(const CPLXMLNode *,
const char *);

static CPLXMLNode *GetDataObject(CPLXMLNode *, const char *);
static CPLXMLNode *GetDataObject(CPLXMLNode *, CPLXMLNode *, const char *);
static const CPLXMLNode *GetDataObject(const CPLXMLNode *, const char *);
static const CPLXMLNode *GetDataObject(const CPLXMLNode *,
const CPLXMLNode *, const char *);

void AddSubDataset(const CPLString &osName, const CPLString &osDesc);

Expand All @@ -73,9 +75,9 @@ class SAFEDataset final : public GDALPamDataset
static GDALDataset *Open(GDALOpenInfo *);
static int Identify(GDALOpenInfo *);

CPLXMLNode *GetManifest()
const CPLXMLNode *GetManifest()
{
return psManifest;
return psManifest.get();
}
};

Expand Down

0 comments on commit d652760

Please sign in to comment.