aboutsummaryrefslogtreecommitdiff
path: root/scripts/create_c_api_projections.py
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2018-11-14 17:40:42 +0100
committerEven Rouault <even.rouault@spatialys.com>2018-11-14 22:48:29 +0100
commitd928db15d53805d9b728b440079756081961c536 (patch)
treee862a961d26bedb34c58e4f28ef0bdeedb5f3225 /scripts/create_c_api_projections.py
parent330e8bf686f9c4524075ca1ff50cbca6c9e091da (diff)
downloadPROJ-d928db15d53805d9b728b440079756081961c536.tar.gz
PROJ-d928db15d53805d9b728b440079756081961c536.zip
Implement RFC 2: Initial integration of "GDAL SRS barn" work
This work mostly consists of: - a C++ implementation of the ISO-19111:2018 / OGC Topic 2 "Referencing by coordinates" classes to represent Datums, Coordinate systems, CRSs (Coordinate Reference Systems) and Coordinate Operations. - methods to convert between this C++ modeling and WKT1, WKT2 and PROJ string representations of those objects - management and query of a SQLite3 database of CRS and Coordinate Operation definition - a C API binding part of those capabilities This is all-in-one squashed commit of the work of https://github.com/OSGeo/proj.4/pull/1040
Diffstat (limited to 'scripts/create_c_api_projections.py')
-rwxr-xr-xscripts/create_c_api_projections.py159
1 files changed, 159 insertions, 0 deletions
diff --git a/scripts/create_c_api_projections.py b/scripts/create_c_api_projections.py
new file mode 100755
index 00000000..5d10a16b
--- /dev/null
+++ b/scripts/create_c_api_projections.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+###############################################################################
+# $Id$
+#
+# Project: PROJ
+# Purpose: Parse XML output of Doxygen on coordinateoperation.hpp to creat
+# C API for projections.
+# Author: Even Rouault <even.rouault at spatialys.com>
+#
+###############################################################################
+# Copyright (c) 2018, Even Rouault <even.rouault at spatialys.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+###############################################################################
+
+from lxml import etree
+import os
+
+script_dir_name = os.path.dirname(os.path.realpath(__file__))
+
+# Make sure to run doxygen
+if not 'SKIP_DOXYGEN' in os.environ:
+ os.system("bash " + os.path.join(script_dir_name, "doxygen.sh"))
+
+xmlfilename = os.path.join(os.path.dirname(script_dir_name),
+ 'docs/build/xml/classosgeo_1_1proj_1_1operation_1_1Conversion.xml')
+
+tree = etree.parse(open(xmlfilename, 'rt'))
+root = tree.getroot()
+compounddef = root.find('compounddef')
+
+header = open('projections.h', 'wt')
+cppfile = open('projections.cpp', 'wt')
+test_cppfile = open('test_projections.cpp', 'wt')
+
+header.write("/* BEGIN: Generated by scripts/create_c_api_projections.py*/\n")
+
+cppfile.write("/* BEGIN: Generated by scripts/create_c_api_projections.py*/\n")
+cppfile.write("\n");
+
+test_cppfile.write("/* BEGIN: Generated by scripts/create_c_api_projections.py*/\n")
+
+for sectiondef in compounddef.iter('sectiondef'):
+ if sectiondef.attrib['kind'] == 'public-static-func':
+ for func in sectiondef.iter('memberdef'):
+ name = func.find('name').text
+ assert name.startswith('create')
+ if name in ('create', 'createChangeVerticalUnit',
+ 'createAxisOrderReversal', 'createGeographicGeocentric'):
+ continue
+ params = []
+ has_angle = False
+ has_linear = False
+ for param in func.iter('param'):
+ type = param.find('type').xpath("normalize-space()")
+ if type.find('Angle') >= 0:
+ has_angle = True
+ if type.find('Length') >= 0:
+ has_linear = True
+ paramname = param.find('declname').text
+ if paramname == 'properties':
+ continue
+ params.append((type, paramname))
+
+ shortName = name[len('create'):]
+
+ decl = "proj_obj_create_projected_crs_"
+ decl += shortName
+ decl += "(\n"
+ decl += " PJ_OBJ* geodetic_crs, const char* crs_name,\n"
+ for param in params:
+ if param[0] in ('int', 'bool'):
+ decl += " int " + param[1] + ",\n"
+ else:
+ decl += " double " + param[1] + ",\n"
+ if has_angle:
+ decl += " const char* angUnitName, double angUnitConvFactor"
+ if has_linear:
+ decl += ","
+ decl += "\n"
+ if has_linear:
+ decl += " const char* linearUnitName, double linearUnitConvFactor"
+ decl += ")"
+
+ header.write("PJ_OBJ PROJ_DLL *" + decl + ";\n\n")
+
+ briefdescription = func.find('briefdescription/para').xpath("normalize-space()")
+ briefdescription = briefdescription.replace("Instanciate ", "Instanciate a ProjectedCRS with ")
+
+ cppfile.write("// ---------------------------------------------------------------------------\n\n")
+ cppfile.write("/** \\brief " + briefdescription + "\n")
+ cppfile.write(" *\n")
+ cppfile.write(" * See osgeo::proj::operation::Conversion::create" + shortName + "().\n")
+ cppfile.write(" *\n")
+ cppfile.write(" * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor).\n")
+ if has_angle:
+ cppfile.write(" * Angular parameters are expressed in (angUnitName, angUnitConvFactor).\n")
+ cppfile.write(" */\n")
+ cppfile.write("PJ_OBJ* " + decl + "{\n");
+ if not has_linear:
+ cppfile.write(" const auto& linearUnit = UnitOfMeasure::METRE;\n")
+ else:
+ cppfile.write(" UnitOfMeasure linearUnit(createLinearUnit(linearUnitName, linearUnitConvFactor));\n")
+ if has_angle:
+ cppfile.write(" UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor));\n")
+ cppfile.write(" auto conv = Conversion::create" + shortName + "(PropertyMap()")
+ for param in params:
+ if param[0] in 'int':
+ cppfile.write(", " + param[1])
+ elif param[0] in 'bool':
+ cppfile.write(", " + param[1] + " != 0")
+ elif param[0].find('Angle') >= 0:
+ cppfile.write(", Angle(" + param[1] + ", angUnit)")
+ elif param[0].find('Length') >= 0:
+ cppfile.write(", Length(" + param[1] + ", linearUnit)")
+ elif param[0].find('Scale') >= 0:
+ cppfile.write(", Scale(" + param[1] + ")")
+
+ cppfile.write(");\n")
+ cppfile.write(" return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, linearUnit);\n")
+ cppfile.write("}\n")
+
+ test_cppfile.write("{\n")
+ test_cppfile.write(" auto projCRS = proj_obj_create_projected_crs_" + shortName + "(\n")
+ test_cppfile.write(" geogCRS, nullptr")
+ for param in params:
+ test_cppfile.write(", 0")
+ if has_angle:
+ test_cppfile.write(", \"Degree\", 0.0174532925199433")
+ if has_angle:
+ test_cppfile.write(", \"Metre\", 1.0")
+ test_cppfile.write(");\n")
+ test_cppfile.write(" ObjectKeeper keeper_projCRS(projCRS);\n")
+ test_cppfile.write(" ASSERT_NE(projCRS, nullptr);\n")
+ test_cppfile.write("}\n")
+
+
+header.write("/* END: Generated by scripts/create_c_api_projections.py*/\n")
+cppfile.write("/* END: Generated by scripts/create_c_api_projections.py*/\n")
+
+test_cppfile.write("/* END: Generated by scripts/create_c_api_projections.py*/\n")
+
+print('projections.h and .cpp, and test_projections.cpp have been generated. Manually merge them now') \ No newline at end of file