Skip to content

Commit

Permalink
gdal vector: make 'read', 'clip' and 'reproject' compatible of OSM-ty…
Browse files Browse the repository at this point in the history
…pe of datasources that require ODsCRandomLayerRead

On-the-fly reading of OSM requires to be able to iterate over features
at the dataset level, and not just at the layer level. Let's implement
that.
  • Loading branch information
rouault committed Feb 11, 2025
1 parent 51ee293 commit 6291ae5
Show file tree
Hide file tree
Showing 17 changed files with 676 additions and 125 deletions.
147 changes: 59 additions & 88 deletions apps/gdalalg_vector_clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,129 +65,99 @@ GDALVectorClipAlgorithm::GDALVectorClipAlgorithm(bool standaloneStep)

namespace
{
class GDALVectorClipAlgorithmLayer final
: public OGRLayer,
public OGRGetNextFeatureThroughRaw<GDALVectorClipAlgorithmLayer>
class GDALVectorClipAlgorithmLayer final : public GDALVectorPipelineOutputLayer
{

DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(GDALVectorClipAlgorithmLayer)

public:
GDALVectorClipAlgorithmLayer(OGRLayer *poSrcLayer,
GDALVectorClipAlgorithmLayer(OGRLayer &oSrcLayer,
std::unique_ptr<OGRGeometry> poClipGeom)
: m_poSrcLayer(poSrcLayer), m_poClipGeom(std::move(poClipGeom)),
m_eSrcLayerGeomType(m_poSrcLayer->GetGeomType()),
: GDALVectorPipelineOutputLayer(oSrcLayer),
m_poClipGeom(std::move(poClipGeom)),
m_eSrcLayerGeomType(oSrcLayer.GetGeomType()),
m_eFlattenSrcLayerGeomType(wkbFlatten(m_eSrcLayerGeomType)),
m_bSrcLayerGeomTypeIsCollection(OGR_GT_IsSubClassOf(
m_eFlattenSrcLayerGeomType, wkbGeometryCollection))
{
SetDescription(poSrcLayer->GetDescription());
poSrcLayer->SetSpatialFilter(m_poClipGeom.get());
SetDescription(oSrcLayer.GetDescription());
oSrcLayer.SetSpatialFilter(m_poClipGeom.get());
}

OGRFeatureDefn *GetLayerDefn() override
{
return m_poSrcLayer->GetLayerDefn();
}

void ResetReading() override
{
m_poSrcLayer->ResetReading();
m_poSrcFeature.reset();
m_poCurGeomColl.reset();
m_idxInCurGeomColl = 0;
return m_srcLayer.GetLayerDefn();
}

OGRFeature *GetNextRawFeature()
void TranslateFeature(
std::unique_ptr<OGRFeature> poSrcFeature,
std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
{
if (m_poSrcFeature && m_poCurGeomColl)
auto poGeom = poSrcFeature->GetGeometryRef();
if (!poGeom)
return;

auto poIntersection = std::unique_ptr<OGRGeometry>(
poGeom->Intersection(m_poClipGeom.get()));
if (!poIntersection)
return;

const auto eFeatGeomType =
wkbFlatten(poIntersection->getGeometryType());
if (m_eFlattenSrcLayerGeomType != wkbUnknown &&
m_eFlattenSrcLayerGeomType != eFeatGeomType)
{
while (m_idxInCurGeomColl < m_poCurGeomColl->getNumGeometries())
// If the intersection is a collection of geometry and the
// layer geometry type is of non-collection type, create
// one feature per element of the collection.
if (!m_bSrcLayerGeomTypeIsCollection &&
OGR_GT_IsSubClassOf(eFeatGeomType, wkbGeometryCollection))
{
const auto poGeom =
m_poCurGeomColl->getGeometryRef(m_idxInCurGeomColl);
++m_idxInCurGeomColl;
if (m_eFlattenSrcLayerGeomType == wkbUnknown ||
m_eFlattenSrcLayerGeomType ==
wkbFlatten(poGeom->getGeometryType()))
auto poGeomColl = std::unique_ptr<OGRGeometryCollection>(
poIntersection.release()->toGeometryCollection());
for (const auto *poSubGeom : poGeomColl.get())
{
auto poDstFeature =
std::unique_ptr<OGRFeature>(m_poSrcFeature->Clone());
poDstFeature->SetGeometry(poGeom);
return poDstFeature.release();
std::unique_ptr<OGRFeature>(poSrcFeature->Clone());
poDstFeature->SetGeometry(poSubGeom);
apoOutFeatures.push_back(std::move(poDstFeature));
}
}
m_poSrcFeature.reset();
m_poCurGeomColl.reset();
m_idxInCurGeomColl = 0;
}

while (auto poFeature =
std::unique_ptr<OGRFeature>(m_poSrcLayer->GetNextFeature()))
{
auto poGeom = poFeature->GetGeometryRef();
if (!poGeom)
continue;

auto poIntersection = std::unique_ptr<OGRGeometry>(
poGeom->Intersection(m_poClipGeom.get()));
if (!poIntersection)
continue;

const auto eFeatGeomType =
wkbFlatten(poIntersection->getGeometryType());
if (m_eFlattenSrcLayerGeomType != wkbUnknown &&
m_eFlattenSrcLayerGeomType != eFeatGeomType)
else if (OGR_GT_GetCollection(eFeatGeomType) ==
m_eFlattenSrcLayerGeomType)
{
// If the intersection is a collection of geometry and the
// layer geometry type is of non-collection type, create
// one feature per element of the collection.
if (!m_bSrcLayerGeomTypeIsCollection &&
OGR_GT_IsSubClassOf(eFeatGeomType, wkbGeometryCollection))
{
m_poSrcFeature = std::move(poFeature);
m_poCurGeomColl.reset(
poIntersection.release()->toGeometryCollection());
m_idxInCurGeomColl = 0;
return GetNextFeature();
}
else if (OGR_GT_GetCollection(eFeatGeomType) ==
m_eFlattenSrcLayerGeomType)
{
poIntersection.reset(OGRGeometryFactory::forceTo(
poIntersection.release(), m_eSrcLayerGeomType));
poFeature->SetGeometryDirectly(poIntersection.release());
return poFeature.release();
}
// else discard geometries of incompatible type with the
// layer geometry type
poIntersection.reset(OGRGeometryFactory::forceTo(
poIntersection.release(), m_eSrcLayerGeomType));
poSrcFeature->SetGeometryDirectly(poIntersection.release());
apoOutFeatures.push_back(std::move(poSrcFeature));
}
else
else if (m_eFlattenSrcLayerGeomType == wkbGeometryCollection)
{
poFeature->SetGeometryDirectly(poIntersection.release());
return poFeature.release();
auto poGeomColl = std::make_unique<OGRGeometryCollection>();
poGeomColl->addGeometry(std::move(poIntersection));
poSrcFeature->SetGeometryDirectly(poGeomColl.release());
apoOutFeatures.push_back(std::move(poSrcFeature));
}
// else discard geometries of incompatible type with the
// layer geometry type
}
else
{
poSrcFeature->SetGeometryDirectly(poIntersection.release());
apoOutFeatures.push_back(std::move(poSrcFeature));
}
return nullptr;
}

int TestCapability(const char *pszCap) override
{
if (EQUAL(pszCap, OLCStringsAsUTF8) ||
EQUAL(pszCap, OLCCurveGeometries) || EQUAL(pszCap, OLCZGeometries))
return m_poSrcLayer->TestCapability(pszCap);
return m_srcLayer.TestCapability(pszCap);
return false;
}

private:
OGRLayer *m_poSrcLayer = nullptr;
std::unique_ptr<OGRGeometry> m_poClipGeom{};
const OGRwkbGeometryType m_eSrcLayerGeomType;
const OGRwkbGeometryType m_eFlattenSrcLayerGeomType;
const bool m_bSrcLayerGeomTypeIsCollection;
std::unique_ptr<OGRFeature> m_poSrcFeature{};
std::unique_ptr<OGRGeometryCollection> m_poCurGeomColl{};
int m_idxInCurGeomColl = 0;

CPL_DISALLOW_COPY_ASSIGN(GDALVectorClipAlgorithmLayer)
};
Expand Down Expand Up @@ -428,8 +398,7 @@ bool GDALVectorClipAlgorithm::RunStep(GDALProgressFunc, void *)
return false;
}

auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>();
outDS->SetDescription(poSrcDS->GetDescription());
auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);

bool ret = true;
for (int i = 0; ret && i < nLayerCount; ++i)
Expand All @@ -448,8 +417,10 @@ bool GDALVectorClipAlgorithm::RunStep(GDALProgressFunc, void *)
}
if (ret)
{
outDS->AddLayer(std::make_unique<GDALVectorClipAlgorithmLayer>(
poSrcLayer, std::move(poClipGeomForLayer)));
outDS->AddLayer(
*poSrcLayer,
std::make_unique<GDALVectorClipAlgorithmLayer>(
*poSrcLayer, std::move(poClipGeomForLayer)));
}
}
}
Expand Down
171 changes: 171 additions & 0 deletions apps/gdalalg_vector_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,4 +516,175 @@ std::string GDALVectorPipelineAlgorithm::GetUsageForCLI(
return ret;
}

