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

basic metadata support #47

Merged
merged 9 commits into from
Oct 17, 2024
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
8 changes: 4 additions & 4 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ endif
# Build PROJ and its dependencies
cmake = import('cmake')
summary({
'libcurl enabled' : enable_curl,
'libtiff enabled' : enable_tiff,
'inline proj.db' : inline_projdb
})
'libcurl' : enable_curl,
'libtiff' : enable_tiff,
'inline proj.db' : inline_projdb
}, bool_yn: true)

if inline_projdb
add_global_link_arguments([
Expand Down
39 changes: 39 additions & 0 deletions src/metadata.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
%nn_shared_ptr(osgeo::proj::metadata::Identifier);
%nn_shared_ptr(osgeo::proj::metadata::Citation);
%nn_shared_ptr(osgeo::proj::metadata::Extent);
%nn_shared_ptr(osgeo::proj::metadata::GeographicBoundingBox);
%nn_shared_ptr(osgeo::proj::metadata::TemporalExtent);
%nn_shared_ptr(osgeo::proj::metadata::VerticalExtent);
%nn_shared_ptr(osgeo::proj::metadata::PositionalAccuracy);

%define IDENTIFIER_DOWNCAST_TABLE_ENTRY(TYPE)
identifier_downcast_table.insert({typeid(TYPE).hash_code(), $descriptor(TYPE *)})
%enddef

%fragment("identifier_downcast_table", "header", fragment="include_map") {
std::map<std::size_t, swig_type_info *> identifier_downcast_table;

void init_identifier_downcast_table() {
IDENTIFIER_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::Identifier);
IDENTIFIER_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::Citation);
IDENTIFIER_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::Extent);
IDENTIFIER_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::GeographicBoundingBox);
IDENTIFIER_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::TemporalExtent);
IDENTIFIER_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::VerticalExtent);
IDENTIFIER_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::PositionalAccuracy);
}
}

%init {
init_identifier_downcast_table();
}

// See util.i for the downcasting mechanics
// This overwrites the typemap created by %nn_shared_ptr
%typemap(out, fragment="identifier_downcast_table") dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::Identifier>> {
TRY_DOWNCASTING($1, $result, osgeo::proj::metadata::Identifier, identifier_downcast_table)
}

// Extent is nullable when not an nn pointer
%typemap(ts) osgeo::proj::metadata::ExtentPtr "Extent | null";
%typemap(ts) const osgeo::proj::metadata::ExtentPtr & "Extent | null";
21 changes: 20 additions & 1 deletion src/operation.i
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,27 @@
%nn_unique_ptr(osgeo::proj::operation::CoordinateOperationFactory);
%nn_unique_ptr(osgeo::proj::operation::CoordinateTransformer);

%define COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(TYPE)
coordinate_operation_downcast_table.insert({typeid(TYPE).hash_code(), $descriptor(TYPE *)})
%enddef

%fragment("coordinate_operation_downcast_table", "header", fragment="include_map") {
std::map<std::size_t, swig_type_info *> coordinate_operation_downcast_table;

void init_coordinate_operation_downcast_table() {
COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::CoordinateOperation);
COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::SingleOperation);
COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::ConcatenatedOperation);
COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::Conversion);
}
}

%init {
init_coordinate_operation_downcast_table();
}

