Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gdal vector: make 'read', 'clip' and 'reproject' compatible of OSM-type of datasources that require ODsCRandomLayerRead #11841

Merged
merged 1 commit into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading