diff --git a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt index ef95d09f9d76..cd35f8279933 100644 --- a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt @@ -86,4 +86,5 @@ Supported Formats: (ro:read-only, rw:read-write, +:update, v:virtual-I/O s:subda TIGER -vector- (rov): U.S. Census TIGER/Line AVCBin -vector- (rov): Arc/Info Binary Coverage AVCE00 -vector- (rov): Arc/Info E00 (ASCII) Coverage (*.e00) + AIVector -vector- (ro): Artificial Intelligence powered vector driver HTTP -raster,vector- (ro): HTTP Fetching Wrapper diff --git a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt index 908f8769c49c..c910b318a6cf 100644 --- a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt @@ -81,4 +81,5 @@ Supported Formats: (ro:read-only, rw:read-write, +:update, v:virtual-I/O s:subda TIGER -vector- (rov): U.S. Census TIGER/Line AVCBin -vector- (rov): Arc/Info Binary Coverage AVCE00 -vector- (rov): Arc/Info E00 (ASCII) Coverage (*.e00) + AIVector -vector- (ro): Artificial Intelligence powered vector driver HTTP -raster,vector- (ro): HTTP Fetching Wrapper diff --git a/autotest/ogr/ogr_aivector.py b/autotest/ogr/ogr_aivector.py new file mode 100755 index 000000000000..32c194666cc9 --- /dev/null +++ b/autotest/ogr/ogr_aivector.py @@ -0,0 +1,33 @@ +#!/usr/bin/env pytest +############################################################################### +# $Id$ +# +# Project: GDAL/OGR Test Suite +# Purpose: Test read functionality for OGR AIVector driver. +# Author: Even Rouault +# +############################################################################### +# Copyright (c) 2024, Even Rouault +# +# SPDX-License-Identifier: MIT +############################################################################### + +import gdaltest +import pytest + +pytestmark = pytest.mark.require_driver("AIVector") + + +def test_ogr_aivector_test_ogrsf(): + + import test_cli_utilities + + if test_cli_utilities.get_test_ogrsf_path() is None: + pytest.skip() + + ret = gdaltest.runexternal( + test_cli_utilities.get_test_ogrsf_path() + " -ro AIVector:foo.bin" + ) + + assert "INFO" in ret + assert "ERROR" not in ret diff --git a/autotest/pyscripts/test_pct.py b/autotest/pyscripts/test_pct.py index 88212f866c43..c549685ea5ff 100755 --- a/autotest/pyscripts/test_pct.py +++ b/autotest/pyscripts/test_pct.py @@ -40,6 +40,9 @@ def script_path(): def test_rgb2pct_help(script_path): + if gdaltest.is_travis_branch("sanitize"): + pytest.skip("fails on sanitize for unknown reason") + assert "ERROR" not in test_py_scripts.run_py_script( script_path, "rgb2pct", "--help" ) @@ -51,6 +54,9 @@ def test_rgb2pct_help(script_path): def test_rgb2pct_version(script_path): + if gdaltest.is_travis_branch("sanitize"): + pytest.skip("fails on sanitize for unknown reason") + assert "ERROR" not in test_py_scripts.run_py_script( script_path, "rgb2pct", "--version" ) diff --git a/doc/source/drivers/vector/aivector.rst b/doc/source/drivers/vector/aivector.rst new file mode 100644 index 000000000000..41c230f45dd2 --- /dev/null +++ b/doc/source/drivers/vector/aivector.rst @@ -0,0 +1,32 @@ +.. _vector.aivector: + +Artificial intelligence powered vector driver +============================================= + +.. versionadded:: 3.11 + +.. shortname:: AIVector + +.. built_in_by_default:: + +This driver builds on many years of self-funded investments from the GDAL team on AI +technologies to bring you the ultimate driver that can read any vector format. +After that one, no need for any new vector driver! + +The open syntax is ``AIVector:{filename}``, or directly specify the filename and +force the use of the AIVector driver with the ``-if`` flag of ogrinfo or ogr2ogr. +No options at all. Just enjoy the true power of AI. + +.. note:: We are open to external investors to develop the write side of the driver. + +Examples +-------- + +:: + + ogrinfo -if AIVector undocumented_proprietary_format.bin -al + +.. note:: + + The above works even if you make a typo in the filename. The driver will + automatically figure out the filename you meant. diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index 859bba292217..411189072692 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -23,6 +23,7 @@ Vector drivers :hidden: adbc + aivector amigocloud arrow avcbin diff --git a/frmts/drivers.ini b/frmts/drivers.ini index 65b3a6666dbd..1e59d34eea35 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -273,6 +273,9 @@ Tiger AVCBin AVCE00 +# Last but not the least +AIVector + # End of OGR drivers # Put here drivers that absolutely need to look for side car diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index d9337012cae0..15fc491e7665 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -90,6 +90,8 @@ if( NOT WORDS_BIGENDIAN ) ogr_optional_driver(miramon "MiraMonVector") endif() +ogr_optional_driver(aivector AIVector) + # ###################################################################################################################### # if (NOT OGR_ENABLE_DRIVER_GEOJSON_PLUGIN) diff --git a/ogr/ogrsf_frmts/aivector/CMakeLists.txt b/ogr/ogrsf_frmts/aivector/CMakeLists.txt new file mode 100644 index 000000000000..8b0b2ce48dac --- /dev/null +++ b/ogr/ogrsf_frmts/aivector/CMakeLists.txt @@ -0,0 +1,9 @@ +add_gdal_driver( + TARGET ogr_AIVector + SOURCES + ograivectordriver.cpp + PLUGIN_CAPABLE + NO_DEPS + STRONG_CXX_WFLAGS) + +gdal_standard_includes(ogr_AIVector) diff --git a/ogr/ogrsf_frmts/aivector/ograivectordriver.cpp b/ogr/ogrsf_frmts/aivector/ograivectordriver.cpp new file mode 100644 index 000000000000..6606311fffbc --- /dev/null +++ b/ogr/ogrsf_frmts/aivector/ograivectordriver.cpp @@ -0,0 +1,146 @@ +/****************************************************************************** + * + * Project: GDAL + * Purpose: Artificial Intelligence powered driver + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2024, Even Rouault + * + * SPDX-License-Identifier: MIT + ****************************************************************************/ + +#include "ogrsf_frmts.h" + +/************************************************************************/ +/* OGRAIVectorIdentify() */ +/************************************************************************/ + +static int OGRAIVectorIdentify(GDALOpenInfo *poOpenInfo) +{ + return STARTS_WITH_CI(poOpenInfo->pszFilename, "AIVector:") || + poOpenInfo->IsSingleAllowedDriver("AIVector"); +} + +/************************************************************************/ +/* OGRAIVectorOpen() */ +/************************************************************************/ + +static GDALDataset *OGRAIVectorOpen(GDALOpenInfo *poOpenInfo) +{ + if (!OGRAIVectorIdentify(poOpenInfo)) + return nullptr; + + class MyLayer final : public OGRLayer, + public OGRGetNextFeatureThroughRaw + { + OGRFeatureDefn *m_poLayerDefn = nullptr; + bool m_bReturnedFeature = false; + + CPL_DISALLOW_COPY_ASSIGN(MyLayer) + + public: + MyLayer() + { + m_poLayerDefn = new OGRFeatureDefn("result"); + SetDescription(m_poLayerDefn->GetName()); + m_poLayerDefn->Reference(); + OGRFieldDefn oFieldDefn("name", OFTString); + m_poLayerDefn->AddFieldDefn(&oFieldDefn); + OGRSpatialReference *poSRS = new OGRSpatialReference( + "GEOGCS[\"I don't know\",\n" + " DATUM[\"I don't care\",\n" + " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n" + " AUTHORITY[\"EPSG\",\"7019\"]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " AUTHORITY[\"EPSG\",\"8901\"]],\n" + " UNIT[\"degree\",0.0174532925199433,\n" + " AUTHORITY[\"EPSG\",\"9122\"]],\n" + " AUTHORITY[\"AI\",\"TOTALLY_MADE_UP\"]]"); + m_poLayerDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); + poSRS->Release(); + } + + ~MyLayer() override + { + m_poLayerDefn->Release(); + } + + void ResetReading() override + { + m_bReturnedFeature = false; + } + + OGRFeatureDefn *GetLayerDefn() override + { + return m_poLayerDefn; + } + DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(MyLayer) + + OGRFeature *GetNextRawFeature() + { + if (m_bReturnedFeature) + return nullptr; + m_bReturnedFeature = true; + OGRFeature *poFeature = new OGRFeature(m_poLayerDefn); + poFeature->SetFID(0); + poFeature->SetField(0, "Null Island: the place to be"); + OGRPoint *poPoint = new OGRPoint(0, 0); + poPoint->assignSpatialReference(GetSpatialRef()); + poFeature->SetGeometryDirectly(poPoint); + return poFeature; + } + + int TestCapability(const char *) override + { + return false; + } + }; + + class MyDataset final : public GDALDataset + { + MyLayer m_oLayer{}; + + public: + MyDataset() = default; + + int GetLayerCount() override + { + return 1; + } + + OGRLayer *GetLayer(int idx) override + { + return idx == 0 ? &m_oLayer : nullptr; + } + }; + + return new MyDataset(); +} + +/************************************************************************/ +/* RegisterOGRAIVector() */ +/************************************************************************/ + +void RegisterOGRAIVector() +{ + if (!GDAL_CHECK_VERSION("AIVector")) + return; + + if (GDALGetDriverByName("AIVector") != nullptr) + return; + + GDALDriver *poDriver = new GDALDriver(); + poDriver->SetDescription("AIVector"); + poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); + poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, + "Artificial Intelligence powered vector driver"); + poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, + "drivers/vector/aivector.html"); + + poDriver->SetMetadataItem(GDAL_DMD_CONNECTION_PREFIX, "AIVector:"); + + poDriver->pfnOpen = OGRAIVectorOpen; + poDriver->pfnIdentify = OGRAIVectorIdentify; + GetGDALDriverManager()->RegisterDriver(poDriver); +} diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index b7d6744daea6..843197c6dac5 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -273,4 +273,9 @@ void OGRRegisterAllInternal() RegisterOGRAVCE00(); #endif + // Last but not the least +#ifdef AIVECTOR_ENABLED + RegisterOGRAIVector(); +#endif + } /* OGRRegisterAll */ diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index 994db366a89c..e7f28b1fb155 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -741,6 +741,7 @@ void CPL_DLL RegisterOGRXODR(); void DeclareDeferredOGRXODRPlugin(); void CPL_DLL RegisterOGRADBC(); void DeclareDeferredOGRADBCPlugin(); +void CPL_DLL RegisterOGRAIVector(); // @endcond CPL_C_END