This is an automated email from the ASF dual-hosted git repository. jsorel pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push: new 7bdaab6a29 Decode OGR vector layers, rebuild FeatureTypes 7bdaab6a29 is described below commit 7bdaab6a292822f9c7700c4cfc99f26fa8b1e0c3 Author: jsorel <johann.so...@geomatys.com> AuthorDate: Wed Oct 9 10:55:36 2024 +0200 Decode OGR vector layers, rebuild FeatureTypes --- .../org.apache.sis.feature/main/module-info.java | 1 + optional/build.gradle.kts | 2 + .../org.apache.sis.storage.DataStoreProvider | 2 +- .../main/module-info.java | 4 + .../main/org/apache/sis/storage/gdal/GDAL.java | 269 +++++++++++++++++++++ .../org/apache/sis/storage/gdal/GDALStore.java | 5 +- .../org/apache/sis/storage/gdal/OGRFeatureSet.java | 184 ++++++++++++++ .../org/apache/sis/storage/gdal/OGRFieldType.java | 84 +++++++ .../apache/sis/storage/gdal/OGRwkbByteOrder.java | 36 +++ .../sis/storage/gdal/OGRwkbGeometryType.java | 185 ++++++++++++++ .../apache/sis/storage/gdal/OgrGeometryReader.java | 206 ++++++++++++++++ .../apache/sis/storage/gdal/OgrSpliterator.java | 133 ++++++++++ .../main/org/apache/sis/storage/gdal/Opener.java | 2 +- .../org/apache/sis/storage/gdal/SpatialRef.java | 13 + 14 files changed, 1123 insertions(+), 3 deletions(-) diff --git a/endorsed/src/org.apache.sis.feature/main/module-info.java b/endorsed/src/org.apache.sis.feature/main/module-info.java index a99f398169..0fa39a382d 100644 --- a/endorsed/src/org.apache.sis.feature/main/module-info.java +++ b/endorsed/src/org.apache.sis.feature/main/module-info.java @@ -55,6 +55,7 @@ module org.apache.sis.feature { org.apache.sis.storage.shapefile, // In the "incubator" sub-project. org.apache.sis.portrayal, org.apache.sis.portrayal.map, // In the "incubator" sub-project. + org.apache.sis.storage.gdal, // In the "optional" sub-project. org.apache.sis.gui; // In the "optional" sub-project. exports org.apache.sis.geometry.wrapper to diff --git a/optional/build.gradle.kts b/optional/build.gradle.kts index dbcd427a82..79fd1f326b 100644 --- a/optional/build.gradle.kts +++ b/optional/build.gradle.kts @@ -50,6 +50,8 @@ dependencies { // Mandatory dependencies api (libs.units) api (libs.geoapi) + api (libs.jts.core) // Should be an optional dependency. + api (libs.esri.geometry) // Idem. implementation(libs.jaxb.api) // Transitive dependency. runtimeOnly (libs.jaxb.impl) api (files(File(pathToFX, "javafx.base.jar"))) diff --git a/optional/src/org.apache.sis.storage.gdal/main/META-INF.services/org.apache.sis.storage.DataStoreProvider b/optional/src/org.apache.sis.storage.gdal/main/META-INF.services/org.apache.sis.storage.DataStoreProvider index 25f274232b..fe0f6d43f6 100644 --- a/optional/src/org.apache.sis.storage.gdal/main/META-INF.services/org.apache.sis.storage.DataStoreProvider +++ b/optional/src/org.apache.sis.storage.gdal/main/META-INF.services/org.apache.sis.storage.DataStoreProvider @@ -1,4 +1,4 @@ # Workaround for Maven bug https://issues.apache.org/jira/browse/MNG-7855 # The content of this file is automatically derived from module-info.class file. # Should be used only if the JAR file was on class-path rather than module-path. -org.apache.sis.storage.gdal.GdalStoreProvider +org.apache.sis.storage.gdal.GDALStoreProvider diff --git a/optional/src/org.apache.sis.storage.gdal/main/module-info.java b/optional/src/org.apache.sis.storage.gdal/main/module-info.java index e4d87b9584..c7c98de106 100644 --- a/optional/src/org.apache.sis.storage.gdal/main/module-info.java +++ b/optional/src/org.apache.sis.storage.gdal/main/module-info.java @@ -52,6 +52,10 @@ module org.apache.sis.storage.gdal { requires transitive org.apache.sis.referencing; requires transitive org.apache.sis.storage; + // Optional dependencies to be provided by user. + requires static esri.geometry.api; + requires static org.locationtech.jts; + exports org.apache.sis.storage.gdal; provides org.apache.sis.storage.DataStoreProvider diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDAL.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDAL.java index c70763fc39..cf6d50abd9 100644 --- a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDAL.java +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDAL.java @@ -274,6 +274,183 @@ final class GDAL extends NativeFunctions { */ final MethodHandle adviseRead; + /** + * <abbr>GDAL</abbr> {@code CPLErr GDALDatasetGetLayerCount(Pointer hDS)}. + * Get the number of layers in this dataset. + */ + final MethodHandle datasetGetLayerCount; + + /** + * <abbr>GDAL</abbr> {@code CPLErr GDALDatasetGetLayer(Pointer hDS, int index)}. + * Fetch a layer by index. + */ + final MethodHandle datasetGetLayer; + + /** + * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_L_GetLayerDefn(Pointer hDS)}. + * Fetch the schema information for this layer. + */ + final MethodHandle ogrLayerGetLayerDefn; + + /** + * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_L_GetName(Pointer hDS)}. + * Return the layer name. + */ + final MethodHandle ogrLayerGetName; + + /** + * <abbr>OGR</abbr> {@code GIntBig CPL_DLL OGR_L_GetFeatureCount(OGRLayerH, int)}. + * Fetch the feature count in this layer. + */ + final MethodHandle ogrLayerGetFeatureCount; + + /** + * <abbr>OGR</abbr> {@code OGRErr CPL_DLL OGR_L_GetExtent(OGRLayerH, OGREnvelope *, int)}. + * Fetch spatial extent. + */ + final MethodHandle ogrLayerGetExtent; + + /** + * <abbr>OGR</abbr> {@code OGRFeatureH CPL_DLL OGR_L_GetNextFeature(OGRLayerH) CPL_WARN_UNUSED_RESULT}. + * Fetch the next available feature from this layer. + */ + final MethodHandle ogrLayerGetNextFeature; + + /** + * <abbr>OGR</abbr> {@code GIntBig CPL_DLL OGR_F_GetFID(OGRFeatureH)}. + * Get feature identifier. + */ + final MethodHandle ogrFeatureGetFid; + + /** + * <abbr>OGR</abbr> {@code int CPL_DLL OGR_F_GetFieldAsInteger(OGRFeatureH, int)}. + * Fetch field value as integer. + */ + final MethodHandle ogrFeatureGetFieldAsInteger; + + /** + * <abbr>OGR</abbr> {@code GIntBig CPL_DLL OGR_F_GetFieldAsInteger64(OGRFeatureH, int)}. + * Fetch field value as integer 64 bit. + */ + final MethodHandle ogrFeatureGetFieldAsInteger64; + + /** + * <abbr>OGR</abbr> {@code double CPL_DLL OGR_F_GetFieldAsDouble(OGRFeatureH, int)}. + * Fetch field value as a double. + */ + final MethodHandle ogrFeatureGetFieldAsDouble; + + /** + * <abbr>OGR</abbr> {@code const char CPL_DLL *OGR_F_GetFieldAsString(OGRFeatureH, int)}. + * Fetch field value as a string. + */ + final MethodHandle ogrFeatureGetFieldAsString; + + /** + * <abbr>OGR</abbr> {@code OGRGeometryH OGR_F_GetGeometryRef(OGRFeatureH hFeat)}. + * Fetch a handle to feature geometry. + */ + final MethodHandle ogrFeatureGetGeometryRef; + + /** + * <abbr>OGR</abbr> {@code void OGR_F_Destroy(OGRFeatureH hFeat)}. + * Destroy feature. + */ + final MethodHandle ogrFeatureDestroy; + + /** + * <abbr>OGR</abbr> {@code void OGR_DS_Destroy(OGRDataSourceH hDS)}. + * Closes opened datasource and releases allocated resources. + */ + final MethodHandle ogrDataSourceDestroy; + + /** + * <abbr>OGR</abbr> {@code const char * OGR_G_GetGeometryName(OGRGeometryH hGeom)}. + * Fetch WKT name for geometry type. + */ + final MethodHandle ogrGeometryGetGeometryName; + + /** + * <abbr>OGR</abbr> {@code int CPL_DLL OGR_G_GetPoints(OGRGeometryH hGeom, void *pabyX, int nXStride, + * void *pabyY, int nYStride, void *pabyZ, int nZStride);}. + * Returns all points of line string. + */ + final MethodHandle ogrGeometryGetPoints; + + /** + * <abbr>OGR</abbr> {@code int OGR_G_GetPointCount(OGRGeometryH hGeom)}. + * Fetch number of points from a Point or a LineString/LinearRing geometry. + */ + final MethodHandle ogrGeometryGetPointCount; + + /** + * <abbr>OGR</abbr> {@code int OGR_G_GetGeometryCount(OGRGeometryH hGeom)}. + * Fetch the number of elements in a geometry or number of geometries in container. + */ + final MethodHandle ogrGeometryGetGeometryCount; + + /** + * <abbr>OGR</abbr> {@code OGRGeometryH OGR_G_GetGeometryRef(OGRGeometryH hGeom, int iSubGeom)}. + * Fetch geometry from a geometry container. + */ + final MethodHandle ogrGeometryGetGeometryRef; + + /** + * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_FD_GetFieldCount(Pointer hDS)}. + * Fetch number of fields on the passed feature definition. + */ + final MethodHandle ogrFeatureDefinitionGetFieldCount; + + /** + * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_FD_GetFieldDefn(Pointer hDS)}. + * Fetch field definition of the passed feature definition. + */ + final MethodHandle ogrFeatureDefinitionGetFieldDefinition; + + /** + * <abbr>OGR</abbr> {@code int CPLErr OGR_Fld_GetType(Pointer hDS, int index)}. + * Fetch type of this field. + */ + final MethodHandle ogrFeatureDefinitionGetFieldType; + + /** + * <abbr>OGR</abbr> {@code Pointer CPLErr OGR_Fld_GetNameRef(Pointer hDS)}. + * Fetch name of this field. + */ + final MethodHandle ogrFeatureDefinitionGetFieldName; + + /** + * <abbr>OGR</abbr> {@code int CPLErr OGR_FD_GetGeomFieldCount(Pointer hDS)}. + * Fetch number of geometry fields on this feature. + */ + final MethodHandle ogrFeatureDefinitionGetGeomFieldCount; + + /** + * <abbr>OGR</abbr> {@code OGRGeomFieldDefnH OGR_FD_GetGeomFieldDefn(OGRFeatureDefnH hDefn, int iGeomField)}. + * Fetch geometry field definition of the passed feature definition. + */ + final MethodHandle ogrFeatureDefinitionGetGeomFieldDefinition; + + /** + * <abbr>OGR</abbr> {@code int CPLErr OGR_Fld_GetType(Pointer hDS, int index)}. + * Fetch geometry type of this field. + */ + final MethodHandle ogrFeatureDefinitionGetGeomFieldType; + + /** + * <abbr>OGR</abbr> {@code OGRwkbGeometryType CPL_DLL OGR_GFld_GetType( OGRGeomFieldDefnH )}. + * Fetch name of this field. + */ + final MethodHandle ogrFeatureDefinitionGetGeomFieldName; + + /** + * <abbr>OGR</abbr> {@code OGRSpatialReferenceH CPL_DLL OGR_GFld_GetSpatialRef(OGRGeomFieldDefnH)}. + * Fetch spatial reference system of this field. + */ + final MethodHandle ogrFeatureDefinitionGetGeomFieldSpatialRef; + + + /** * Creates the handles for all <abbr>GDAL</abbr> functions which will be needed. * @@ -288,6 +465,7 @@ final class GDAL extends NativeFunctions { final var acceptPointerReturnInt = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS); final var acceptTwoPtrsReturnDouble = FunctionDescriptor.of(ValueLayout.JAVA_DOUBLE, ValueLayout.ADDRESS, ValueLayout.ADDRESS); final var acceptTwoPtrsReturnPointer = FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS); + final var acceptPointerAndIntReturnPointer = FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT); // Memory management free = lookup("VSIFree", FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)); @@ -394,6 +572,97 @@ final class GDAL extends NativeFunctions { ValueLayout.JAVA_INT, // GDALDataType eBDataType ValueLayout.ADDRESS)); // CSLConstList papszOptions + // Dataset layer API + datasetGetLayerCount = lookup("GDALDatasetGetLayerCount", acceptPointerReturnInt); + + datasetGetLayer = lookup("GDALDatasetGetLayer", acceptPointerAndIntReturnPointer); + + // OGR API + ogrLayerGetLayerDefn = lookup("OGR_L_GetLayerDefn", acceptPointerReturnPointer); + + ogrLayerGetName = lookup("OGR_L_GetName", acceptPointerReturnPointer); + + ogrLayerGetFeatureCount = lookup("OGR_L_GetFeatureCount", FunctionDescriptor.of( + ValueLayout.JAVA_LONG, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT)); //flag to force computtion + + ogrLayerGetExtent = lookup("OGR_L_GetExtent", FunctionDescriptor.of( + ValueLayout.JAVA_INT, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT)); + + ogrLayerGetNextFeature = lookup("OGR_L_GetNextFeature", acceptPointerReturnPointer); + + ogrFeatureGetFid = lookup("OGR_F_GetFID", FunctionDescriptor.of( + ValueLayout.JAVA_LONG, + ValueLayout.ADDRESS)); + + ogrFeatureDefinitionGetFieldCount = lookup("OGR_FD_GetFieldCount", acceptPointerReturnInt); + + ogrFeatureDefinitionGetFieldDefinition = lookup("OGR_FD_GetFieldDefn", acceptPointerAndIntReturnPointer); + + ogrFeatureDefinitionGetFieldType = lookup("OGR_Fld_GetType", acceptPointerReturnInt); + + ogrFeatureDefinitionGetFieldName = lookup("OGR_Fld_GetNameRef", acceptPointerReturnPointer); + + ogrFeatureDefinitionGetGeomFieldCount = lookup("OGR_FD_GetGeomFieldCount", acceptPointerReturnInt); + + ogrFeatureDefinitionGetGeomFieldDefinition = lookup("OGR_FD_GetGeomFieldDefn", acceptPointerAndIntReturnPointer); + + ogrFeatureDefinitionGetGeomFieldType = lookup("OGR_GFld_GetType", acceptPointerReturnInt); + + ogrFeatureDefinitionGetGeomFieldName = lookup("OGR_GFld_GetNameRef", acceptPointerReturnPointer); + + ogrFeatureDefinitionGetGeomFieldSpatialRef = lookup("OGR_GFld_GetSpatialRef", acceptPointerReturnPointer); + + ogrFeatureGetFieldAsInteger = lookup("OGR_F_GetFieldAsInteger", FunctionDescriptor.of( + ValueLayout.JAVA_INT, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT)); + + ogrFeatureGetFieldAsInteger64 = lookup("OGR_F_GetFieldAsInteger64", FunctionDescriptor.of( + ValueLayout.JAVA_LONG, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT)); + + ogrFeatureGetFieldAsDouble = lookup("OGR_F_GetFieldAsDouble", FunctionDescriptor.of( + ValueLayout.JAVA_DOUBLE, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT)); + + ogrFeatureGetFieldAsString = lookup("OGR_F_GetFieldAsString", FunctionDescriptor.of( + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT)); + + ogrFeatureGetGeometryRef = lookup("OGR_F_GetGeometryRef", acceptPointerReturnPointer); + + ogrFeatureDestroy = lookup("OGR_F_Destroy", FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)); + + ogrDataSourceDestroy = lookup("OGR_DS_Destroy", FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)); + + ogrGeometryGetGeometryName = lookup("OGR_G_GetGeometryName", acceptPointerReturnPointer); + + ogrGeometryGetPoints = lookup("OGR_G_GetPoints", FunctionDescriptor.of( + ValueLayout.JAVA_INT, + ValueLayout.ADDRESS, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT, + ValueLayout.ADDRESS, + ValueLayout.JAVA_INT)); + + ogrGeometryGetPointCount = lookup("OGR_G_GetPointCount", acceptPointerReturnInt); + + ogrGeometryGetGeometryCount = lookup("OGR_G_GetGeometryCount", acceptPointerReturnInt); + + ogrGeometryGetGeometryRef = lookup("OGR_G_GetGeometryRef", acceptPointerAndIntReturnPointer); + + + // Set error handling first in order to redirect initialization warnings. setErrorHandler(null); diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java index 748dc7d15c..2aa49d6ccb 100644 --- a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java @@ -50,6 +50,7 @@ import org.apache.sis.util.privy.Constants; import org.apache.sis.util.privy.UnmodifiableArrayList; import org.apache.sis.util.iso.DefaultNameFactory; import org.apache.sis.system.Cleaners; +import org.apache.sis.util.ArraysExt; /** @@ -373,7 +374,9 @@ public class GDALStore extends DataStore implements Aggregate { if (subdatasets != null && !subdatasets.isEmpty()) { components = subdatasets; } else { - components = UnmodifiableArrayList.wrap(TiledResource.groupBySizeAndType(this, gdal, handle())); + final TiledResource[] rasters = TiledResource.groupBySizeAndType(this, gdal, handle()); + final OGRFeatureSet[] vectors = OGRFeatureSet.listVectors(this, gdal, handle()); + components = UnmodifiableArrayList.wrap(ArraysExt.concatenate(new Resource[0], rasters, vectors)); } } finally { ErrorHandler.throwOnFailure(this, "components"); diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFeatureSet.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFeatureSet.java new file mode 100644 index 0000000000..639f108e2f --- /dev/null +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFeatureSet.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.storage.gdal; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.DoubleBuffer; +import java.util.Optional; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import org.apache.sis.feature.builder.AttributeRole; +import org.apache.sis.feature.builder.AttributeTypeBuilder; +import org.apache.sis.feature.builder.FeatureTypeBuilder; +import org.apache.sis.feature.privy.AttributeConvention; +import org.apache.sis.geometry.GeneralEnvelope; +import org.apache.sis.referencing.crs.AbstractCRS; +import org.apache.sis.referencing.cs.AxesConvention; +import org.apache.sis.storage.AbstractFeatureSet; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.panama.NativeFunctions; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.MultiLineString; +import org.locationtech.jts.geom.MultiPolygon; +import org.locationtech.jts.geom.Polygon; +import org.opengis.feature.Feature; +import org.opengis.feature.FeatureType; +import org.opengis.geometry.Envelope; +import org.opengis.referencing.crs.CoordinateReferenceSystem; + +/** + * + * @author Johann Sorel (Geomatys) + */ +final class OGRFeatureSet extends AbstractFeatureSet { + + final GDALStore store; + final GDAL gdal; + final MemorySegment dataset; + final MemorySegment layer; + + //computed after a getType() call + FeatureType type; + CoordinateReferenceSystem crs; + String[] fields; + String[] geomFields; + OGRFieldType[] fieldEncs; + + OGRFeatureSet(final GDALStore store, final GDAL gdal, final MemorySegment dataset, MemorySegment layer) { + super(store); + this.store = store; + this.gdal = gdal; + this.dataset = dataset; + this.layer = layer; + } + + @Override + public synchronized FeatureType getType() throws DataStoreException { + if (type != null) return type; + + try { + final MemorySegment driver = (MemorySegment) gdal.getDatasetDriver.invokeExact(dataset); + final String driverName = NativeFunctions.toString((MemorySegment) gdal.getName.invokeExact(driver)); + + final MemorySegment layerDef = (MemorySegment) gdal.ogrLayerGetLayerDefn.invokeExact(layer); + final String name = NativeFunctions.toString( ((MemorySegment) gdal.ogrLayerGetName.invokeExact(layer))); + + final FeatureTypeBuilder ftb = new FeatureTypeBuilder(); + ftb.addAttribute(Long.class).setName(AttributeConvention.IDENTIFIER_PROPERTY); + ftb.setName(name); + + // List feature type fields + fields = new String[(int)gdal.ogrFeatureDefinitionGetFieldCount.invokeExact(layerDef)]; + fieldEncs = new OGRFieldType[fields.length]; + for (int i = 0 ; i<fields.length; i++) { + final MemorySegment fieldDef = (MemorySegment) gdal.ogrFeatureDefinitionGetFieldDefinition.invokeExact(layerDef,i); + final OGRFieldType type = OGRFieldType.valueOf((int) gdal.ogrFeatureDefinitionGetFieldType.invokeExact(fieldDef)); + final String fieldName = NativeFunctions.toString( (MemorySegment)gdal.ogrFeatureDefinitionGetFieldName.invokeExact(fieldDef)); + final Class<?> valueClass = type.getJavaClass(); + ftb.addAttribute(valueClass).setName(fieldName); + fields[i] = fieldName; + fieldEncs[i] = type; + } + + // List geometric feature type fields + geomFields = new String[(int) gdal.ogrFeatureDefinitionGetGeomFieldCount.invokeExact(layerDef)]; + for(int i=0; i<geomFields.length; i++) { + final MemorySegment ogrGeomFieldDefnH = (MemorySegment) gdal.ogrFeatureDefinitionGetGeomFieldDefinition.invokeExact(layerDef,i); + final OGRwkbGeometryType typrgeom = OGRwkbGeometryType.valueOf( (int) gdal.ogrFeatureDefinitionGetGeomFieldType.invokeExact(ogrGeomFieldDefnH)); + geomFields[i] = NativeFunctions.toString((MemorySegment)gdal.ogrFeatureDefinitionGetGeomFieldName.invokeExact(ogrGeomFieldDefnH)); + if(geomFields[i].isEmpty()) geomFields[i] = "geometry"+i; + + //read CRS + final MemorySegment crsRef = (MemorySegment) gdal.ogrFeatureDefinitionGetGeomFieldSpatialRef.invokeExact(ogrGeomFieldDefnH); + final SpatialRef spatialRef = SpatialRef.createWithHandle(store, gdal, crsRef); + crs = spatialRef.parseCRS("listVectors"); + //force longitude first + crs = ((AbstractCRS)crs).forConvention(AxesConvention.RIGHT_HANDED); + + Class<?> geomClass = typrgeom.getJavaClass(); + if (driverName.toLowerCase().contains("shapefile")) { + //OGR Hack : shapefile geometry type is not correctly detected + //this seems to be because ogr shp driver do not make a difference betwen geom types + //https://code.djangoproject.com/ticket/7218 + if (Polygon.class.equals(geomClass)) geomClass = MultiPolygon.class; + if (LineString.class.equals(geomClass)) geomClass = MultiLineString.class; + } + + final AttributeTypeBuilder<?> attBuilder = ftb.addAttribute(geomClass).setName(geomFields[i]).setCRS(crs); + if (i == 0) attBuilder.addRole(AttributeRole.DEFAULT_GEOMETRY); // first geometry as default + } + type = ftb.build(); + } catch (Throwable e) { + throw GDAL.propagate(e); + } + return type; + } + + @Override + public Optional<Envelope> getEnvelope() throws DataStoreException { + // use ogr provided envelope + try (Arena arena = Arena.ofConfined()) { + final MemorySegment extent = arena.allocate(8*4); + int error = (int) gdal.ogrLayerGetExtent.invokeExact(layer, extent, 1); + if (error != 0) { + throw new DataStoreException("Failed to calculate envelope for type "+ getIdentifier().get()); + } + final DoubleBuffer db = extent.asByteBuffer().asDoubleBuffer(); + final GeneralEnvelope env = new GeneralEnvelope(crs); + env.setRange(0, db.get(0), db.get(1)); + env.setRange(1, db.get(2), db.get(3)); + return Optional.of(env); + } catch (Throwable e) { + throw GDAL.propagate(e); + } + } + + public long getCount() throws DataStoreException { + try { + final Long nb = (Long) gdal.ogrLayerGetFeatureCount.invokeExact(layer, 1); + return nb != null ? nb : -1; + } catch (Throwable e) { + throw GDAL.propagate(e); + } + } + + @Override + public Stream<Feature> features(boolean parallel) throws DataStoreException { + final OgrSpliterator ite = new OgrSpliterator(this, getType()); + return StreamSupport.stream(ite, parallel); + } + + /** + * Returns featuresets found. + * + * @throws DataStoreException if an error occurred. + */ + static OGRFeatureSet[] listVectors(final GDALStore parent, final GDAL gdal, final MemorySegment dataset) + throws DataStoreException { + try { + final OGRFeatureSet[] array = new OGRFeatureSet[(int) gdal.datasetGetLayerCount.invokeExact(dataset)]; + for (int iLayer = 0; iLayer < array.length ; iLayer++) { + final MemorySegment layer = (MemorySegment) gdal.datasetGetLayer.invokeExact(dataset, iLayer); + array[iLayer] = new OGRFeatureSet(parent, gdal, dataset, layer); + } + return array; + } catch (Throwable e) { + throw GDAL.propagate(e); + } + } +} diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFieldType.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFieldType.java new file mode 100644 index 0000000000..9559127e58 --- /dev/null +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRFieldType.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.storage.gdal; + +/** + * + * @author Hilmi Bouallegue (Geomatys) + */ +enum OGRFieldType { + /** Simple 32bit integer */ + OFTInteger(Integer.class), + /** List of 32bit integers */ + OFTIntegerList(Object.class), + /** Double Precision floating point */ + OFTReal(Double.class), + /** List of doubles */ + OFTRealList(Object.class), + /** String of ASCII chars */ + OFTString(String.class), + /** Array of strings */ + OFTStringList(Object.class), + /** deprecated */ + OFTWideString(String.class), + /** deprecated */ + OFTWideStringList(Object.class), + /** Raw Binary data */ + OFTBinary(Object.class), + /** Date */ + OFTDate(Object.class), + /** Time */ + OFTTime(Object.class), + /** Date and Time */ + OFTDateTime(Object.class), + /** Single 64bit integer */ + OFTInteger64(Long.class), + /** List of 64bit integers */ + OFTInteger64List(Object.class), + OFTMaxType(Object.class); + + private final Class javaClass; + + OGRFieldType(Class javaClass){ + this.javaClass =javaClass; + } + + public Class getJavaClass(){ + return javaClass; + } + + public static OGRFieldType valueOf(int value) { + switch (value) { + case 0 : return OFTInteger; + case 1 : return OFTIntegerList; + case 2 : return OFTReal; + case 3 : return OFTRealList; + case 4 : return OFTString; + case 5 : return OFTStringList; + case 6 : return OFTWideString; + case 7 : return OFTWideStringList; + case 8 : return OFTBinary; + case 9 : return OFTDate; + case 10 : return OFTTime; + case 11 : return OFTDateTime; + case 12 : return OFTInteger64; + case 13 : return OFTInteger64List; + } + throw new IllegalArgumentException("Unknown type " + value); + } + +} diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbByteOrder.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbByteOrder.java new file mode 100644 index 0000000000..6cacfa2312 --- /dev/null +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbByteOrder.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.storage.gdal; + +/** + * + * @author Hilmi Bouallegue (Geomatys) + */ +enum OGRwkbByteOrder { + /** MSB/Sun/Motoroloa: Most Significant Byte First. */ + wkbXDR, + /** LSB/Intel/Vax: Least Significant Byte First. */ + wkbNDR; + + public static OGRwkbByteOrder valueOf(int value) { + switch (value) { + case 0 : return wkbXDR; + case 1 : return wkbNDR; + } + throw new IllegalArgumentException("Unknown type " + value); + } +} diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbGeometryType.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbGeometryType.java new file mode 100644 index 0000000000..5f81883227 --- /dev/null +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OGRwkbGeometryType.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.storage.gdal; + +import org.locationtech.jts.geom.*; + + +/** + * + * @author Hilmi Bouallegue (Geomatys) + */ +public enum OGRwkbGeometryType { + wkbUnknown(Geometry.class), + wkbPoint(Point.class), + wkbLineString(LineString.class), + wkbPolygon(Polygon.class), + wkbMultiPoint(MultiPoint.class), + wkbMultiLineString(MultiLineString.class), + wkbMultiPolygon(MultiPolygon.class), + wkbGeometryCollection(GeometryCollection.class), + wkbCircularString(Geometry.class), + wkbCompoundCurve(Geometry.class), + wkbCurvePolygon(Geometry.class), + wkbMultiCurve(Geometry.class), + wkbMultiSurface(Geometry.class), + wkbCurve(Geometry.class), + wkbSurface(Geometry.class), + wkbPolyhedralSurface(Geometry.class), + wkbTIN(Geometry.class), + wkbTriangle(Geometry.class), + wkbNone(Geometry.class), + wkbLinearRing(Geometry.class), + wkbCircularStringZ(Geometry.class), + wkbCompoundCurveZ(Geometry.class), + wkbCurvePolygonZ(Geometry.class), + wkbMultiCurveZ(Geometry.class), + wkbMultiSurfaceZ(Geometry.class), + wkbCurveZ(Geometry.class), + wkbSurfaceZ(Geometry.class), + wkbPolyhedralSurfaceZ(Geometry.class), + wkbTINZ(Geometry.class), + wkbTriangleZ(Geometry.class), + wkbPointM(Geometry.class), + wkbLineStringM(Geometry.class), + wkbPolygonM(Geometry.class), + wkbMultiPointM(Geometry.class), + wkbMultiLineStringM(Geometry.class), + wkbMultiPolygonM(Geometry.class), + wkbGeometryCollectionM(Geometry.class), + wkbCircularStringM(Geometry.class), + wkbCompoundCurveM(Geometry.class), + wkbCurvePolygonM(Geometry.class), + wkbMultiCurveM(Geometry.class), + wkbMultiSurfaceM(Geometry.class), + wkbCurveM(Geometry.class), + wkbSurfaceM(Geometry.class), + wkbPolyhedralSurfaceM(Geometry.class), + wkbTINM(Geometry.class), + wkbTriangleM(Geometry.class), + wkbPointZM(Geometry.class), + wkbLineStringZM(Geometry.class), + wkbPolygonZM(Geometry.class), + wkbMultiPointZM(Geometry.class), + wkbMultiLineStringZM(Geometry.class), + wkbMultiPolygonZM(Geometry.class), + wkbGeometryCollectionZM(Geometry.class), + wkbCircularStringZM(Geometry.class), + wkbCompoundCurveZM(Geometry.class), + wkbCurvePolygonZM(Geometry.class), + wkbMultiCurveZM(Geometry.class), + wkbMultiSurfaceZM(Geometry.class), + wkbCurveZM(Geometry.class), + wkbSurfaceZM(Geometry.class), + wkbPolyhedralSurfaceZM(Geometry.class), + wkbTINZM(Geometry.class), + wkbTriangleZM(Geometry.class), + wkbPoint25D(Geometry.class), + wkbLineString25D(Geometry.class), + wkbPolygon25D(Geometry.class), + wkbMultiPoint25D(Geometry.class), + wkbMultiLineString25D(Geometry.class), + wkbMultiPolygon25D(Geometry.class), + wkbGeometryCollection25D(Geometry.class); + + private final Class javaClass; + + OGRwkbGeometryType(Class javaClass){ + this.javaClass =javaClass; + } + + public Class getJavaClass(){ + return javaClass; + } + + public static OGRwkbGeometryType valueOf(int value) { + switch (value) { + case 0 : return wkbUnknown; + case 1 : return wkbPoint; + case 2 : return wkbLineString; + case 3 : return wkbPolygon; + case 4 : return wkbMultiPoint; + case 5 : return wkbMultiLineString; + case 6 : return wkbMultiPolygon; + case 7 : return wkbGeometryCollection; + case 8 : return wkbCircularString; + case 9 : return wkbCompoundCurve; + case 10 : return wkbCurvePolygon; + case 11 : return wkbMultiCurve; + case 12 : return wkbMultiSurface; + case 13 : return wkbCurve; + case 14 : return wkbSurface; + case 15 : return wkbPolyhedralSurface; + case 16 : return wkbTIN; + case 17 : return wkbTriangle; + case 18 : return wkbNone; + case 19 : return wkbLinearRing; + case 20 : return wkbCircularStringZ; + case 21 : return wkbCompoundCurveZ; + case 22 : return wkbCurvePolygonZ; + case 23 : return wkbMultiCurveZ; + case 24 : return wkbMultiSurfaceZ; + case 25 : return wkbCurveZ; + case 26 : return wkbSurfaceZ; + case 27 : return wkbPolyhedralSurfaceZ; + case 28 : return wkbTINZ; + case 29 : return wkbTriangleZ; + case 30 : return wkbPointM; + case 31 : return wkbLineStringM; + case 32 : return wkbPolygonM; + case 33 : return wkbMultiPointM; + case 34 : return wkbMultiLineStringM; + case 35 : return wkbMultiPolygonM; + case 36 : return wkbGeometryCollectionM; + case 37 : return wkbCircularStringM; + case 38 : return wkbCompoundCurveM; + case 39 : return wkbCurvePolygonM; + case 40 : return wkbMultiCurveM; + case 41 : return wkbMultiSurfaceM; + case 42 : return wkbCurveM; + case 43 : return wkbSurfaceM; + case 44 : return wkbPolyhedralSurfaceM; + case 45 : return wkbTINM; + case 46 : return wkbTriangleM; + case 47 : return wkbPointZM; + case 48 : return wkbLineStringZM; + case 49 : return wkbPolygonZM; + case 50 : return wkbMultiPointZM; + case 51 : return wkbMultiLineStringZM; + case 52 : return wkbMultiPolygonZM; + case 53 : return wkbGeometryCollectionZM; + case 54 : return wkbCircularStringZM; + case 55 : return wkbCompoundCurveZM; + case 56 : return wkbCurvePolygonZM; + case 57 : return wkbMultiCurveZM; + case 58 : return wkbMultiSurfaceZM; + case 59 : return wkbCurveZM; + case 60 : return wkbSurfaceZM; + case 61 : return wkbPolyhedralSurfaceZM; + case 62 : return wkbTINZM; + case 63 : return wkbTriangleZM; + case 64 : return wkbPoint25D; + case 65 : return wkbLineString25D; + case 66 : return wkbPolygon25D; + case 67 : return wkbMultiPoint25D; + case 68 : return wkbMultiLineString25D; + case 69 : return wkbMultiPolygon25D; + case 70 : return wkbGeometryCollection25D; + } + throw new IllegalArgumentException("Unknown type " + value); + } +} diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrGeometryReader.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrGeometryReader.java new file mode 100644 index 0000000000..2bbe4aade8 --- /dev/null +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrGeometryReader.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.storage.gdal; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.panama.NativeFunctions; +import org.locationtech.jts.geom.CoordinateSequence; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.LinearRing; +import org.locationtech.jts.geom.Polygon; +import org.locationtech.jts.geom.impl.PackedCoordinateSequence; + +/** + * + * @author Johann Sorel (Geomatys) + */ +final class OgrGeometryReader implements AutoCloseable { + + private static final GeometryFactory GF = new GeometryFactory(); + //reuse direct buffer for better performances + private MemorySegment px; + private MemorySegment py; + private ByteBuffer bufferx; + private ByteBuffer buffery; + + private final Arena arena = Arena.ofConfined(); + private final GDAL gdal; + + OgrGeometryReader(GDAL gdal) { + this.gdal = gdal; + } + + private void resizeBuffer(int nbPoint){ + final int size = nbPoint*2*8; + if (px == null || px.byteSize() < size) { + px = arena.allocate(size); + py = px.asSlice(8); + bufferx = px.asByteBuffer(); + buffery = py.asByteBuffer(); + } + } + + public Geometry toGeometry(MemorySegment ogrGeom) throws DataStoreException { + if (ogrGeom == null) return null; + + try { + MemorySegment NULL = MemorySegment.ofAddress(0); + final String type = NativeFunctions.toString( (MemorySegment)gdal.ogrGeometryGetGeometryName.invokeExact(ogrGeom)); + + switch (type) { + case "POINT" : { + final double[] coords = new double[2]; + resizeBuffer(1); + final int returnedNbPoints = (int) gdal.ogrGeometryGetPoints.invokeExact(ogrGeom,px,16,py,16,NULL,0); + + bufferx.position(0); + bufferx.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer().get(coords); + + final CoordinateSequence cs = new PackedCoordinateSequence.Double(coords,2,0); + return GF.createPoint(cs); + } + case "MULTIPOINT" : { + final int nbPoint = (int) gdal.ogrGeometryGetPointCount.invokeExact(ogrGeom); + final double[] coords = new double[nbPoint*2]; + if (nbPoint != 0) { + resizeBuffer(nbPoint); + final int returnedNbPoints = (int) gdal.ogrGeometryGetPoints.invokeExact(ogrGeom,px,16,py,16,NULL,0); + + bufferx.position(0); + bufferx.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer().get(coords); + } + final CoordinateSequence cs = new PackedCoordinateSequence.Double(coords,2,0); + return GF.createMultiPoint(cs); + } + case "LINESTRING" : { + final int nbPoint = (int) gdal.ogrGeometryGetPointCount.invokeExact(ogrGeom); + final double[] coords = new double[nbPoint*2]; + resizeBuffer(nbPoint); + final int returnedNbPoints = (int) gdal.ogrGeometryGetPoints.invokeExact(ogrGeom,px,16,py,16,NULL,0); + + bufferx.position(0); + bufferx.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer().get(coords); + + if (nbPoint==1) { + //duplicate first point, JTS need at least 2 coordinates + final double[] cp = new double[]{coords[0],coords[1],coords[0],coords[1]}; + final CoordinateSequence cs = new PackedCoordinateSequence.Double(cp,2,0); + return GF.createLineString(cs); + } else { + final CoordinateSequence cs = new PackedCoordinateSequence.Double(coords,2,0); + return GF.createLineString(cs); + } + } + case "LINEARRING" : { + final int nbPoint = (int) gdal.ogrGeometryGetPointCount.invokeExact(ogrGeom); + double[] coords = new double[(nbPoint+1)*2]; + resizeBuffer(nbPoint+1); + final int returnedNbPoints = (int) gdal.ogrGeometryGetPoints.invokeExact(ogrGeom,px,16,py,16,NULL,0); + + bufferx.position(0); + bufferx.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer().get(coords,0,nbPoint*2); + + //JTS needs at least 3+1 points + if (coords.length<8) { + double[] cs = Arrays.copyOf(coords, 8); + for(int i=nbPoint;i<4;i++){ + cs[i*2+0] = coords[0]; + cs[i*2+1] = coords[1]; + } + coords = cs; + } + + //duplicate first to last point this is a JTS constraint + coords[coords.length-2] = coords[0]; + coords[coords.length-1] = coords[1]; + + final CoordinateSequence cs = new PackedCoordinateSequence.Double(coords,2,0); + return GF.createLinearRing(cs); + } + case "MULTILINESTRING" : { + final int nbGeom = (int) gdal.ogrGeometryGetGeometryCount.invokeExact(ogrGeom); + final LineString[] children = new LineString[nbGeom]; + for (int i=0;i<nbGeom;i++) { + final MemorySegment sub = (MemorySegment) gdal.ogrGeometryGetGeometryRef.invokeExact(ogrGeom, i); + children[i] = (LineString) toGeometry(sub); + } + return GF.createMultiLineString(children); + } + case "POLYGON" : { + final int nbGeom = (int) gdal.ogrGeometryGetGeometryCount.invokeExact(ogrGeom); + //first is the exterior ring, next ones are the interiors + LinearRing exterior = null; + final LinearRing[] interiors = new LinearRing[nbGeom-1]; + for (int i=0;i<nbGeom;i++) { + final MemorySegment sub = (MemorySegment) gdal.ogrGeometryGetGeometryRef.invokeExact(ogrGeom, i); + if (i==0) exterior = (LinearRing) toGeometry(sub); + else interiors[i-1] = (LinearRing) toGeometry(sub); + } + return GF.createPolygon(exterior,interiors); + } + case "MULTIPOLYGON" : { + final int nbGeom = (int) gdal.ogrGeometryGetGeometryCount.invokeExact(ogrGeom); + final Polygon[] children = new Polygon[nbGeom]; + for (int i=0;i<nbGeom;i++) { + final MemorySegment sub = (MemorySegment) gdal.ogrGeometryGetGeometryRef.invokeExact(ogrGeom, i); + children[i] = (Polygon) toGeometry(sub); + } + return GF.createMultiPolygon(children); + } + case "GEOMETRYCOLLECTION" : { + final int nbGeom = (int) gdal.ogrGeometryGetGeometryCount.invokeExact(ogrGeom); + final Geometry[] children = new Geometry[nbGeom]; + for (int i=0;i<nbGeom;i++) { + final MemorySegment sub = (MemorySegment) gdal.ogrGeometryGetGeometryRef.invokeExact(ogrGeom, i); + children[i] = toGeometry(sub); + } + return GF.createGeometryCollection(children); + } + case "GEOMETRY" : + case "CIRCULARSTRING" : + case "COMPOUNDCURVE" : + case "CURVEPOLYGON" : + case "MULTICURVE" : + case "MULTISURFACE" : + case "CURVE" : + case "SURFACE" : + case "POLYHEDRALSURFACE" : + case "TIN" : + case "TRIANGLE" : + default : { + throw new DataStoreException("Unsupported geometry type "+type); + } + } + } catch (Throwable e) { + throw GDAL.propagate(e); + } + + } + + @Override + public void close() { + arena.close(); + } + +} diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrSpliterator.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrSpliterator.java new file mode 100644 index 0000000000..a293d52327 --- /dev/null +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/OgrSpliterator.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.storage.gdal; + +import java.lang.foreign.MemorySegment; +import java.util.Spliterator; +import java.util.function.Consumer; +import org.apache.sis.feature.privy.AttributeConvention; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.panama.NativeFunctions; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.MultiLineString; +import org.locationtech.jts.geom.MultiPolygon; +import org.locationtech.jts.geom.Polygon; +import org.opengis.feature.AttributeType; +import org.opengis.feature.Feature; +import org.opengis.feature.FeatureType; + + +/** + * + * @author Johann Sorel (Geomatys) + */ +final class OgrSpliterator implements Spliterator<Feature>{ + + private final OGRFeatureSet fs; + private final OgrGeometryReader geomReader; + private final FeatureType type; + private boolean closed = false; + private final GDAL gdal; + + OgrSpliterator(OGRFeatureSet fs, FeatureType type) throws DataStoreException { + this.fs = fs; + this.type = type; + gdal = fs.gdal; + geomReader = new OgrGeometryReader(gdal); + } + + @Override + public Spliterator<Feature> trySplit() { + return null; + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + + @Override + public int characteristics() { + return NONNULL; + } + + @Override + public boolean tryAdvance(Consumer<? super Feature> action) { + //Reading the features of the layer + try { + final MemorySegment featurePt = (MemorySegment) gdal.ogrLayerGetNextFeature.invokeExact(fs.layer); + if (featurePt == null || featurePt.address() == 0L) { + return false; + } + + final Feature feature = type.newInstance(); + feature.setPropertyValue(AttributeConvention.IDENTIFIER, (long) gdal.ogrFeatureGetFid.invokeExact(featurePt)); + //Loop for all the features of the layer + for (int i = 0; i < fs.fields.length; i++) { + OGRFieldType fieldType = fs.fieldEncs[i]; + String propName = fs.fields[i]; + if (fieldType == OGRFieldType.OFTInteger) { + feature.setPropertyValue(propName, (int) gdal.ogrFeatureGetFieldAsInteger.invokeExact(featurePt, i)); + } else if (fieldType == OGRFieldType.OFTInteger64) { + feature.setPropertyValue(propName, (long) gdal.ogrFeatureGetFieldAsInteger64.invokeExact(featurePt, i)); + } else if (fieldType == OGRFieldType.OFTReal) { + feature.setPropertyValue(propName, (double) gdal.ogrFeatureGetFieldAsDouble.invokeExact(featurePt, i)); + } else if (fieldType == OGRFieldType.OFTString) { + feature.setPropertyValue(propName, NativeFunctions.toString( (MemorySegment) gdal.ogrFeatureGetFieldAsString.invokeExact(featurePt, i))); + } else { + feature.setPropertyValue(propName, NativeFunctions.toString( (MemorySegment) gdal.ogrFeatureGetFieldAsString.invokeExact(featurePt, i))); + } + } + // read geometry + if (fs.geomFields.length > 0) { + //TODO loop on all geometries + final MemorySegment ogrGeom = (MemorySegment) gdal.ogrFeatureGetGeometryRef.invokeExact(featurePt); + Geometry geom = geomReader.toGeometry(ogrGeom); + final AttributeType geomType = (AttributeType) type.getProperty(fs.geomFields[0]); + + //shapefile mix LineString with MultiLineString and Polygon with MultiPolygon, but not JTS + if (geom instanceof LineString) { + final MultiLineString ml = geom.getFactory().createMultiLineString(new LineString[]{(LineString) geom}); + ml.setUserData(geom.getUserData()); + geom = ml; + } else if (geom instanceof Polygon) { + final MultiPolygon mp = geom.getFactory().createMultiPolygon(new Polygon[]{(Polygon) geom}); + mp.setUserData(geom.getUserData()); + geom = mp; + } + geom.setUserData(fs.crs); + feature.setPropertyValue(fs.geomFields[0], geom); + } + //release memory + gdal.ogrFeatureDestroy.invokeExact(featurePt); + + action.accept(feature); + return true; + } catch (Throwable e) { + throw GDAL.propagate(e); + } + } + + public synchronized void close() { + if (closed) { + return; + } + closed = true; + } + +} diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java index 4b737797ec..59b699c11a 100644 --- a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java @@ -69,7 +69,7 @@ final class Opener implements Runnable { * @throws DataStoreException if <var>GDAL</var> cannot open the data set. */ Opener(final GDALStoreProvider owner, final String url, final String... allowedDrivers) throws DataStoreException { - this(owner, url, new OpenFlag[] {OpenFlag.RASTER, OpenFlag.SHARED}, allowedDrivers, null, null); + this(owner, url, new OpenFlag[] {OpenFlag.RASTER, OpenFlag.VECTOR, OpenFlag.SHARED}, allowedDrivers, null, null); } /** diff --git a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/SpatialRef.java b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/SpatialRef.java index 912c6a1707..813108973c 100644 --- a/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/SpatialRef.java +++ b/optional/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/SpatialRef.java @@ -97,6 +97,19 @@ final class SpatialRef { return new SpatialRef(owner, gdal, handle); } + /** + * Creates a new instance. + * + * @param owner the dataset which is providing the <abbr>CRS</abbr> definition. + * @param gdal sets of handles for invoking <abbr>GDAL</abbr> functions. + * @param spatialRefHandle pointer to native SpatialRef. + * @return wrapper for the <abbr>CRS</abbr> definition provided by <abbr>GDAL</abbr>, or {@code null} if none. + * @throws DataStoreException if an error occurred while fetching information from <abbr>GDAL</abbr>. + */ + static SpatialRef createWithHandle(final GDALStore owner, final GDAL gdal, final MemorySegment spatialRefHandle) throws DataStoreException { + return new SpatialRef(owner, gdal, spatialRefHandle); + } + /** * Parses the <abbr>CRS</abbr> of the data set by parsing its <abbr>WKT</abbr> representation. * This method must be invoked from a method synchronized on {@link GDALStore}.