/************************************************************************/
/* GDALVectorPipelineOutputLayer */
/************************************************************************/

/************************************************************************/
/* GDALVectorPipelineOutputLayer() */
/************************************************************************/

GDALVectorPipelineOutputLayer::GDALVectorPipelineOutputLayer(OGRLayer &srcLayer)
: m_srcLayer(srcLayer)
{
}

/************************************************************************/
/* GDALVectorPipelineOutputLayer::ResetReading() */
/************************************************************************/

void GDALVectorPipelineOutputLayer::ResetReading()
{
m_srcLayer.ResetReading();
m_pendingFeatures.clear();
m_idxInPendingFeatures = 0;
}

/************************************************************************/
/* GDALVectorPipelineOutputLayer::GetNextRawFeature() */
/************************************************************************/

OGRFeature *GDALVectorPipelineOutputLayer::GetNextRawFeature()
{
if (m_idxInPendingFeatures < m_pendingFeatures.size())
{
OGRFeature *poFeature =
m_pendingFeatures[m_idxInPendingFeatures].release();
++m_idxInPendingFeatures;
return poFeature;
}
m_pendingFeatures.clear();
m_idxInPendingFeatures = 0;
while (true)
{
auto poSrcFeature =
std::unique_ptr<OGRFeature>(m_srcLayer.GetNextFeature());
if (!poSrcFeature)
return nullptr;
TranslateFeature(std::move(poSrcFeature), m_pendingFeatures);
if (!m_pendingFeatures.empty())
break;
}
OGRFeature *poFeature = m_pendingFeatures[0].release();
m_idxInPendingFeatures = 1;
return poFeature;
}