// See util.i for the downcasting mechanics
// This overwrites the typemap created by %nn_shared_ptr
%typemap(out, fragment="downcast_tables") dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::CoordinateOperation>> {
%typemap(out, fragment="coordinate_operation_downcast_table") dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::CoordinateOperation>> {
TRY_DOWNCASTING($1, $result, osgeo::proj::operation::CoordinateOperation, coordinate_operation_downcast_table)
}
63 changes: 53 additions & 10 deletions src/optional.i
Original file line number Diff line number Diff line change
@@ -1,36 +1,79 @@
// C++ osgeo::proj::util::optional<std::string> <-> JS string
// osgeo::proj::util::optional

// This is almost a string, but not quite
/*
* Input arguments
*/

// Input argument, plain object, conversion by copying
%typemap(in) osgeo::proj::util::optional<std::string> {
// Input argument, plain object, conversion by copying using the underlying object typemap
%typemap(in) osgeo::proj::util::optional {
if (!$input.IsNull()) {
std::string opt_string;
$typemap(in, std::string, input=$input, 1=opt_string, argnum=$argnum);
$1 = osgeo::proj::util::optional<std::string>{opt_string};
$T0type obj;
$typemap(in, $T0type, input=$input, 1=obj, argnum=$argnum);
$1 = osgeo::proj::util::optional<$T0type>{obj};
}
}
// Input argument, const reference, conversion by constructing an 'optional'
// around the object held by JS
// (DataEpoch & Measure do not support operator=, thus the unique_ptr gymnastics)
%typemap(in) const osgeo::proj::util::optional & (std::unique_ptr<$*1_ltype> opt_object) {
if (!$input.IsNull()) {
$T0type *obj;
$typemap(in, const $T0type &, input=$input, 1=obj, argnum=$argnum);
opt_object = std::make_unique<$*1_ltype>(*obj);
} else {
opt_object = std::make_unique<$*1_ltype>();
}
$1 = opt_object.get();
}

// string and double are special cases, these are copied
%typemap(in) const osgeo::proj::util::optional<std::string> & (osgeo::proj::util::optional<std::string> opt_string) {
if (!$input.IsNull()) {
$typemap(in, std::string, input=$input, 1=opt_string, argnum=$argnum);
}
$1 = &opt_string;
}
%typemap(in) const osgeo::proj::util::optional<double> & (osgeo::proj::util::optional<double> opt_double) {
if (!$input.IsNull()) {
$typemap(in, double, input=$input, 1=opt_double, argnum=$argnum);
}
$1 = &opt_double;
}

%typemap(ts) osgeo::proj::util::optional, const osgeo::proj::util::optional & "$typemap(ts, $T0type)";

%typemap(ts) osgeo::proj::util::optional<std::string>, const osgeo::proj::util::optional<std::string> & "string";
/*
* Return values
*/

// Return value, plain object, conversion by copying
%typemap(out) osgeo::proj::util::optional<std::string> {
%typemap(out) osgeo::proj::util::optional {
if ($1.has_value()) {
$typemap(out, std::string, 1=(*$1), result=$result, argnum=$argnum);
$typemap(out, $T0type, 1=(*$1), result=$result, argnum=$argnum);
} else {
$result = env.Null();
}
}
// Return value, const reference, conversion by wrapping a constant object
%typemap(out) const osgeo::proj::util::optional & {
if ($1->has_value()) {
$typemap(out, const $T0type &, 1=&(*$1), result=$result, argnum=$argnum);
} else {
$result = env.Null();
}
}
// string and double are special cases, these are copied
%typemap(out) const osgeo::proj::util::optional<std::string> & {
if ($1->has_value()) {
$typemap(out, const std::string &, 1=(*$1), result=$result, argnum=$argnum);
} else {
$result = env.Null();
}
}
%typemap(out) const osgeo::proj::util::optional<double> & {
if ($1->has_value()) {
$typemap(out, double, 1=(**$1), result=$result, argnum=$argnum);
} else {
$result = env.Null();
}
}
2 changes: 2 additions & 0 deletions src/proj.i
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ using namespace NS_PROJ;
%include "util.i"
%include "common.i"
%include "io.i"
%include "metadata.i"
%include "operation.i"
%include "datum.i"
%include "coordinatesystem.i"
Expand Down Expand Up @@ -112,6 +113,7 @@ using namespace NS_PROJ;

%include <proj/util.hpp>
%include <proj/io.hpp>
%include <proj/metadata.hpp>
%include <proj/common.hpp>
%include <proj/datum.hpp>
%include <proj/coordinatesystem.hpp>
Expand Down
43 changes: 22 additions & 21 deletions src/util.i
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,14 @@
baseobject_downcast_table.insert({typeid(TYPE).hash_code(), $descriptor(TYPE *)})
%enddef

%define COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(TYPE)
coordinate_operation_downcast_table.insert({typeid(TYPE).hash_code(), $descriptor(TYPE *)})
%enddef

%fragment("downcast_tables", "header") {
%fragment("include_map", "header") {
#include <map>
}

%fragment("baseobject_downcast_table", "header", fragment="include_map") {
std::map<std::size_t, swig_type_info *> baseobject_downcast_table;
std::map<std::size_t, swig_type_info *> coordinate_operation_downcast_table;

void init_downcast_tables() {
void init_baseobject_downcast_table() {
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::crs::ProjectedCRS);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::crs::GeographicCRS);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::crs::VerticalCRS);
Expand All @@ -72,16 +70,24 @@ coordinate_operation_downcast_table.insert({typeid(TYPE).hash_code(), $descripto
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::crs::DerivedEngineeringCRS);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::crs::DerivedParametricCRS);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::crs::DerivedTemporalCRS);

COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::CoordinateOperation);
COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::SingleOperation);
COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::ConcatenatedOperation);
COORDINATE_OPERATION_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::Conversion);
// These can be downcasted both from BaseObject and from CoordinateOperation (in operation.i)
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::CoordinateOperation);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::SingleOperation);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::ConcatenatedOperation);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::operation::Conversion);
// These can be downcasted both from BaseObject and from Identifier (in metadata.i)
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::Identifier);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::Citation);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::Extent);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::GeographicBoundingBox);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::TemporalExtent);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::VerticalExtent);
BASEOBJECT_DOWNCAST_TABLE_ENTRY(osgeo::proj::metadata::PositionalAccuracy);
}
}

