From 5e7970e595a49ecabcf500b82223e5d6718100d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Desboeufs?= Date: Fri, 24 Nov 2023 23:46:27 +0100 Subject: [PATCH] Add FieldDefn subtype --- documentation.yml | 6 ++++++ lib/gdal.js | 15 +++++++++++++++ src/gdal_field_defn.cpp | 35 +++++++++++++++++++++++++++++++++++ src/gdal_field_defn.hpp | 2 ++ src/node_gdal.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/utils/field_types.hpp | 23 ++++++++++++++++++++++- 6 files changed, 117 insertions(+), 1 deletion(-) diff --git a/documentation.yml b/documentation.yml index 2e6c5c5f0..9c3068f66 100644 --- a/documentation.yml +++ b/documentation.yml @@ -223,6 +223,12 @@ toc: - OFTTime - OFTWideString - OFTWideStringList + - name: Feature Field Sub-Types + children: + - OFSTNone + - OFSTBoolean + - OFSTInt16 + - OFSTFloat32 - name: Justification children: - OJLeft diff --git a/lib/gdal.js b/lib/gdal.js index a7a2c7042..7c9396ac2 100644 --- a/lib/gdal.js +++ b/lib/gdal.js @@ -578,6 +578,17 @@ function fieldTypeFromValue(val) { throw new Error('Value cannot be converted into OGRFieldType') } +function fieldSubtypeFromValue(val) { + const type = typeof val + if (type === 'boolean') { + return gdal.OFSTBoolean + } else if (val instanceof Array) { + return fieldSubtypeFromValue(val[0]) + } else { + return gdal.OFSTNone + } +} + /** * Creates a LayerFields instance from an object of keys and values. * @@ -611,7 +622,11 @@ gdal.LayerFields.prototype.fromObject = function (obj, approx_ok) { approx_ok = approx_ok || false Object.entries(obj).forEach(([ k, v ]) => { const type = fieldTypeFromValue(v) + const subtype = fieldSubtypeFromValue(v) const def = new gdal.FieldDefn(k, type) + if (subtype) { + def.subtype = subtype + } this.add(def, approx_ok) }) } diff --git a/src/gdal_field_defn.cpp b/src/gdal_field_defn.cpp index 8991397e3..124b167d7 100644 --- a/src/gdal_field_defn.cpp +++ b/src/gdal_field_defn.cpp @@ -16,6 +16,7 @@ void FieldDefn::Initialize(Local target) { ATTR(lcons, "name", nameGetter, nameSetter); ATTR(lcons, "type", typeGetter, typeSetter); + ATTR(lcons, "subtype", subtypeGetter, subtypeSetter); ATTR(lcons, "justification", justificationGetter, justificationSetter); ATTR(lcons, "width", widthGetter, widthSetter); ATTR(lcons, "precision", precisionGetter, precisionSetter); @@ -142,6 +143,25 @@ NAN_GETTER(FieldDefn::typeGetter) { info.GetReturnValue().Set(SafeString::New(getFieldTypeName(def->this_->GetType()))); } +/** + * Data subtype (see {@link OFST|OFST constants} + * + * @kind member + * @name subtype + * @instance + * @memberof FieldDefn + * @type {string} + */ +NAN_GETTER(FieldDefn::subtypeGetter) { + FieldDefn *def = Nan::ObjectWrap::Unwrap(info.This()); + OGRFieldSubType subtype = def->this_->GetSubType(); + if (subtype == OFSTNone) { + info.GetReturnValue().Set(Nan::Undefined()); + return; + } + info.GetReturnValue().Set(SafeString::New(getFieldSubTypeName(def->this_->GetSubType()))); +} + /** * @kind member * @name ignored @@ -226,6 +246,21 @@ NAN_SETTER(FieldDefn::typeSetter) { } } +NAN_SETTER(FieldDefn::subtypeSetter) { + FieldDefn *def = Nan::ObjectWrap::Unwrap(info.This()); + if (!value->IsString()) { + Nan::ThrowError("subtype must be a string"); + return; + } + std::string name = *Nan::Utf8String(value); + int subtype = getFieldSubTypeByName(name.c_str()); + if (subtype < 0) { + Nan::ThrowError("Unrecognized field subtype"); + } else { + def->this_->SetSubType(OGRFieldSubType(subtype)); + } +} + NAN_SETTER(FieldDefn::justificationSetter) { FieldDefn *def = Nan::ObjectWrap::Unwrap(info.This()); diff --git a/src/gdal_field_defn.hpp b/src/gdal_field_defn.hpp index bc43837aa..46b7b9a1c 100644 --- a/src/gdal_field_defn.hpp +++ b/src/gdal_field_defn.hpp @@ -27,6 +27,7 @@ class FieldDefn : public Nan::ObjectWrap { static NAN_GETTER(nameGetter); static NAN_GETTER(typeGetter); + static NAN_GETTER(subtypeGetter); static NAN_GETTER(justificationGetter); static NAN_GETTER(precisionGetter); static NAN_GETTER(widthGetter); @@ -34,6 +35,7 @@ class FieldDefn : public Nan::ObjectWrap { static NAN_SETTER(nameSetter); static NAN_SETTER(typeSetter); + static NAN_SETTER(subtypeSetter); static NAN_SETTER(justificationSetter); static NAN_SETTER(precisionSetter); static NAN_SETTER(widthSetter); diff --git a/src/node_gdal.cpp b/src/node_gdal.cpp index 80a97353c..5af7066c1 100644 --- a/src/node_gdal.cpp +++ b/src/node_gdal.cpp @@ -1543,6 +1543,43 @@ static void Init(Local target, Local, void *) { */ Nan::Set(target, Nan::New("OFTDateTime").ToLocalChecked(), Nan::New(getFieldTypeName(OFTDateTime)).ToLocalChecked()); + /* + * Field sub-types + */ + + /** + * @final + * @constant + * @name OFSTNone + * @type {string} + */ + Nan::Set( + target, Nan::New("OFSTNone").ToLocalChecked(), Nan::New(getFieldSubTypeName(OFSTNone)).ToLocalChecked()); + /** + * @final + * @constant + * @name OFSTBoolean + * @type {string} + */ + Nan::Set( + target, Nan::New("OFSTBoolean").ToLocalChecked(), Nan::New(getFieldSubTypeName(OFSTBoolean)).ToLocalChecked()); + /** + * @final + * @constant + * @name OFSTInt16 + * @type {string} + */ + Nan::Set( + target, Nan::New("OFSTInt16").ToLocalChecked(), Nan::New(getFieldSubTypeName(OFSTInt16)).ToLocalChecked()); + /** + * @final + * @constant + * @name OFSTFloat32 + * @type {string} + */ + Nan::Set( + target, Nan::New("OFSTFloat32").ToLocalChecked(), Nan::New(getFieldSubTypeName(OFSTFloat32)).ToLocalChecked()); + /* * Resampling options that can be used with the gdal.reprojectImage() and gdal.RasterBandPixels.read methods. */ diff --git a/src/utils/field_types.hpp b/src/utils/field_types.hpp index a3733116b..bb415fd6f 100644 --- a/src/utils/field_types.hpp +++ b/src/utils/field_types.hpp @@ -35,4 +35,25 @@ inline int getFieldTypeByName(std::string name) { return -1; } -#endif \ No newline at end of file +// OFSTNone = 0, OFSTBoolean = 1, OFSTInt16 = 2, OFSTFloat32 = 3 + +static const char *const FIELD_SUBTYPES[] = { + /* 0 */ "none", + /* 1 */ "boolean", + /* 2 */ "integer16", + /* 3 */ "float32"}; + +inline const char *getFieldSubTypeName(OGRFieldSubType subtype) { + int i = static_cast(subtype); + if (i < 0 || i > OFSTFloat32) { return "invalid"; } + return FIELD_SUBTYPES[i]; +} + +inline int getFieldSubTypeByName(std::string name) { + for (int i = 0; i <= OFSTFloat32; i++) { + if (name == FIELD_SUBTYPES[i]) return i; + } + return 0; +} + +#endif