/************************************************************************/
/* GDALVectorPipelineOutputDataset */
/************************************************************************/

/************************************************************************/
/* GDALVectorPipelineOutputDataset() */
/************************************************************************/

GDALVectorPipelineOutputDataset::GDALVectorPipelineOutputDataset(
GDALDataset &srcDS)
: m_srcDS(srcDS)
{
SetDescription(m_srcDS.GetDescription());
}

/************************************************************************/
/* GDALVectorPipelineOutputDataset::AddLayer() */
/************************************************************************/

void GDALVectorPipelineOutputDataset::AddLayer(
OGRLayer &oSrcLayer,
std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer)
{
m_layersToDestroy.push_back(std::move(poNewLayer));
OGRLayerWithTranslateFeature *poNewLayerRaw =
m_layersToDestroy.back().get();
m_layers.push_back(poNewLayerRaw);
m_mapSrcLayerToNewLayer[&oSrcLayer] = poNewLayerRaw;
}

/************************************************************************/
/* GDALVectorPipelineOutputDataset::GetLayerCount() */
/************************************************************************/

int GDALVectorPipelineOutputDataset::GetLayerCount()
{
return static_cast<int>(m_layers.size());
}

/************************************************************************/
/* GDALVectorPipelineOutputDataset::GetLayer() */
/************************************************************************/

OGRLayer *GDALVectorPipelineOutputDataset::GetLayer(int idx)
{
return idx >= 0 && idx < GetLayerCount() ? m_layers[idx] : nullptr;
}

/************************************************************************/
/* GDALVectorPipelineOutputDataset::TestCapability() */
/************************************************************************/

int GDALVectorPipelineOutputDataset::TestCapability(const char *pszCap)
{
if (EQUAL(pszCap, ODsCRandomLayerRead))
{
return m_srcDS.TestCapability(pszCap);
}
return false;
}

/************************************************************************/
/* GDALVectorPipelineOutputDataset::ResetReading() */
/************************************************************************/

void GDALVectorPipelineOutputDataset::ResetReading()
{
m_srcDS.ResetReading();
m_pendingFeatures.clear();
m_idxInPendingFeatures = 0;
}

/************************************************************************/
/* GDALVectorPipelineOutputDataset::GetNextFeature() */
/************************************************************************/

OGRFeature *GDALVectorPipelineOutputDataset::GetNextFeature(
OGRLayer **ppoBelongingLayer, double *pdfProgressPct,
GDALProgressFunc pfnProgress, void *pProgressData)
{
if (m_idxInPendingFeatures < m_pendingFeatures.size())
{
OGRFeature *poFeature =
m_pendingFeatures[m_idxInPendingFeatures].release();
if (ppoBelongingLayer)
*ppoBelongingLayer = m_belongingLayer;
++m_idxInPendingFeatures;
return poFeature;
}

m_pendingFeatures.clear();
m_idxInPendingFeatures = 0;

while (true)
{
OGRLayer *poSrcBelongingLayer = nullptr;
auto poSrcFeature = std::unique_ptr<OGRFeature>(m_srcDS.GetNextFeature(
&poSrcBelongingLayer, pdfProgressPct, pfnProgress, pProgressData));
if (!poSrcFeature)
return nullptr;
auto iterToDstLayer = m_mapSrcLayerToNewLayer.find(poSrcBelongingLayer);
if (iterToDstLayer != m_mapSrcLayerToNewLayer.end())
{
m_belongingLayer = iterToDstLayer->second;
m_belongingLayer->TranslateFeature(std::move(poSrcFeature),
m_pendingFeatures);
if (!m_pendingFeatures.empty())
break;
}
}
OGRFeature *poFeature = m_pendingFeatures[0].release();
if (ppoBelongingLayer)
*ppoBelongingLayer = m_belongingLayer;
m_idxInPendingFeatures = 1;
return poFeature;
}

//! @endcond
Loading

0 comments on commit 6291ae5

Please sign in to comment.