%init {
init_downcast_tables();
init_baseobject_downcast_table();
}

/*
Expand All @@ -93,10 +99,10 @@ coordinate_operation_downcast_table.insert({typeid(TYPE).hash_code(), $descripto
*/
%define TRY_DOWNCASTING(INPUT, OUTPUT, BASE_TYPE, TABLE)
std::size_t rtti_code = typeid(*INPUT.get()).hash_code();
SWIG_VERBOSE("downcasting for type %s: ", typeid(*INPUT.get()).name());
SWIG_VERBOSE(#TABLE ": downcasting for type %s: ", typeid(*INPUT.get()).name());
if (TABLE.count(rtti_code) > 0) {
SWIG_VERBOSE("found\n");
swig_type_info *info = TABLE.at(rtti_code);
SWIG_VERBOSE("found %s (%s)\n", info->str, info->name);
OUTPUT = SWIG_NewPointerObj(INPUT.get(), info, SWIG_POINTER_OWN | %newpointer_flags);
auto *owner = new std::shared_ptr<BASE_TYPE>(*&INPUT);
auto finalizer = new SWIG_NAPI_Finalizer([owner](){
Expand All @@ -109,15 +115,10 @@ coordinate_operation_downcast_table.insert({typeid(TYPE).hash_code(), $descripto
}
%enddef

%typemap(out, fragment="downcast_tables") osgeo::proj::util::BaseObjectNNPtr {
%typemap(out, fragment="baseobject_downcast_table") osgeo::proj::util::BaseObjectNNPtr {
TRY_DOWNCASTING($1, $result, osgeo::proj::util::BaseObject, baseobject_downcast_table)
}

/*
* CoordinateOperation downcasting is in operation.i, it must come
* after the %nn_shared_ptr definition for CoordinateOperation
*/

/*
* TypeScript has static compile-time checking just like C++, which means that
* the explicit cast cannot be avoided
Expand Down
2 changes: 1 addition & 1 deletion test/shared/coordinateoperation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { assert } from 'chai';
import qPROJ from 'proj.js';
import type * as PROJ from 'proj.js';

describe.only('CoordinateOperation with automatic import', () => {
describe('CoordinateOperation with automatic import', () => {
let PROJ: Awaited<typeof qPROJ>;

let dbContext: PROJ.DatabaseContext;
Expand Down
14 changes: 14 additions & 0 deletions test/shared/crs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,18 @@ describe('CRS with automatic import', () => {
assert.instanceOf(crs, PROJ.CRS);
assert.instanceOf(crs, PROJ.ProjectedCRS);
});

it('isDynamic (return bool)', () => {
const crs = authFactoryEPSG.createCoordinateReferenceSystem('3857');
assert.isBoolean(crs.isDynamic());
});

it('extract GeographicCRS (return CRS)', () => {
const crs = authFactoryEPSG.createCoordinateReferenceSystem('3857');
const geographic = crs.extractGeographicCRS();
assert.instanceOf(geographic, PROJ.CRS);
assert.instanceOf(geographic, PROJ.SingleCRS);
assert.instanceOf(geographic, PROJ.GeographicCRS);
});

});
41 changes: 41 additions & 0 deletions test/shared/metadata.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { assert } from 'chai';

import qPROJ from 'proj.js';
import type * as PROJ from 'proj.js';

describe('metadata with automatic import', () => {
let PROJ: Awaited<typeof qPROJ>;

let dbContext: PROJ.DatabaseContext;
let authFactory: PROJ.AuthorityFactory;
let authFactoryEPSG: PROJ.AuthorityFactory;

before('init', async () => {
PROJ = await qPROJ;
dbContext = PROJ.DatabaseContext.create();
authFactory = PROJ.AuthorityFactory.create(dbContext, 'string');
authFactoryEPSG = PROJ.AuthorityFactory.create(dbContext, 'EPSG');
});

it('static properties', () => {
assert.isString(PROJ.Identifier.AUTHORITY_KEY);
assert.isString(PROJ.Identifier.CODESPACE_KEY);
});

it('IdentifiedObject properties', () => {
const crs = authFactoryEPSG.createCoordinateReferenceSystem('3857');
const metadata = crs.identifiers();
assert.isArray(metadata);
for (const m of metadata) {
assert.instanceOf(m, PROJ.Identifier);
assert.instanceOf(m, PROJ.BaseObject);
assert.isString(m.code());
assert.isString(m.codeSpace());
assert.strictEqual(m.code(), '3857');
assert.strictEqual(m.codeSpace(), 'EPSG');
assert.isNull(m.authority());
assert.isNull(m.uri());
}
});

});
Loading